mirror of
https://github.com/furyhawk/ESP32-X-Desktop.git
synced 2026-07-21 00:55:34 +00:00
Add security and transport layers for enhanced provisioning
- Implemented security2.py for handling protobuf packets with security type protocomm_security2. - Introduced srp6a.py for secure password verification and session management. - Created transport layer with various transport methods: BLE, console, and HTTP. - Added utility functions for data type conversions in convenience.py. - Established a modular structure for network provisioning, allowing for flexible transport options.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
72d27784e3daf807418a34fb00be136ec50c6db49d989ce981d22e031fc0e7f8
|
||||
@@ -0,0 +1,51 @@
|
||||
# 1.2.4 (14-April-2026)
|
||||
|
||||
- Fix incorrect fail reason reported in `NETWORK_PROV_WIFI_CRED_FAIL` event.
|
||||
|
||||
# 1.2.3 (2-April-2026)
|
||||
- Fix possible NULL pointer dereference with malformed protobuf messages
|
||||
- Fix possible buffer overflow in Thread provisioning
|
||||
- Fix potential memory leaks
|
||||
|
||||
# 1.2.2 (18-Dec-2025)
|
||||
|
||||
- Fix connection attempts counter not being reset on state reset or new credentials
|
||||
- Reset `connection_attempts_completed` to 0 in `network_prov_mgr_reset_wifi_sm_state_on_failure()`
|
||||
and `network_prov_mgr_configure_wifi_sta()` to ensure full `wifi_conn_attempts` retries
|
||||
after reset or when applying new credentials.
|
||||
|
||||
# 1.2.1 (15-Dec-2025)
|
||||
|
||||
- Fix prov-ctrl reset handler to return success when device is already in provisioning mode
|
||||
- If firmware has already called `network_prov_mgr_reset_wifi_sm_state_on_failure()` or
|
||||
`network_prov_mgr_reset_thread_sm_state_on_failure()`, the device state is already reset
|
||||
to provisioning mode. The prov-ctrl handler now returns success in this case instead of
|
||||
an invalid state error, allowing phone apps to successfully reset even if firmware has
|
||||
already performed the reset operation.
|
||||
|
||||
# 07-October-2025
|
||||
|
||||
- Use managed cJSON component for IDF v6.0 and above
|
||||
|
||||
# 01-April-2025
|
||||
|
||||
- Extend provisioning check for `ESP_WIFI_REMOTE_ENABLED` as well along with existing `ESP_WIFI_ENABLED`
|
||||
- This enables provisioning for the devices not having native Wi-Fi (e.g., ESP32-P4) and using external/remote Wi-Fi solution such as esp-hosted for Wi-Fi connectivity.
|
||||
|
||||
# 17-March-2025
|
||||
|
||||
- Update the network provisioning component to work with the protocomm component which fixes incorrect AES-GCM IV usage in security2 scheme.
|
||||
|
||||
# 19-June-2024
|
||||
|
||||
- Change the proto files to make the network provisioning component stay backward compatible with the wifi_provisioing
|
||||
|
||||
# 23-April-2024
|
||||
|
||||
- Add `wifi_prov` or `thread_prov` in provision capabilities in the network provisioning manager for the provisioner to distinguish Thread or Wi-Fi devices
|
||||
|
||||
# 16-April-2024
|
||||
|
||||
- Move wifi_provisioning component from ESP-IDF at commit 5a40bb8746 and rename it to network_provisioning with the addition of Thread provisioning support.
|
||||
- Update esp_prov tool to support both Wi-Fi provisioning and Thread provisioning.
|
||||
- Create thread_prov and wifi_prov examples
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,40 @@
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
|
||||
if(${target} STREQUAL "linux")
|
||||
return() # This component is not supported by the POSIX/Linux simulator
|
||||
endif()
|
||||
|
||||
set(srcs "src/network_config.c"
|
||||
"src/network_scan.c"
|
||||
"src/network_ctrl.c"
|
||||
"src/manager.c"
|
||||
"src/handlers.c"
|
||||
"src/scheme_console.c"
|
||||
"proto-c/network_config.pb-c.c"
|
||||
"proto-c/network_scan.pb-c.c"
|
||||
"proto-c/network_ctrl.pb-c.c"
|
||||
"proto-c/network_constants.pb-c.c")
|
||||
|
||||
if((CONFIG_ESP_WIFI_ENABLED OR CONFIG_ESP_WIFI_REMOTE_ENABLED) AND CONFIG_ESP_WIFI_SOFTAP_SUPPORT)
|
||||
list(APPEND srcs "src/scheme_softap.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_BT_ENABLED)
|
||||
if(CONFIG_BT_BLUEDROID_ENABLED OR CONFIG_BT_NIMBLE_ENABLED)
|
||||
list(APPEND srcs
|
||||
"src/scheme_ble.c")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(priv_requires protobuf-c bt esp_timer esp_wifi openthread)
|
||||
|
||||
# For IDF < 6.0, use IDF's built-in json component; for IDF >= 6.0 use managed cJSON component
|
||||
if("${IDF_VERSION_MAJOR}" VERSION_LESS "6")
|
||||
list(APPEND priv_requires json)
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS include
|
||||
PRIV_INCLUDE_DIRS src proto-c
|
||||
REQUIRES lwip protocomm
|
||||
PRIV_REQUIRES ${priv_requires})
|
||||
@@ -0,0 +1,88 @@
|
||||
menu "Network Provisioning Manager"
|
||||
|
||||
choice NETWORK_PROV_NETWORK_TYPE
|
||||
prompt "Network Type"
|
||||
default NETWORK_PROV_NETWORK_TYPE_WIFI if (ESP_WIFI_ENABLED || ESP_WIFI_REMOTE_ENABLED)
|
||||
default NETWORK_PROV_NETWORK_TYPE_THREAD if !ESP_WIFI_ENABLE && OPENTHREAD_ENABLED
|
||||
|
||||
config NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
bool "Network Type - Wi-Fi"
|
||||
depends on ESP_WIFI_ENABLED || ESP_WIFI_REMOTE_ENABLED
|
||||
|
||||
config NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
bool "Network Type - Thread"
|
||||
depends on OPENTHREAD_ENABLED
|
||||
|
||||
endchoice
|
||||
|
||||
config NETWORK_PROV_SCAN_MAX_ENTRIES
|
||||
int "Max Network Scan Result Entries"
|
||||
default 16
|
||||
range 1 255
|
||||
help
|
||||
This sets the maximum number of entries of network scan results that will be kept by the
|
||||
provisioning manager
|
||||
|
||||
config NETWORK_PROV_AUTOSTOP_TIMEOUT
|
||||
int "Provisioning auto-stop timeout"
|
||||
default 30
|
||||
range 5 600
|
||||
help
|
||||
Time (in seconds) after which the network provisioning manager will auto-stop after connecting to
|
||||
a network successfully.
|
||||
|
||||
config NETWORK_PROV_BLE_BONDING
|
||||
bool
|
||||
prompt "Enable BLE bonding"
|
||||
depends on BT_ENABLED
|
||||
help
|
||||
This option is applicable only when provisioning transport is BLE. Used to enable BLE bonding process
|
||||
where the information from the pairing process will be stored on the devices.
|
||||
|
||||
config NETWORK_PROV_BLE_SEC_CONN
|
||||
bool
|
||||
prompt "Enable BLE Secure connection flag"
|
||||
depends on BT_NIMBLE_ENABLED
|
||||
default y
|
||||
help
|
||||
Used to enable Secure connection support when provisioning transport is BLE.
|
||||
|
||||
config NETWORK_PROV_BLE_FORCE_ENCRYPTION
|
||||
bool
|
||||
prompt "Force Link Encryption during characteristic Read / Write"
|
||||
depends on BT_ENABLED
|
||||
help
|
||||
Used to enforce link encryption when attempting to read / write characteristic
|
||||
|
||||
config NETWORK_PROV_BLE_NOTIFY
|
||||
bool
|
||||
prompt "Add support for Notification for provisioning BLE descriptors"
|
||||
depends on BT_ENABLED
|
||||
help
|
||||
Used to enable support Notification in BLE descriptors of prov* characteristics
|
||||
|
||||
config NETWORK_PROV_KEEP_BLE_ON_AFTER_PROV
|
||||
bool "Keep BT on after provisioning is done"
|
||||
depends on BT_ENABLED
|
||||
select ESP_PROTOCOMM_KEEP_BLE_ON_AFTER_BLE_STOP
|
||||
|
||||
config NETWORK_PROV_DISCONNECT_AFTER_PROV
|
||||
bool "Terminate connection after provisioning is done"
|
||||
depends on NETWORK_PROV_KEEP_BLE_ON_AFTER_PROV
|
||||
default y
|
||||
select ESP_PROTOCOMM_DISCONNECT_AFTER_BLE_STOP
|
||||
|
||||
choice NETWORK_PROV_WIFI_STA_SCAN_METHOD
|
||||
bool "Wifi Provisioning Scan Method"
|
||||
depends on NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
default NETWORK_PROV_WIFI_STA_ALL_CHANNEL_SCAN
|
||||
config NETWORK_PROV_WIFI_STA_ALL_CHANNEL_SCAN
|
||||
bool "All Channel Scan"
|
||||
help
|
||||
Scan will end after scanning the entire channel. This option is useful in Mesh WiFi Systems.
|
||||
config NETWORK_PROV_WIFI_STA_FAST_SCAN
|
||||
bool "Fast Scan"
|
||||
help
|
||||
Scan will end after an AP matching with the SSID has been detected.
|
||||
endchoice
|
||||
endmenu
|
||||
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2020 Piyush Shah <shahpiyushv@gmail.com>
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,9 @@
|
||||
# Network Provisioning component
|
||||
|
||||
[](https://components.espressif.com/components/espressif/network_provisioning)
|
||||
|
||||
The network provisioning component provides APIs that control the network provisioning service for receiving and configuring network credentials via secure [Protocol Communication](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/provisioning/protocomm.html) sessions.
|
||||
|
||||
It currently supports both Wi-Fi and Thread network provisioning:
|
||||
- Provision Wi-Fi credentials over SoftAP or Bluetooth LE
|
||||
- Provision Thread credentials over Bluetooth LE
|
||||
@@ -0,0 +1,11 @@
|
||||
# Provisioning Application Examples
|
||||
|
||||
This primarily consists of two examples `wifi_prov` and `thread_prov`.
|
||||
|
||||
* wifi_prov
|
||||
Abstracts out most of the complexity of Wi-Fi provisioning and allows easy switching between the SoftAP (using HTTP) and BLE transports. It also demonstrates how applications can register and use additional custom data endpoints.
|
||||
|
||||
* thread_prov
|
||||
Abstracts out most of the complexity of Thread provisioning over BLE transport. It also demonstrates how applications can register and use additional custom data endpoints.
|
||||
|
||||
Provisioning applications are available for `Linux / Windows / macOS` platform as `esp_prov.py` [script](../tool/esp_prov/esp_prov.py)
|
||||
@@ -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(thread_prov)
|
||||
@@ -0,0 +1,375 @@
|
||||
| Supported Targets | ESP32-C6 | ESP32-H2 |
|
||||
| ----------------- | -------- | -------- |
|
||||
|
||||
# Network Provisioning Manager Example for Thread Provisioning
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
`thread_prov` example demonstrates the usage of `network_provisioning` manager component for building a Thread provisioning application.
|
||||
|
||||
For this example, Bluetooth LE is chosen as the mode of transport, over which the provisioning related communication is to take place. NimBLE has been configured as the host.
|
||||
|
||||
In the provisioning process the device is configured as a Thread FTD with specified dataset. Once configured, the device will retain the Thread configuration, until a flash erase is performed.
|
||||
|
||||
Right after the provisioning is complete, Bluetooth LE is turned off and disabled to free the memory used by the Bluetooth LE stack. Though, that is specific to this example, and the user can choose to keep Bluetooth LE stack intact in their own application.
|
||||
|
||||
`thread_prov` uses the following components :
|
||||
* `network_provisioning` : Provides provisioning manager, data structures and protocomm endpoint handlers for Thread configuration
|
||||
* `protocomm` : For protocol based communication and secure session establishment
|
||||
* `protobuf` : Google's protocol buffer library for serialization of protocomm data structures
|
||||
* `bt` : ESP-IDF's Bluetooth LE stack for transport of protobuf packets
|
||||
|
||||
This example can be used, as it is, for adding a provisioning service to any application intended for IoT.
|
||||
|
||||
> Note: If you use this example code in your own project, in Bluetooth LE mode, then remember to enable the BT stack and BTDM BLE control settings in your SDK configuration (e.g. by using the `sdkconfig.defaults` file from this project).
|
||||
|
||||
## Security Scheme
|
||||
|
||||
The `protocomm` component is used for establishing secure communication channel at the time of provisioning. It supports two security schemes for establishing secure communication which are [Security 1 Scheme](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/provisioning/provisioning.html#security-1-scheme) and [Security 2 Scheme](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/provisioning/provisioning.html#security-2-scheme). The example uses `Security 2 Scheme` (latest) by default.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
Example should be able to run on any commonly available ESP32-H2/ESP32-C6 development board.
|
||||
|
||||
### Script Required
|
||||
|
||||
Currently, provisioning script is available for `Linux / Windows / macOS` platforms.
|
||||
|
||||
#### Platform : Linux / Windows / macOS
|
||||
|
||||
To install the dependency packages needed, please refer to the ESP-IDF examples [README file](https://github.com/espressif/esp-idf/blob/master/examples/README.md#running-test-python-script-ttfw).
|
||||
|
||||
`esp_prov` supports Bluetooth LE and SoftAP transport for Linux, MacOS and Windows platforms. For Bluetooth LE, however, if dependencies are not met, the script falls back to console mode and requires another application through which the communication can take place. The `esp_prov` console will guide you through the provisioning process of locating the correct Bluetooth LE GATT services and characteristics, the values to write, and input read values.
|
||||
|
||||
### Configure the project
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
### 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 (445) app: Starting provisioning
|
||||
I (1035) app: Provisioning started
|
||||
I (1045) network_prov_mgr: Provisioning started with service name : PROV_F72E6B
|
||||
```
|
||||
|
||||
Make sure to note down the Bluetooth LE device name (starting with `PROV_`) displayed in the serial monitor log (eg. PROV_F72E6B). This will depend on the MAC ID and will be unique for every device.
|
||||
|
||||
In a separate terminal run the `esp_prov.py` script under [directory](../../tool/esp_prov/) (make sure to replace `dataset_tlvs` with the dataset of the Thread network to which the device is supposed to connect to after provisioning). Assuming default example configuration, which uses the protocomm security version 2:
|
||||
|
||||
```
|
||||
python esp_prov.py --transport ble --service_name PROV_F72E6B --sec_ver 2 --sec2_username threadprov --sec2_pwd abcd1234 --dataset_tlvs <dataset_tlvs>
|
||||
```
|
||||
|
||||
For security scheme 1 with PoP-based (proof-of-possession) authentication, the following command can be used:
|
||||
```
|
||||
python esp_prov.py --transport ble --service_name PROV_F72E6B --sec_ver 1 --pop abcd1234 --dataset_tlvs <dataset_tlvs>
|
||||
```
|
||||
|
||||
Above command will perform the provisioning steps, and the monitor log should display something like this :
|
||||
|
||||
```
|
||||
I(125493) OPENTHREAD:[N] Mle-----------: Role disabled -> detached
|
||||
I (125503) OT_STATE: netif up
|
||||
I(125883) OPENTHREAD:[N] Mle-----------: Attach attempt 1, AnyPartition reattaching with Active Dataset
|
||||
I(126793) OPENTHREAD:[N] Mle-----------: RLOC16 fffe -> a40d
|
||||
I(126793) OPENTHREAD:[N] Mle-----------: Role detached -> child
|
||||
I (126813) OT_STATE: Set dns server address: FDE6:8626:404B:2::808:808
|
||||
I (126823) network_prov_mgr: Thread attached
|
||||
I (126823) app: Provisioning successful
|
||||
I (126823) app: Hello World!
|
||||
I (127833) app: Hello World!
|
||||
I (128833) app: Hello World!
|
||||
.
|
||||
.
|
||||
.
|
||||
I (131883) network_prov_mgr: Provisioning stopped
|
||||
.
|
||||
.
|
||||
.
|
||||
I (52355) app: Hello World!
|
||||
I (53355) app: Hello World!
|
||||
I (54355) app: Hello World!
|
||||
I (55355) app: Hello World!
|
||||
```
|
||||
|
||||
**Note:** For generating the credentials for security version 2 (`SRP6a` salt and verifier) for the device-side, the following example command can be used. The output can then directly be used in this example.
|
||||
|
||||
The config option `CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE` should be enabled for the example and in `main/app_main.c`, the macro `EXAMPLE_PROV_SEC2_USERNAME` should be set to the same username used in the salt-verifier generation.
|
||||
|
||||
```log
|
||||
$ python esp_prov.py --transport ble --sec_ver 2 --sec2_gen_cred --sec2_username threadprov --sec2_pwd abcd1234
|
||||
==== Salt-verifier for security scheme 2 (SRP6a) ====
|
||||
static const char sec2_salt[] = {
|
||||
0x1f, 0xff, 0x29, 0xf5, 0xc7, 0x7e, 0x07, 0x48, 0x02, 0xe9, 0x93, 0x3e, 0xa3, 0xa2, 0x26, 0x73
|
||||
};
|
||||
|
||||
static const char sec2_verifier[] = {
|
||||
0xa7, 0x29, 0xe6, 0xa5, 0x4d, 0x20, 0x57, 0x71, 0x7c, 0x9d, 0x78, 0x2d, 0x0a, 0xb0, 0x9f, 0xec,
|
||||
0x7e, 0x8b, 0xab, 0xf5, 0xe6, 0xc3, 0x36, 0x41, 0x93, 0xfd, 0xb9, 0x49, 0x67, 0xe7, 0x7f, 0x79,
|
||||
0x66, 0x25, 0x2e, 0xac, 0x89, 0x19, 0xb2, 0xb3, 0x14, 0xb1, 0x16, 0xb0, 0xb0, 0xe4, 0x34, 0xd4,
|
||||
0x99, 0x40, 0x85, 0xa4, 0x99, 0x2b, 0x84, 0x21, 0xa1, 0xfb, 0x15, 0x48, 0x04, 0x91, 0xf5, 0x74,
|
||||
.
|
||||
.
|
||||
.
|
||||
0x80, 0x86, 0xf4, 0xd5, 0x08, 0xbc, 0xb0, 0xdd, 0x6b, 0x50, 0xfa, 0xdd, 0x16, 0x10, 0x23, 0x4b
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### QR Code Scanning
|
||||
|
||||
Enabling `CONFIG_EXAMPLE_PROV_SHOW_QR` will display a QR code on the serial terminal, which can be scanned from the ESP Provisioning phone apps to start the Thread provisioning process. The ESP Provisioning phone apps will be released later.
|
||||
|
||||
The monitor log should display something like this :
|
||||
|
||||
```
|
||||
I (673) app: Provisioning started
|
||||
I (673) app: Scan this QR code from the provisioning application for Provisioning.
|
||||
I (693) QRCODE: Encoding below text with ECC LVL 0 & QR Code Version 10
|
||||
I (774) QRCODE: {"ver":"v1","name":"PROV_F72E6B","username":"threadprov","pop":"abcd1234","transport":"ble","network":"thread"}
|
||||
>
|
||||
█▀▀▀▀▀█ ▄▄▄█ ██▄▀█▀▀▀▀ ▀▄ ▄█▀█▄▀ █▀▀▀▀▀█
|
||||
█ ███ █ ▄▄██ ▀▄▄▄▀▀▀▄▀▄▀▀▄▄▄▄▄█▀▄ █ ███ █
|
||||
█ ▀▀▀ █ ▄ █ █▄ ▀ ▄ ▄▀▄ █▄███▀ █ ▀▀▀ █
|
||||
▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀▄▀ ▀ ▀▄▀ █ █▄█ █▄▀ ▀▀▀▀▀▀▀
|
||||
▀▀▀██▄▀██▄▀██▀▀▀ ▀▄▄█▄▀█ ▀▄▀▀▀█▄ █▄▀▄█ ▀▄
|
||||
██▄ ▀ ▀ ▀▄▄█ ▄█▄ ▀ ██ ▀█▀█▀█ █▀ ▀█▄▀█▄
|
||||
▄█▀▀▄▄▀█▄▀▀ ▀▄▄▄▄ ▀▀▄▄▀▄▀▀▀▀▄▀▄▄ ▄▄▄▄ ▀▀▄
|
||||
▀ █▄▄ ▀ ▀▀█▀▀█ ▄ ▀█▄█▄ ▀▀▀▀▄▀█ ▄█▄ ▄▀▀▄▄
|
||||
▀█▄█▀▀▀ ▄ ▀█▀██ █▄█▄▄▀▄▀▄▀ ▀ ▄▄█▄▀▄█▀▀▄
|
||||
█ ▀██ ▀▀▄▄▄▄██▀▀ █▄ ▄█▄▄▄▀█▀▄▀█ █▄█▄▄█ ▀
|
||||
▀▀▄ ▄ ▀▄ ▄█ ▄ ▀█▀ ▄ ▀ ▀▄ ▀█▀▄▀▄██ ▄█▄█▀█▄
|
||||
█▄▄ ▀▀ ▄▀ ▄ █▀ ▄ ▀██▄█▀ ▀ █▄ ▄▀▄█ ▀▄
|
||||
▄▄ ██▄▀▄█▀█▄▀▀ ▀ ▀ ▄█▄▀▄ ▀ █▄▄ ▄▄█▄█▄ ▀▀█
|
||||
█▄█ ▄▄▀▀ ▀ ▄ ▄▀▄ ▀▄ █▀ ▀ ▀█ ▄ ▀▀▄ ▄ ▀█
|
||||
█ ▄▀▀▀▀█▄▄ ▀ ▄█▄ ▀ ▄▄ ▄█▀▀ ▀▄▄█ ▄█▄ ▀ ▄
|
||||
█ █▀█ ▀█▄ ██▀▀ ▄ ██▄██▄█▀ █▄▀█▄██▄ ▄ ▀ ▄
|
||||
▀ ▀▀ ▀ ▄ ▀█▀█▄ ██ █ ▄ █ █ ▄█ ▄▀█▀▀▀█ ▀▄█
|
||||
█▀▀▀▀▀█ ▀▄ ▄██▀▀██▄▄ ▄ ▄█▀▄▀▄ ██ ▀ █ ▀ ▄
|
||||
█ ███ █ █▀▀ ▄▄▀▄▀ ▄▀ ▄█▄▄█ ▀ ██ █▀▀▀▀███▄
|
||||
█ ▀▀▀ █ ███ ▄▀ █▀▀█ █▄ ▄█ ▀▀ ▀ ▀██▀ ▀ ▄
|
||||
▀▀▀▀▀▀▀ ▀ ▀▀ ▀ ▀ ▀▀ ▀▀ ▀▀ ▀ ▀ ▀
|
||||
|
||||
I (1134) app: If QR code is not visible, copy paste the below URL in a browser.
|
||||
https://espressif.github.io/esp-jumpstart/qrcode.html?data={"ver":"v1","name":"PROV_F72E6B","username":"threadprov","pop":"abcd1234","transport":"ble","network":"thread"}
|
||||
|
||||
```
|
||||
|
||||
### Thread Scanning
|
||||
|
||||
Provisioning manager also supports providing real-time Thread scan results (performed on the device) during provisioning. This allows the client side applications to choose the Thread network for which the device is to be configured. Various information about the visible Thread networks is available, like signal strength (RSSI) and link quality (LQI), etc. Also, the manager now provides capabilities information which can be used by client applications to determine availability of specific features (like `thread_scan`).
|
||||
|
||||
When using the scan based provisioning, we don't need to specify the `--dataset_tlvs` fields explicitly:
|
||||
|
||||
```
|
||||
python esp_prov.py --transport ble --service_name PROV_F72E6B --pop abcd1234
|
||||
```
|
||||
|
||||
See below the sample output from `esp_prov` tool on running above command:
|
||||
|
||||
```
|
||||
Connecting...
|
||||
Connected
|
||||
Getting Services...
|
||||
Security scheme determined to be : 1
|
||||
|
||||
==== Starting Session ====
|
||||
==== Session Established ====
|
||||
|
||||
==== Scanning Thread Networks ====
|
||||
++++ Scan process executed in 6.247516632080078 sec
|
||||
++++ Scan results : 12
|
||||
|
||||
++++ Scan finished in 7.349079132080078 sec
|
||||
==== Thread Scan results ====
|
||||
S.N. PAN ID EXT PAN ID NAME EXT ADDR CHN RSSI LQI
|
||||
[ 1] 34121 9a6526ce2aaf4383 ST-34EW e2848e0e9e315357 11 -53 9
|
||||
[ 2] 14311 7e010e5a22beb040 OpenThread-37e7 02a2ab187a4fb728 21 -47 10
|
||||
[ 3] 14311 7e010e5a22beb040 OpenThread-37e7 22bfc4ba63cf3bb8 21 -44 9
|
||||
[ 4] 4660 dead00beef00cafe OpenThread-13b4 1e4d2bb3a614163f 22 -40 10
|
||||
[ 5] 48989 516f754f983e50c6 OpenThread-bf5d be64e2845dc1d21a 22 -46 9
|
||||
[ 6] 4660 dead00beef00cafe OpenThread-79c0 3e19ed4f89be20ee 22 -53 10
|
||||
[ 7] 31233 6c5105b3cb215393 qqqQQQQQQQQ 86ba2d8a2ded00d0 24 -47 8
|
||||
[ 8] 32231 0458ef52172c21d6 OpenThread-7de7 deca5eddda6da2a7 25 -50 10
|
||||
[ 9] 32231 0458ef52172c21d6 OpenThread-7de7 0e085d0f1d89db89 25 -45 10
|
||||
[10] 10299 07f592f684bc4266 MyHome1926416771 b268d0525d81f5c4 25 -59 9
|
||||
[11] 10299 07f592f684bc4266 MyHome1926416771 6ee0445b8d49d4b8 25 -56 9
|
||||
[12] 51344 7899e5214acf64db OpenThread-c890 b22f21bc5ce8a058 26 -40 10
|
||||
Select Network by number (0 to rescan) : 4
|
||||
Enter Thread network key string :
|
||||
|
||||
==== Sending Thread Dataset to Target ====
|
||||
==== Thread Dataset sent successfully ====
|
||||
|
||||
==== Applying Thread Config to Target ====
|
||||
==== Apply config sent successfully ====
|
||||
|
||||
==== Thread connection state ====
|
||||
==== Thread state: Attaching ====
|
||||
|
||||
==== Thread connection state ====
|
||||
==== Thread state: Attaching ====
|
||||
|
||||
==== Thread connection state ====
|
||||
==== Thread state: Attached ====
|
||||
==== Provisioning was successful ====
|
||||
|
||||
```
|
||||
|
||||
### Interactive Provisioning
|
||||
|
||||
`esp_prov` supports interactive provisioning. You can trigger the script with a simplified command and input the necessary details
|
||||
(`Proof-of-possession` for security scheme 1 and `SRP6a username`, `SRP6a password` for security scheme 2) as the provisioning process advances.
|
||||
|
||||
The command `python esp_prov.py --transport ble --sec_ver 2` gives out the following sample output:
|
||||
|
||||
```
|
||||
Discovering...
|
||||
==== BLE Discovery results ====
|
||||
S.N. Name Address
|
||||
.
|
||||
.
|
||||
.
|
||||
[35] PROV_F73E7E 60:55:F9:F7:3E:7E
|
||||
[36] 62-37-56-08-AA-64 62:37:56:08:AA:64
|
||||
.
|
||||
.
|
||||
.
|
||||
Select device by number (0 to rescan) : 35
|
||||
Connecting...
|
||||
Getting Services..
|
||||
Security Scheme 2 - SRP6a Username required: threadprov
|
||||
Security Scheme 2 - SRP6a Password required:
|
||||
|
||||
==== Starting Session ====
|
||||
==== Session Established ====
|
||||
|
||||
==== Scanning Thread Networks ====
|
||||
++++ Scan process executed in 6.247041702270508 sec
|
||||
++++ Scan results : 14
|
||||
|
||||
++++ Scan finished in 7.40191650390625 sec
|
||||
==== Thread Scan results ====
|
||||
S.N. PAN ID EXT PAN ID NAME EXT ADDR CHN RSSI LQI
|
||||
[ 1] 34121 9a6526ce2aaf4383 ST-34EW e2848e0e9e315357 11 -53 9
|
||||
[ 2] 14311 7e010e5a22beb040 OpenThread-37e7 02a2ab187a4fb728 21 -45 9
|
||||
[ 3] 14311 7e010e5a22beb040 OpenThread-37e7 22bfc4ba63cf3bb8 21 -40 10
|
||||
[ 4] 4660 dead00beef00cafe OpenThread-79c0 3e19ed4f89be20ee 22 -59 10
|
||||
[ 5] 4660 dead00beef00cafe OpenThread-13b4 1e4d2bb3a614163f 22 -43 9
|
||||
[ 6] 48989 516f754f983e50c6 OpenThread-bf5d be64e2845dc1d21a 22 -47 10
|
||||
[ 7] 23427 5b83dead5b83beef 5b83 8a1e30a60615c16c 24 -57 8
|
||||
[ 8] 31233 6c5105b3cb215393 qqqQQQQQQQQ 86ba2d8a2ded00d0 24 -48 10
|
||||
[ 9] 10299 07f592f684bc4266 MyHome1926416771 6ee0445b8d49d4b8 25 -55 9
|
||||
[10] 32231 0458ef52172c21d6 OpenThread-7de7 deca5eddda6da2a7 25 -50 10
|
||||
[11] 10299 07f592f684bc4266 MyHome1926416771 b268d0525d81f5c4 25 -55 9
|
||||
[12] 32231 0458ef52172c21d6 OpenThread-7de7 0e085d0f1d89db89 25 -47 10
|
||||
[13] 10299 07f592f684bc4266 MyHome1926416771 7e06f10b32fe678f 25 -54 10
|
||||
[14] 51344 7899e5214acf64db OpenThread-c890 b22f21bc5ce8a058 26 -42 10
|
||||
Select Network by number (0 to rescan) : 5
|
||||
Enter Thread network key string :
|
||||
|
||||
==== Sending Thread Dataset to Target ====
|
||||
==== Thread Dataset sent successfully ====
|
||||
|
||||
==== Applying Thread Config to Target ====
|
||||
==== Apply config sent successfully ====
|
||||
|
||||
==== Thread connection state ====
|
||||
==== Thread state: Attaching ====
|
||||
|
||||
==== Thread connection state ====
|
||||
==== Thread state: Attaching ====
|
||||
|
||||
==== Thread connection state ====
|
||||
==== Thread state: Attached ====
|
||||
==== Provisioning was successful ====
|
||||
```
|
||||
|
||||
### Sending Custom Data
|
||||
|
||||
The provisioning manager allows applications to send some custom data during provisioning, which may be
|
||||
required for some other operations like connecting to some cloud service. This is achieved by creating
|
||||
and registering additional endpoints using the below APIs
|
||||
|
||||
```
|
||||
network_prov_mgr_endpoint_create();
|
||||
network_prov_mgr_endpoint_register();
|
||||
```
|
||||
|
||||
In this particular example, we have added an endpoint named "custom-data" which can be tested
|
||||
by passing the `--custom_data <MyCustomData>` option to the esp\_prov tool. Following output is
|
||||
expected on success:
|
||||
|
||||
```
|
||||
==== Sending Custom data to esp32 ====
|
||||
CustomData response: SUCCESS
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Provisioning failed
|
||||
|
||||
It is possible that the Thread dataset provided were incorrect, or the device was not able to establish connection to the network, in which the the `esp_prov` script will notify failure (with reason). Serial monitor log will display the failure along with disconnect reason :
|
||||
|
||||
```
|
||||
E (367015) app: Provisioning failed!
|
||||
Reason : Thread network not found
|
||||
Please reset to factory and retry provisioning
|
||||
```
|
||||
|
||||
Once dataset have been applied, even though wrong dataset were provided, the device will no longer go into provisioning mode on subsequent reboots until NVS is erased (see following section).
|
||||
|
||||
### Provisioning does not start
|
||||
|
||||
If the serial monitor log shows the following :
|
||||
|
||||
```
|
||||
I (465) app: Already provisioned, enabling netif and starting Thread
|
||||
```
|
||||
|
||||
it means either the device has been provisioned earlier with or without success (e.g. scenario covered in above section), or that the Thread dataset was already set by some other application flashed previously onto your device.
|
||||
|
||||
To fix this we simple need to erase the NVS partition from flash. First we need to find out its address and size. This can be seen from the monitor log on the top right after reboot.
|
||||
|
||||
```
|
||||
I (47) boot: Partition Table:
|
||||
I (50) boot: ## Label Usage Type ST Offset Length
|
||||
I (58) boot: 0 nvs WiFi data 01 02 00009000 00006000
|
||||
I (65) boot: 1 phy_init RF data 01 01 0000f000 00001000
|
||||
I (73) boot: 2 factory factory app 00 00 00010000 00124f80
|
||||
I (80) boot: End of partition table
|
||||
```
|
||||
|
||||
Now erase NVS partition by running the following commands :
|
||||
|
||||
```
|
||||
$IDF_PATH/components/esptool_py/esptool/esptool.py erase_region 0x9000 0x6000
|
||||
```
|
||||
|
||||
### Bluetooth Pairing Request during provisioning
|
||||
|
||||
ESP-IDF now has functionality to enforce link encryption requirement while performing GATT write on characteristics of provisioning service. This will however result in a pairing pop-up dialog, if link is not encrypted. This feature is disabled by default. In order to enable this feature, please set `CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION=y` in the sdkconfig or select the configuration using "idf.py menuconfig" .
|
||||
|
||||
```
|
||||
Component Config --> Network Provisioning Manager --> Force Link Encryption during Characteristic Read/Write
|
||||
|
||||
```
|
||||
Recompiling the application with above changes should suffice to enable this functionality.
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "app_main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,82 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice EXAMPLE_PROV_SECURITY_VERSION
|
||||
bool "Protocomm security version"
|
||||
default EXAMPLE_PROV_SECURITY_VERSION_2
|
||||
help
|
||||
Network provisioning component offers 3 security versions.
|
||||
The example offers a choice between security version 1 and 2.
|
||||
|
||||
config EXAMPLE_PROV_SECURITY_VERSION_1
|
||||
bool "Security version 1"
|
||||
select ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1
|
||||
|
||||
config EXAMPLE_PROV_SECURITY_VERSION_2
|
||||
bool "Security version 2"
|
||||
select ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2
|
||||
endchoice
|
||||
|
||||
choice EXAMPLE_PROV_MODE
|
||||
bool "Security version 2 mode"
|
||||
depends on EXAMPLE_PROV_SECURITY_VERSION_2
|
||||
default EXAMPLE_PROV_SEC2_DEV_MODE
|
||||
|
||||
config EXAMPLE_PROV_SEC2_DEV_MODE
|
||||
bool "Security version 2 development mode"
|
||||
depends on EXAMPLE_PROV_SECURITY_VERSION_2
|
||||
help
|
||||
This enables the development mode for
|
||||
security version 2.
|
||||
Please note that this mode is NOT recommended for production purpose.
|
||||
|
||||
config EXAMPLE_PROV_SEC2_PROD_MODE
|
||||
bool "Security version 2 production mode"
|
||||
depends on EXAMPLE_PROV_SECURITY_VERSION_2
|
||||
help
|
||||
This enables the production mode for
|
||||
security version 2.
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_PROV_TRANSPORT
|
||||
int
|
||||
default 1 if EXAMPLE_PROV_TRANSPORT_BLE
|
||||
|
||||
config EXAMPLE_RESET_PROVISIONED
|
||||
bool
|
||||
default n
|
||||
prompt "Reset provisioned status of the device"
|
||||
help
|
||||
This erases the NVS to reset provisioned status of the device on every reboot.
|
||||
Provisioned status is determined by the Wi-Fi STA configuration, saved on the NVS.
|
||||
|
||||
config EXAMPLE_RESET_PROV_MGR_ON_FAILURE
|
||||
bool
|
||||
default y
|
||||
prompt "Reset provisioned credentials and state machine after session failure"
|
||||
help
|
||||
Enable resetting provisioned credentials and state machine after session failure.
|
||||
This will restart the provisioning service after retries are exhausted.
|
||||
|
||||
config EXAMPLE_PROV_MGR_MAX_RETRY_CNT
|
||||
int
|
||||
default 5
|
||||
prompt "Max retries before resetting provisioning state machine"
|
||||
depends on EXAMPLE_RESET_PROV_MGR_ON_FAILURE
|
||||
help
|
||||
Set the Maximum retry to avoid reconnecting to an inexistent AP or if credentials
|
||||
are misconfigured. Provisioned credentials are erased and internal state machine
|
||||
is reset after this threshold is reached.
|
||||
|
||||
config EXAMPLE_PROV_SHOW_QR
|
||||
bool "Show provisioning QR code"
|
||||
default y
|
||||
help
|
||||
Show the QR code for provisioning.
|
||||
|
||||
config EXAMPLE_REPROVISIONING
|
||||
bool "Re-provisioning"
|
||||
help
|
||||
Enable re-provisioning - allow the device to provision for new credentials
|
||||
after previous successful provisioning.
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,495 @@
|
||||
/* Network Provisioning Manager Example for Thread network
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/event_groups.h>
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_openthread.h>
|
||||
#include "esp_openthread_cli.h"
|
||||
#include "esp_openthread_netif_glue.h"
|
||||
#include "esp_openthread_types.h"
|
||||
#include <esp_ot_config.h>
|
||||
#include <esp_netif.h>
|
||||
#include <esp_event.h>
|
||||
#include <esp_mac.h>
|
||||
#include <esp_vfs_eventfd.h>
|
||||
#include <nvs_flash.h>
|
||||
|
||||
#include <network_provisioning/manager.h>
|
||||
|
||||
#include "openthread/cli.h"
|
||||
#include "openthread/instance.h"
|
||||
#include "openthread/logging.h"
|
||||
#include "openthread/tasklet.h"
|
||||
#include "openthread/thread.h"
|
||||
|
||||
#include <network_provisioning/scheme_ble.h>
|
||||
|
||||
#include "qrcode.h"
|
||||
|
||||
static const char *TAG = "app";
|
||||
|
||||
#if CONFIG_EXAMPLE_PROV_SECURITY_VERSION_2
|
||||
#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE
|
||||
#define EXAMPLE_PROV_SEC2_USERNAME "threadprov"
|
||||
#define EXAMPLE_PROV_SEC2_PWD "abcd1234"
|
||||
|
||||
/* This salt,verifier has been generated for username = "threadprov" and password = "abcd1234"
|
||||
* IMPORTANT NOTE: For production cases, this must be unique to every device
|
||||
* and should come from device manufacturing partition.*/
|
||||
static const char sec2_salt[] = {
|
||||
0x1f, 0xff, 0x29, 0xf5, 0xc7, 0x7e, 0x07, 0x48, 0x02, 0xe9, 0x93, 0x3e, 0xa3, 0xa2, 0x26, 0x73
|
||||
};
|
||||
|
||||
static const char sec2_verifier[] = {
|
||||
0xa7, 0x29, 0xe6, 0xa5, 0x4d, 0x20, 0x57, 0x71, 0x7c, 0x9d, 0x78, 0x2d, 0x0a, 0xb0, 0x9f, 0xec,
|
||||
0x7e, 0x8b, 0xab, 0xf5, 0xe6, 0xc3, 0x36, 0x41, 0x93, 0xfd, 0xb9, 0x49, 0x67, 0xe7, 0x7f, 0x79,
|
||||
0x66, 0x25, 0x2e, 0xac, 0x89, 0x19, 0xb2, 0xb3, 0x14, 0xb1, 0x16, 0xb0, 0xb0, 0xe4, 0x34, 0xd4,
|
||||
0x99, 0x40, 0x85, 0xa4, 0x99, 0x2b, 0x84, 0x21, 0xa1, 0xfb, 0x15, 0x48, 0x04, 0x91, 0xf5, 0x74,
|
||||
0x95, 0x8a, 0x88, 0xd4, 0x4e, 0x25, 0xf6, 0xf3, 0x8e, 0x5c, 0xf9, 0x3c, 0xda, 0xbb, 0x4f, 0xa2,
|
||||
0x47, 0xe1, 0x01, 0x8f, 0x1c, 0xf5, 0xe0, 0x34, 0x41, 0x0c, 0x88, 0x76, 0x46, 0xd0, 0x16, 0xd9,
|
||||
0xfa, 0x57, 0x3d, 0x78, 0x46, 0xf1, 0xcb, 0xb1, 0x05, 0x16, 0xab, 0xf7, 0xbf, 0x9d, 0xeb, 0x05,
|
||||
0x2e, 0xc1, 0xd5, 0xe1, 0xde, 0x92, 0xe6, 0x20, 0x5f, 0xe4, 0x27, 0xda, 0xe3, 0x59, 0x91, 0x27,
|
||||
0x7b, 0x40, 0x83, 0x4c, 0xe8, 0xb5, 0xe0, 0x75, 0xe6, 0xbf, 0x26, 0xa9, 0x67, 0x06, 0xa3, 0x15,
|
||||
0x2d, 0x20, 0x81, 0xd5, 0x2a, 0x2e, 0x30, 0x84, 0xdf, 0xa2, 0x82, 0x62, 0xc4, 0x47, 0x25, 0xb6,
|
||||
0x93, 0x73, 0x87, 0x3c, 0xa7, 0x57, 0x2a, 0x47, 0x96, 0x1d, 0x89, 0xce, 0x49, 0xc6, 0x9d, 0x4f,
|
||||
0x6b, 0x39, 0x38, 0x67, 0xbb, 0x85, 0x24, 0xdf, 0xcd, 0xf5, 0xf1, 0x9f, 0x0a, 0x9e, 0x1c, 0x31,
|
||||
0xfa, 0xf1, 0x01, 0xa5, 0x30, 0xf0, 0xcb, 0x5e, 0x1c, 0xd6, 0xa0, 0x11, 0x3f, 0xf8, 0xdd, 0x07,
|
||||
0x09, 0x53, 0x62, 0x9f, 0x76, 0x5c, 0x69, 0xd1, 0x5e, 0x5b, 0xc7, 0xb0, 0x0e, 0x53, 0xeb, 0x8c,
|
||||
0x67, 0x88, 0xc7, 0x45, 0xc0, 0x26, 0xd9, 0xfa, 0xf8, 0x63, 0x0c, 0x64, 0xcb, 0x9e, 0xf4, 0x1b,
|
||||
0xb3, 0xfd, 0x78, 0x0c, 0x47, 0x0f, 0x66, 0xf3, 0xf7, 0xcd, 0xe9, 0xc6, 0x36, 0xa5, 0x58, 0xe5,
|
||||
0x9d, 0x31, 0x53, 0xb2, 0xe4, 0x8e, 0xdd, 0xd0, 0x8d, 0x13, 0xe8, 0xc6, 0x96, 0x60, 0x30, 0x50,
|
||||
0xbc, 0xef, 0xce, 0xbc, 0x23, 0xe3, 0x60, 0x63, 0x54, 0x11, 0x24, 0xba, 0x68, 0x47, 0x6a, 0xb2,
|
||||
0x5e, 0x70, 0xa3, 0xa6, 0xc3, 0xad, 0x58, 0xd1, 0x3b, 0xce, 0xce, 0x90, 0xe9, 0x90, 0x7e, 0x7a,
|
||||
0xfb, 0x4f, 0x69, 0xa2, 0x81, 0xdf, 0x15, 0xec, 0xa7, 0x8f, 0xd6, 0x5a, 0xb8, 0x1f, 0x42, 0x18,
|
||||
0x0e, 0x4f, 0x3e, 0x45, 0x2d, 0x08, 0xf2, 0xd6, 0x51, 0x90, 0xef, 0x64, 0x77, 0xee, 0xcc, 0x3c,
|
||||
0xb4, 0xa6, 0x6f, 0x0b, 0x10, 0xb2, 0xce, 0x31, 0x19, 0x10, 0x8d, 0x75, 0x8f, 0xa8, 0xa2, 0x6e,
|
||||
0x7a, 0x00, 0x92, 0x91, 0xe2, 0x16, 0xe3, 0x7a, 0xf9, 0x1d, 0x4e, 0x39, 0xe5, 0xd0, 0xd1, 0x7e,
|
||||
0x80, 0x86, 0xf4, 0xd5, 0x08, 0xbc, 0xb0, 0xdd, 0x6b, 0x50, 0xfa, 0xdd, 0x16, 0x10, 0x23, 0x4b
|
||||
};
|
||||
#endif
|
||||
|
||||
static esp_err_t example_get_sec2_salt(const char **salt, uint16_t *salt_len)
|
||||
{
|
||||
#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE
|
||||
ESP_LOGI(TAG, "Development mode: using hard coded salt");
|
||||
*salt = sec2_salt;
|
||||
*salt_len = sizeof(sec2_salt);
|
||||
return ESP_OK;
|
||||
#elif CONFIG_EXAMPLE_PROV_SEC2_PROD_MODE
|
||||
ESP_LOGE(TAG, "Not implemented!");
|
||||
return ESP_FAIL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static esp_err_t example_get_sec2_verifier(const char **verifier, uint16_t *verifier_len)
|
||||
{
|
||||
#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE
|
||||
ESP_LOGI(TAG, "Development mode: using hard coded verifier");
|
||||
*verifier = sec2_verifier;
|
||||
*verifier_len = sizeof(sec2_verifier);
|
||||
return ESP_OK;
|
||||
#elif CONFIG_EXAMPLE_PROV_SEC2_PROD_MODE
|
||||
/* This code needs to be updated with appropriate implementation to provide verifier */
|
||||
ESP_LOGE(TAG, "Not implemented!");
|
||||
return ESP_FAIL;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Signal Thread events on this event-group */
|
||||
const int THREAD_ATTACHED_EVENT = BIT0;
|
||||
static EventGroupHandle_t thread_event_group;
|
||||
|
||||
#define PROV_QR_VERSION "v1"
|
||||
#define PROV_TRANSPORT_BLE "ble"
|
||||
#define QRCODE_BASE_URL "https://espressif.github.io/esp-jumpstart/qrcode.html"
|
||||
|
||||
/* Event handler for catching system events */
|
||||
static void event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
if (event_base == NETWORK_PROV_EVENT) {
|
||||
switch (event_id) {
|
||||
case NETWORK_PROV_START:
|
||||
ESP_LOGI(TAG, "Provisioning started");
|
||||
break;
|
||||
case NETWORK_PROV_THREAD_DATASET_RECV: {
|
||||
// TODO Log thread dataset
|
||||
break;
|
||||
}
|
||||
case NETWORK_PROV_THREAD_DATASET_FAIL: {
|
||||
network_prov_thread_fail_reason_t *reason = (network_prov_thread_fail_reason_t *)event_data;
|
||||
ESP_LOGE(TAG, "Provisioning failed!\n\tReason : %s"
|
||||
"\n\tPlease reset to factory and retry provisioning",
|
||||
(*reason == NETWORK_PROV_THREAD_DATASET_INVALID) ?
|
||||
"Invalid Thread dataset" : "Thread network not found");
|
||||
break;
|
||||
}
|
||||
case NETWORK_PROV_THREAD_DATASET_SUCCESS:
|
||||
ESP_LOGI(TAG, "Provisioning successful");
|
||||
break;
|
||||
case NETWORK_PROV_END:
|
||||
/* De-initialize manager once provisioning is finished */
|
||||
network_prov_mgr_deinit();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (event_base == OPENTHREAD_EVENT && event_id == OPENTHREAD_EVENT_ATTACHED) {
|
||||
xEventGroupSetBits(thread_event_group, THREAD_ATTACHED_EVENT);
|
||||
} else if (event_base == PROTOCOMM_SECURITY_SESSION_EVENT) {
|
||||
switch (event_id) {
|
||||
case PROTOCOMM_SECURITY_SESSION_SETUP_OK:
|
||||
ESP_LOGI(TAG, "Secured session established!");
|
||||
break;
|
||||
case PROTOCOMM_SECURITY_SESSION_INVALID_SECURITY_PARAMS:
|
||||
ESP_LOGE(TAG, "Received invalid security parameters for establishing secure session!");
|
||||
break;
|
||||
case PROTOCOMM_SECURITY_SESSION_CREDENTIALS_MISMATCH:
|
||||
ESP_LOGE(TAG, "Received incorrect username and/or PoP for establishing secure session!");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void get_device_service_name(char *service_name, size_t max)
|
||||
{
|
||||
uint8_t ieee802154_mac[8];
|
||||
const char *ssid_prefix = "PROV_";
|
||||
esp_read_mac(ieee802154_mac, ESP_MAC_IEEE802154);
|
||||
snprintf(service_name, max, "%s%02X%02X%02X",
|
||||
ssid_prefix, ieee802154_mac[5], ieee802154_mac[6], ieee802154_mac[7]);
|
||||
}
|
||||
|
||||
/* Handler for the optional provisioning endpoint registered by the application.
|
||||
* The data format can be chosen by applications. Here, we are using plain ascii text.
|
||||
* Applications can choose to use other formats like protobuf, JSON, XML, etc.
|
||||
*/
|
||||
esp_err_t custom_prov_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,
|
||||
uint8_t **outbuf, ssize_t *outlen, void *priv_data)
|
||||
{
|
||||
if (inbuf) {
|
||||
ESP_LOGI(TAG, "Received data: %.*s", inlen, (char *)inbuf);
|
||||
}
|
||||
char response[] = "SUCCESS";
|
||||
*outbuf = (uint8_t *)strdup(response);
|
||||
if (*outbuf == NULL) {
|
||||
ESP_LOGE(TAG, "System out of memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
*outlen = strlen(response) + 1; /* +1 for NULL terminating byte */
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void network_prov_print_qr(const char *name, const char *username, const char *pop, const char *transport)
|
||||
{
|
||||
if (!name || !transport) {
|
||||
ESP_LOGW(TAG, "Cannot generate QR code payload. Data missing.");
|
||||
return;
|
||||
}
|
||||
char payload[150] = {0};
|
||||
if (pop) {
|
||||
#if CONFIG_EXAMPLE_PROV_SECURITY_VERSION_1
|
||||
snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
|
||||
",\"pop\":\"%s\",\"transport\":\"%s\"}",
|
||||
PROV_QR_VERSION, name, pop, transport);
|
||||
#elif CONFIG_EXAMPLE_PROV_SECURITY_VERSION_2
|
||||
snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
|
||||
",\"username\":\"%s\",\"pop\":\"%s\",\"transport\":\"%s\"}",
|
||||
PROV_QR_VERSION, name, username, pop, transport);
|
||||
#endif
|
||||
} else {
|
||||
snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
|
||||
",\"transport\":\"%s\"}",
|
||||
PROV_QR_VERSION, name, transport);
|
||||
}
|
||||
#ifdef CONFIG_EXAMPLE_PROV_SHOW_QR
|
||||
ESP_LOGI(TAG, "Scan this QR code from the provisioning application for Provisioning.");
|
||||
esp_qrcode_config_t cfg = ESP_QRCODE_CONFIG_DEFAULT();
|
||||
esp_qrcode_generate(&cfg, payload);
|
||||
//TODO: Add the network protocol type to the QR code payload
|
||||
#endif /* CONFIG EXAMPLE_PROV_SHOW_QR */
|
||||
ESP_LOGI(TAG, "If QR code is not visible, copy paste the below URL in a browser.\n%s?data=%s", QRCODE_BASE_URL, payload);
|
||||
}
|
||||
|
||||
static esp_netif_t *init_openthread_netif(const esp_openthread_platform_config_t *config)
|
||||
{
|
||||
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_OPENTHREAD();
|
||||
esp_netif_t *netif = esp_netif_new(&cfg);
|
||||
assert(netif != NULL);
|
||||
ESP_ERROR_CHECK(esp_netif_attach(netif, esp_openthread_netif_glue_init(config)));
|
||||
|
||||
return netif;
|
||||
}
|
||||
|
||||
static void ot_task_worker(void *aContext)
|
||||
{
|
||||
esp_openthread_platform_config_t config = {
|
||||
.radio_config = ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG(),
|
||||
.host_config = ESP_OPENTHREAD_DEFAULT_HOST_CONFIG(),
|
||||
.port_config = ESP_OPENTHREAD_DEFAULT_PORT_CONFIG(),
|
||||
};
|
||||
|
||||
// Initialize the OpenThread stack
|
||||
ESP_ERROR_CHECK(esp_openthread_init(&config));
|
||||
#if CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC
|
||||
// The OpenThread log level directly matches ESP log level
|
||||
(void)otLoggingSetLevel(CONFIG_LOG_DEFAULT_LEVEL);
|
||||
#endif
|
||||
#if CONFIG_OPENTHREAD_CLI
|
||||
// Initialize the OpenThread cli
|
||||
esp_openthread_cli_init();
|
||||
#endif
|
||||
esp_netif_t *openthread_netif = init_openthread_netif(&config);
|
||||
// Initialize the esp_netif bindings
|
||||
esp_netif_set_default_netif(openthread_netif);
|
||||
|
||||
// Run the main loop
|
||||
#if CONFIG_OPENTHREAD_CLI
|
||||
esp_openthread_cli_create_task();
|
||||
#endif
|
||||
esp_openthread_launch_mainloop();
|
||||
|
||||
// Clean up
|
||||
esp_netif_destroy(openthread_netif);
|
||||
esp_openthread_netif_glue_deinit();
|
||||
|
||||
esp_vfs_eventfd_unregister();
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/* Initialize NVS partition */
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
/* NVS partition was truncated
|
||||
* and needs to be erased */
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
|
||||
/* Retry nvs_flash_init */
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
}
|
||||
|
||||
/* Initialize TCP/IP */
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
|
||||
/* Initialize the event loop */
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
thread_event_group = xEventGroupCreate();
|
||||
|
||||
/* Register our event handler for OpenThread and Provisioning related events */
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(NETWORK_PROV_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(PROTOCOMM_TRANSPORT_BLE_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
|
||||
#endif
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(PROTOCOMM_SECURITY_SESSION_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(OPENTHREAD_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
|
||||
|
||||
esp_vfs_eventfd_config_t eventfd_config = {
|
||||
.max_fds = 3,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config));
|
||||
xTaskCreate(ot_task_worker, "ot_task", 6144, xTaskGetCurrentTaskHandle(), 5, NULL);
|
||||
|
||||
/* Configuration for the provisioning manager */
|
||||
network_prov_mgr_config_t config = {
|
||||
/* Use network_prov_scheme_ble as the Provisioning Scheme */
|
||||
.scheme = network_prov_scheme_ble,
|
||||
|
||||
/* Any default scheme specific event handler that you would
|
||||
* like to choose. Since our example application requires
|
||||
* neither BT nor BLE, we can choose to release the associated
|
||||
* memory once provisioning is complete, or not needed
|
||||
* (in case when device is already provisioned). Choosing
|
||||
* appropriate scheme specific event handler allows the manager
|
||||
* to take care of this automatically. */
|
||||
.scheme_event_handler = NETWORK_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BLE
|
||||
};
|
||||
|
||||
/* Initialize provisioning manager with the
|
||||
* configuration parameters set above */
|
||||
ESP_ERROR_CHECK(network_prov_mgr_init(config));
|
||||
|
||||
bool provisioned = false;
|
||||
#ifdef CONFIG_EXAMPLE_RESET_PROVISIONED
|
||||
network_prov_mgr_reset_thread_provisioning();
|
||||
#else
|
||||
/* Let's find out if the device is provisioned */
|
||||
ESP_ERROR_CHECK(network_prov_mgr_is_thread_provisioned(&provisioned));
|
||||
|
||||
#endif
|
||||
/* If device is not yet provisioned start provisioning service */
|
||||
if (!provisioned) {
|
||||
ESP_LOGI(TAG, "Starting provisioning");
|
||||
|
||||
/* What is the Device Service Name that we want
|
||||
* This translates to :
|
||||
* - device name when scheme is network_prov_scheme_ble
|
||||
*/
|
||||
char service_name[12];
|
||||
get_device_service_name(service_name, sizeof(service_name));
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_PROV_SECURITY_VERSION_1
|
||||
/* What is the security level that we want (0, 1, 2):
|
||||
* - NETWORK_PROV_SECURITY_0 is simply plain text communication.
|
||||
* - NETWORK_PROV_SECURITY_1 is secure communication which consists of secure handshake
|
||||
* using X25519 key exchange and proof of possession (pop) and AES-CTR
|
||||
* for encryption/decryption of messages.
|
||||
* - NETWORK_PROV_SECURITY_2 SRP6a based authentication and key exchange
|
||||
* + AES-GCM encryption/decryption of messages
|
||||
*/
|
||||
network_prov_security_t security = NETWORK_PROV_SECURITY_1;
|
||||
|
||||
/* Do we want a proof-of-possession (ignored if Security 0 is selected):
|
||||
* - this should be a string with length > 0
|
||||
* - NULL if not used
|
||||
*/
|
||||
const char *pop = "abcd1234";
|
||||
|
||||
/* This is the structure for passing security parameters
|
||||
* for the protocomm security 1.
|
||||
*/
|
||||
network_prov_security1_params_t *sec_params = pop;
|
||||
|
||||
const char *username = NULL;
|
||||
|
||||
#elif CONFIG_EXAMPLE_PROV_SECURITY_VERSION_2
|
||||
network_prov_security_t security = NETWORK_PROV_SECURITY_2;
|
||||
/* The username must be the same one, which has been used in the generation of salt and verifier */
|
||||
|
||||
#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE
|
||||
/* This pop field represents the password that will be used to generate salt and verifier.
|
||||
* The field is present here in order to generate the QR code containing password.
|
||||
* In production this password field shall not be stored on the device */
|
||||
const char *username = EXAMPLE_PROV_SEC2_USERNAME;
|
||||
const char *pop = EXAMPLE_PROV_SEC2_PWD;
|
||||
#elif CONFIG_EXAMPLE_PROV_SEC2_PROD_MODE
|
||||
/* The username and password shall not be embedded in the firmware,
|
||||
* they should be provided to the user by other means.
|
||||
* e.g. QR code sticker */
|
||||
const char *username = NULL;
|
||||
const char *pop = NULL;
|
||||
#endif
|
||||
/* This is the structure for passing security parameters
|
||||
* for the protocomm security 2.
|
||||
* If dynamically allocated, sec2_params pointer and its content
|
||||
* must be valid till WIFI_PROV_END event is triggered.
|
||||
*/
|
||||
network_prov_security2_params_t sec2_params = {};
|
||||
|
||||
ESP_ERROR_CHECK(example_get_sec2_salt(&sec2_params.salt, &sec2_params.salt_len));
|
||||
ESP_ERROR_CHECK(example_get_sec2_verifier(&sec2_params.verifier, &sec2_params.verifier_len));
|
||||
|
||||
network_prov_security2_params_t *sec_params = &sec2_params;
|
||||
#endif
|
||||
/* What is the service key (could be NULL)
|
||||
* This translates to :
|
||||
* - simply ignored when scheme is network_prov_scheme_ble
|
||||
*/
|
||||
const char *service_key = NULL;
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE
|
||||
/* This step is only useful when scheme is network_prov_scheme_ble. This will
|
||||
* set a custom 128 bit UUID which will be included in the BLE advertisement
|
||||
* and will correspond to the primary GATT service that provides provisioning
|
||||
* endpoints as GATT characteristics. Each GATT characteristic will be
|
||||
* formed using the primary service UUID as base, with different auto assigned
|
||||
* 12th and 13th bytes (assume counting starts from 0th byte). The client side
|
||||
* applications must identify the endpoints by reading the User Characteristic
|
||||
* Description descriptor (0x2901) for each characteristic, which contains the
|
||||
* endpoint name of the characteristic */
|
||||
uint8_t custom_service_uuid[] = {
|
||||
/* LSB <---------------------------------------
|
||||
* ---------------------------------------> MSB */
|
||||
0xb4, 0xdf, 0x5a, 0x1c, 0x3f, 0x6b, 0xf4, 0xbf,
|
||||
0xea, 0x4a, 0x82, 0x03, 0x04, 0x90, 0x1a, 0x02,
|
||||
};
|
||||
|
||||
/* If your build fails with linker errors at this point, then you may have
|
||||
* forgotten to enable the BT stack or BTDM BLE settings in the SDK (e.g. see
|
||||
* the sdkconfig.defaults in the example project) */
|
||||
network_prov_scheme_ble_set_service_uuid(custom_service_uuid);
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_BLE */
|
||||
|
||||
/* An optional endpoint that applications can create if they expect to
|
||||
* get some additional custom data during provisioning workflow.
|
||||
* The endpoint name can be anything of your choice.
|
||||
* This call must be made before starting the provisioning.
|
||||
*/
|
||||
network_prov_mgr_endpoint_create("custom-data");
|
||||
|
||||
/* Do not stop and de-init provisioning even after success,
|
||||
* so that we can restart it later. */
|
||||
#ifdef CONFIG_EXAMPLE_REPROVISIONING
|
||||
network_prov_mgr_disable_auto_stop(1000);
|
||||
#endif
|
||||
/* Start provisioning service */
|
||||
ESP_ERROR_CHECK(network_prov_mgr_start_provisioning(security, (const void *) sec_params, service_name, service_key));
|
||||
|
||||
/* The handler for the optional endpoint created above.
|
||||
* This call must be made after starting the provisioning, and only if the endpoint
|
||||
* has already been created above.
|
||||
*/
|
||||
network_prov_mgr_endpoint_register("custom-data", custom_prov_data_handler, NULL);
|
||||
|
||||
/* Uncomment the following to wait for the provisioning to finish and then release
|
||||
* the resources of the manager. Since in this case de-initialization is triggered
|
||||
* by the default event loop handler, we don't need to call the following */
|
||||
// network_prov_mgr_wait();
|
||||
// network_prov_mgr_deinit();
|
||||
/* Print QR code for provisioning */
|
||||
network_prov_print_qr(service_name, username, pop, PROV_TRANSPORT_BLE);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Already provisioned, enabling netif and starting Thread");
|
||||
|
||||
/* We don't need the manager as device is already provisioned,
|
||||
* so let's release it's resources */
|
||||
network_prov_mgr_deinit();
|
||||
|
||||
otInstance *instance = esp_openthread_get_instance();
|
||||
(void)otIp6SetEnabled(instance, true);
|
||||
(void)otThreadSetEnabled(instance, true);
|
||||
}
|
||||
|
||||
/* Wait for Thread connection */
|
||||
xEventGroupWaitBits(thread_event_group, THREAD_ATTACHED_EVENT, true, true, portMAX_DELAY);
|
||||
|
||||
/* Start main application now */
|
||||
#if CONFIG_EXAMPLE_REPROVISIONING
|
||||
while (1) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ESP_LOGI(TAG, "Hello World!");
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
/* Resetting provisioning state machine to enable re-provisioning */
|
||||
network_prov_mgr_reset_thread_sm_state_for_reprovision();
|
||||
|
||||
/* Wait for thread connection */
|
||||
xEventGroupWaitBits(thread_event_group, THREAD_ATTACHED_EVENT, true, true, portMAX_DELAY);
|
||||
}
|
||||
#else
|
||||
while (1) {
|
||||
ESP_LOGI(TAG, "Hello World!");
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/* Network Provisioning Manager Example for Thread network
|
||||
*
|
||||
* This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, this
|
||||
* software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_openthread_types.h"
|
||||
|
||||
#if SOC_IEEE802154_SUPPORTED
|
||||
#define ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG() \
|
||||
{ \
|
||||
.radio_mode = RADIO_MODE_NATIVE, \
|
||||
}
|
||||
|
||||
#else
|
||||
#define ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG() \
|
||||
{ \
|
||||
.radio_mode = RADIO_MODE_UART_RCP, \
|
||||
.radio_uart_config = { \
|
||||
.port = 1, \
|
||||
.uart_config = \
|
||||
{ \
|
||||
.baud_rate = 115200, \
|
||||
.data_bits = UART_DATA_8_BITS, \
|
||||
.parity = UART_PARITY_DISABLE, \
|
||||
.stop_bits = UART_STOP_BITS_1, \
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE, \
|
||||
.rx_flow_ctrl_thresh = 0, \
|
||||
.source_clk = UART_SCLK_DEFAULT, \
|
||||
}, \
|
||||
.rx_pin = 4, \
|
||||
.tx_pin = 5, \
|
||||
}, \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \
|
||||
{ \
|
||||
.host_connection_mode = HOST_CONNECTION_MODE_CLI_UART, \
|
||||
.host_uart_config = { \
|
||||
.port = 0, \
|
||||
.uart_config = \
|
||||
{ \
|
||||
.baud_rate = 115200, \
|
||||
.data_bits = UART_DATA_8_BITS, \
|
||||
.parity = UART_PARITY_DISABLE, \
|
||||
.stop_bits = UART_STOP_BITS_1, \
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE, \
|
||||
.rx_flow_ctrl_thresh = 0, \
|
||||
.source_clk = UART_SCLK_DEFAULT, \
|
||||
}, \
|
||||
.rx_pin = UART_PIN_NO_CHANGE, \
|
||||
.tx_pin = UART_PIN_NO_CHANGE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \
|
||||
{ \
|
||||
.storage_partition_name = "nvs", \
|
||||
.netif_queue_size = 10, \
|
||||
.task_queue_size = 10, \
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
dependencies:
|
||||
espressif/network_provisioning:
|
||||
version: ^1.0.0
|
||||
espressif/qrcode:
|
||||
version: ^0.1.0
|
||||
version: 1.0.0
|
||||
@@ -0,0 +1,5 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||
nvs, data, nvs, , 0x6000,
|
||||
phy_init, data, phy, , 0x1000,
|
||||
factory, app, factory, , 0x180000,
|
||||
|
@@ -0,0 +1,31 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
|
||||
## For Bluedroid as binary is larger than default size
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
|
||||
# mbedTLS
|
||||
CONFIG_MBEDTLS_CMAC_C=y
|
||||
CONFIG_MBEDTLS_SSL_PROTO_DTLS=y
|
||||
CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y
|
||||
CONFIG_MBEDTLS_ECJPAKE_C=y
|
||||
|
||||
# OpenThread
|
||||
CONFIG_OPENTHREAD_ENABLED=y
|
||||
CONFIG_OPENTHREAD_BORDER_ROUTER=n
|
||||
CONFIG_OPENTHREAD_DNS64_CLIENT=y
|
||||
|
||||
# Network type
|
||||
CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD=y
|
||||
|
||||
# LwIP
|
||||
CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096
|
||||
CONFIG_LWIP_IPV6_NUM_ADDRESSES=8
|
||||
CONFIG_LWIP_MULTICAST_PING=y
|
||||
CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_CUSTOM=y
|
||||
|
||||
# IEEE 802.15.4
|
||||
CONFIG_IEEE802154_ENABLED=y
|
||||
@@ -0,0 +1,5 @@
|
||||
# ESP32 specific default configurations
|
||||
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
@@ -0,0 +1,7 @@
|
||||
# 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)
|
||||
set(COMPONENTS main)
|
||||
project(wifi_prov)
|
||||
@@ -0,0 +1,402 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# Wi-Fi Provisioning Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
`wifi_prov` example demonstrates the usage of `network_provisioning` manager component for building a Wi-Fi provisioning application.
|
||||
|
||||
For this example, Bluetooth LE is chosen as the default mode of transport, over which the provisioning related communication is to take place. NimBLE has been configured as the default host, but you can also switch to Bluedroid using menuconfig -> Components -> Bluetooth -> Bluetooth Host.
|
||||
|
||||
> Note: Since ESP32-S2 does not support Bluetooth LE, the SoftAP will be the default mode of transport in that case. Even for ESP32, you can change to SoftAP transport from menuconfig.
|
||||
|
||||
In the provisioning process the device is configured as a Wi-Fi station with specified credentials. Once configured, the device will retain the Wi-Fi configuration, until a flash erase is performed.
|
||||
|
||||
Right after provisioning is complete, Bluetooth LE is turned off and disabled to free the memory used by the Bluetooth LE stack. Though, that is specific to this example, and the user can choose to keep Bluetooth LE stack intact in their own application.
|
||||
|
||||
`wifi_prov` uses the following components :
|
||||
* `network_provisioning` : Provides provisioning manager, data structures and protocomm endpoint handlers for Wi-Fi configuration
|
||||
* `protocomm` : For protocol based communication and secure session establishment
|
||||
* `protobuf` : Google's protocol buffer library for serialization of protocomm data structures
|
||||
* `bt` : ESP-IDF's Bluetooth LE stack for transport of protobuf packets
|
||||
|
||||
This example can be used, as it is, for adding a provisioning service to any application intended for IoT.
|
||||
|
||||
> Note: If you use this example code in your own project, in Bluetooth LE mode, then remember to enable the BT stack and BTDM BLE control settings in your SDK configuration (e.g. by using the `sdkconfig.defaults` file from this project).
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
Example should be able to run on any commonly available ESP32/ESP32-C2/ESP32-C3/ESP32-C6/ESP32-S2/ESP32-S3 development board.
|
||||
|
||||
### Script Required
|
||||
|
||||
Currently, Provisioning script is available for `Linux / Windows / macOS` platforms.
|
||||
|
||||
#### Platform : Linux / Windows / macOS
|
||||
|
||||
To install the dependency packages needed, please refer to the ESP-IDF examples [README file](https://github.com/espressif/esp-idf/blob/master/examples/README.md#running-test-python-script-ttfw).
|
||||
|
||||
`esp_prov` supports Bluetooth LE and SoftAP transport for Linux, MacOS and Windows platforms. For Bluetooth LE, however, if dependencies are not met, the script falls back to console mode and requires another application through which the communication can take place. The `esp_prov` console will guide you through the provisioning process of locating the correct Bluetooth LE GATT services and characteristics, the values to write, and input read values.
|
||||
|
||||
### Configure the project
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
* Set the Bluetooth LE/Soft AP transport under "Example Configuration" options. ESP32-S2 will have only SoftAP option (SoftAP option cannot be used if IPv4 is disabled in lwIP)
|
||||
|
||||
### 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 (445) app: Starting provisioning
|
||||
I (1035) app: Provisioning started
|
||||
I (1045) network_prov_mgr: Provisioning started with service name : PROV_01B1E8
|
||||
```
|
||||
|
||||
Make sure to note down the Bluetooth LE device name (starting with `PROV_`) displayed in the serial monitor log (eg. PROV_01B1E8). This will depend on the MAC ID and will be unique for every device.
|
||||
|
||||
In a separate terminal run the `esp_prov.py` script under [directory](../../tool/esp_prov) (make sure to replace `myssid` and `mypassword` with the credentials of the AP to which the device is supposed to connect to after provisioning). Assuming default example configuration, which uses the protocomm security version 2 with username and password authentication:
|
||||
|
||||
```
|
||||
python esp_prov.py --transport ble --service_name PROV_01B1E8 --sec_ver 2 --sec2_username wifiprov --sec2_pwd abcd1234 --ssid myssid --passphrase mypassword
|
||||
```
|
||||
|
||||
For security scheme 1 with PoP-based (proof-of-possession) authentication, the following command can be used:
|
||||
```
|
||||
python esp_prov.py --transport ble --service_name PROV_01B1E8 --sec_ver 1 --pop abcd1234 --ssid myssid --passphrase mypassword
|
||||
```
|
||||
|
||||
Above command will perform the provisioning steps, and the monitor log should display something like this :
|
||||
|
||||
```
|
||||
I (39725) app: Received Wi-Fi credentials
|
||||
SSID : myssid
|
||||
Password : mypassword
|
||||
.
|
||||
.
|
||||
.
|
||||
I (45335) esp_netif_handlers: sta ip: 192.168.43.243, mask: 255.255.255.0, gw: 192.168.43.1
|
||||
I (45345) app: Provisioning successful
|
||||
I (45345) app: Connected with IP Address:192.168.43.243
|
||||
I (46355) app: Hello World!
|
||||
I (47355) app: Hello World!
|
||||
I (48355) app: Hello World!
|
||||
I (49355) app: Hello World!
|
||||
.
|
||||
.
|
||||
.
|
||||
I (52315) network_prov_mgr: Provisioning stopped
|
||||
.
|
||||
.
|
||||
.
|
||||
I (52355) app: Hello World!
|
||||
I (53355) app: Hello World!
|
||||
I (54355) app: Hello World!
|
||||
I (55355) app: Hello World!
|
||||
```
|
||||
|
||||
**Note:** For generating the credentials for security version 2 (`SRP6a` salt and verifier) for the device-side, the following example command can be used. The output can then directly be used in this example.
|
||||
|
||||
The config option `CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE` should be enabled for the example and in `main/app_main.c`, the macro `EXAMPLE_PROV_SEC2_USERNAME` should be set to the same username used in the salt-verifier generation.
|
||||
|
||||
```log
|
||||
$ python esp_prov.py --transport softap --sec_ver 2 --sec2_gen_cred --sec2_username wifiprov --sec2_pwd abcd1234
|
||||
==== Salt-verifier for security scheme 2 (SRP6a) ====
|
||||
static const char sec2_salt[] = {
|
||||
0x03, 0x6e, 0xe0, 0xc7, 0xbc, 0xb9, 0xed, 0xa8, 0x4c, 0x9e, 0xac, 0x97, 0xd9, 0x3d, 0xec, 0xf4
|
||||
};
|
||||
|
||||
static const char sec2_verifier[] = {
|
||||
0x7c, 0x7c, 0x85, 0x47, 0x65, 0x08, 0x94, 0x6d, 0xd6, 0x36, 0xaf, 0x37, 0xd7, 0xe8, 0x91, 0x43,
|
||||
0x78, 0xcf, 0xfd, 0x61, 0x6c, 0x59, 0xd2, 0xf8, 0x39, 0x08, 0x12, 0x72, 0x38, 0xde, 0x9e, 0x24,
|
||||
.
|
||||
.
|
||||
.
|
||||
0xe6, 0xf6, 0x53, 0xc8, 0x31, 0xa8, 0x78, 0xde, 0x50, 0x40, 0xf7, 0x62, 0xde, 0x36, 0xb2, 0xba
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### QR Code Scanning
|
||||
|
||||
Enabling `CONFIG_EXAMPLE_PROV_SHOW_QR` will display a QR code on the serial terminal, which can be scanned from the ESP Provisioning phone apps to start the Wi-Fi provisioning process.
|
||||
|
||||
The monitor log should display something like this :
|
||||
|
||||
```
|
||||
I (690) app: Provisioning started
|
||||
I (690) app: Scan this QR code from the provisioning application for Provisioning.
|
||||
I (700) QRCODE: Encoding below text with ECC LVL 0 & QR Code Version 10
|
||||
I (710) QRCODE: {"ver":"v1","name":"PROV_01B1E8","username":"wifiprov","pop":"abcd1234","transport":"ble","network":"wifi"}
|
||||
|
||||
█▀▀▀▀▀█ ▄▀▀████▄██▀▀▀▀ ▀▄██▄ ▄▄▀ █▀▀▀▀▀█
|
||||
█ ███ █ ▄▀ ▀▀▀▄ █▀▀▀█▀▄▀█▄█▄ ▄▀▀ █ ███ █
|
||||
█ ▀▀▀ █ ▄█▄▀▄ █▄▀█ ▄ █▀▀ ▀▄███▀▀ █ ▀▀▀ █
|
||||
▀▀▀▀▀▀▀ ▀▄▀ █ ▀▄▀ ▀ ▀▄▀ █ █ █ █▄▀ ▀▀▀▀▀▀▀
|
||||
▀▀█▀▀ ▀█▀ ██▀▀ ▀▄▀ ▄▄ ▀█ ▀█▄██▄ █▄▀▄█ █▄
|
||||
▀ █▀▀██▄█▀▀ ▄█ ▀ ▀██ ▀ █▀ ▄ █▀▄▀█▄▀█
|
||||
▀▄ ▀▄ ▀█ ██ ▀ ▄█▄ ▀▀▄█ ▄▀▀▀▀█▀▄▄ ▄█▄ ▀ ▄
|
||||
█▄▄█ ▄▀▀▀ █▀▀ ▄ ██▄█▄▄▀ ██▄▀█▄ █▄▄ ▀▄▄
|
||||
▀██▀█▄▀ █▄▀█▄█▄ ██ █▄ ▀▄▀█▄▀▀ █▄█▄▀▄▄▀▀▄
|
||||
▄▄▀▀▄ ▀▄▄▀▀ ▀█▀▀ █▄▄█ ▀▄▄▀▄█ ██ ▄▄█ ▀▄
|
||||
█▀█▄▀▀ █▀ ▄▄▀█▀ ▄ ▀▀▀▄▀█ ▀█▀██▀▄▄▄▄███▄
|
||||
█▄▀▄▀▀▀▀▄█ ▄▀ █▀▀█ ▀██ ▄ ██ █▄ ▄▀▀█ ▀▄
|
||||
▀▄█▀▀ ▀ ▀ ▄▄▀▀ ▀ ▀▄▄█▄▀█ ▀ ▀▀ ▄▄█▄█▄ ▀▀█
|
||||
▀ █▀▀█▀▄▀ ▄▄▄ ▄█▄ ▀▄ █▄ ▀ ▀█▀█ ▀ █ ▄ ▀█▄
|
||||
█▀▀█▄▄▀█ ▄ ▀ ▄▄▄▄▀ ▄█▄▄▀▀▄ ▄▀█▄ ▄▄▄ ▀▀▄
|
||||
█ ▄ █▀▀▄█▀▄█▀▀ ▄▀ █▄██▄ ▀ ▀▄▀█ ▄█▄ ▄▄▀ ▄
|
||||
▀ ▀ ▀ ▀▀█▄██▀█▀ █ █ ▄ █ ▄█▄▄ █▀▀▀█▀▀▀█
|
||||
█▀▀▀▀▀█ ▀▀█▄██▀▀ █▄▄ ▀▄█▀ ▀▄ ▄██ ▀ █ ▀▀
|
||||
█ ███ █ █▀▀ ▄ ▀█▀ ▄▀▀█▀▄ █ ▀▄██ █▀▀▀▀█▀█▄
|
||||
█ ▀▀▀ █ █▄ ▄ ▄█▀▀▄ ▀▄ ▄█ ▀▀ ▀ ███▀ ▀▄ ▄
|
||||
▀▀▀▀▀▀▀ ▀▀▀ ▀▀▀▀ ▀▀ ▀ ▀▀ ▀▀ ▀ ▀▀ ▀▀
|
||||
|
||||
I (1000) app: If QR code is not visible, copy paste the below URL in a browser.
|
||||
https://espressif.github.io/esp-jumpstart/qrcode.html?data={"ver":"v1","name":"PROV_01B1E8","username":"wifiprov","pop":"abcd1234","transport":"ble","network":"wifi"}
|
||||
```
|
||||
|
||||
### Wi-Fi Scanning
|
||||
|
||||
Provisioning manager also supports providing real-time Wi-Fi scan results (performed on the device) during provisioning. This allows the client side applications to choose the AP for which the device Wi-Fi station is to be configured. Various information about the visible APs is available, like signal strength (RSSI) and security type, etc. Also, the manager now provides capabilities information which can be used by client applications to determine the security type and availability of specific features (like `wifi_scan`).
|
||||
|
||||
When using the scan based provisioning, we don't need to specify the `--ssid` and `--passphrase` fields explicitly:
|
||||
|
||||
```
|
||||
python esp_prov.py --transport ble --service_name PROV_01B1E8 --pop abcd1234
|
||||
```
|
||||
|
||||
See below the sample output from `esp_prov` tool on running above command:
|
||||
|
||||
```
|
||||
Connecting...
|
||||
Connected
|
||||
Getting Services...
|
||||
Security scheme determined to be : 1
|
||||
|
||||
==== Starting Session ====
|
||||
==== Session Established ====
|
||||
|
||||
==== Scanning Wi-Fi APs ====
|
||||
++++ Scan process executed in 1.9967520237 sec
|
||||
++++ Scan results : 5
|
||||
|
||||
++++ Scan finished in 2.7374596596 sec
|
||||
==== Wi-Fi Scan results ====
|
||||
S.N. SSID BSSID CHN RSSI AUTH
|
||||
[ 1] MyHomeWiFiAP 788a20841996 1 -45 WPA2_PSK
|
||||
[ 2] MobileHotspot 7a8a20841996 11 -46 WPA2_PSK
|
||||
[ 3] MyHomeWiFiAP 788a208daa26 11 -54 WPA2_PSK
|
||||
[ 4] NeighborsWiFiAP 8a8a20841996 6 -61 WPA2_PSK
|
||||
[ 5] InsecureWiFiAP dca4caf1227c 7 -74 Open
|
||||
|
||||
Select AP by number (0 to rescan) : 1
|
||||
Enter passphrase for MyHomeWiFiAP :
|
||||
|
||||
==== Sending Wi-Fi Credentials to Target ====
|
||||
==== Wi-Fi Credentials sent successfully ====
|
||||
|
||||
==== Applying Wi-Fi Config to Target ====
|
||||
==== Apply config sent successfully ====
|
||||
|
||||
==== Wi-Fi connection state ====
|
||||
==== WiFi state: Connected ====
|
||||
==== Provisioning was successful ====
|
||||
```
|
||||
|
||||
### Interactive Provisioning
|
||||
|
||||
`esp_prov` supports interactive provisioning. You can trigger the script with a simplified command and input the necessary details
|
||||
(`Proof-of-possession` for security scheme 1 and `SRP6a username`, `SRP6a password` for security scheme 2) as the provisioning process advances.
|
||||
|
||||
The command `python esp_prov.py --transport ble --sec_ver 1` gives out the following sample output:
|
||||
|
||||
```
|
||||
Discovering...
|
||||
==== BLE Discovery results ====
|
||||
S.N. Name Address
|
||||
[ 1] PROV_4C33E8 01:02:03:04:05:06
|
||||
[ 1] BT_DEVICE_SBC 0A:0B:0C:0D:0E:0F
|
||||
Select device by number (0 to rescan) : 1
|
||||
Connecting...
|
||||
Getting Services...
|
||||
Proof of Possession required:
|
||||
|
||||
==== Starting Session ====
|
||||
==== Session Established ====
|
||||
|
||||
==== Scanning Wi-Fi APs ====
|
||||
++++ Scan process executed in 3.8695244789123535 sec
|
||||
++++ Scan results : 2
|
||||
|
||||
++++ Scan finished in 4.4132080078125 sec
|
||||
==== Wi-Fi Scan results ====
|
||||
S.N. SSID BSSID CHN RSSI AUTH
|
||||
[ 1] MyHomeWiFiAP 788a20841996 1 -45 WPA2_PSK
|
||||
[ 2] MobileHotspot 7a8a20841996 11 -46 WPA2_PSK
|
||||
|
||||
Select AP by number (0 to rescan) : 1
|
||||
Enter passphrase for myssid :
|
||||
|
||||
==== Sending Wi-Fi Credentials to Target ====
|
||||
==== Wi-Fi Credentials sent successfully ====
|
||||
|
||||
==== Applying Wi-Fi Config to Target ====
|
||||
==== Apply config sent successfully ====
|
||||
|
||||
==== Wi-Fi connection state ====
|
||||
==== WiFi state: Connected ====
|
||||
==== Provisioning was successful ====
|
||||
```
|
||||
|
||||
### Sending Custom Data
|
||||
|
||||
The provisioning manager allows applications to send some custom data during provisioning, which may be
|
||||
required for some other operations like connecting to some cloud service. This is achieved by creating
|
||||
and registering additional endpoints using the below APIs
|
||||
|
||||
```
|
||||
network_prov_mgr_endpoint_create();
|
||||
network_prov_mgr_endpoint_register();
|
||||
```
|
||||
|
||||
In this particular example, we have added an endpoint named "custom-data" which can be tested
|
||||
by passing the `--custom_data <MyCustomData>` option to the esp\_prov tool. Following output is
|
||||
expected on success:
|
||||
|
||||
```
|
||||
==== Sending Custom data to esp32 ====
|
||||
CustomData response: SUCCESS
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Provisioning failed
|
||||
|
||||
It is possible that the Wi-Fi credentials provided were incorrect, or the device was not able to establish connection to the network, in which the the `esp_prov` script will notify failure (with reason). Serial monitor log will display the failure along with disconnect reason :
|
||||
|
||||
```
|
||||
E (367015) app: Provisioning failed!
|
||||
Reason : Wi-Fi AP password incorrect
|
||||
Please reset to factory and retry provisioning
|
||||
```
|
||||
|
||||
Once credentials have been applied, even though wrong credentials were provided, the device will no longer go into provisioning mode on subsequent reboots until NVS is erased (see following section).
|
||||
|
||||
### Provisioning does not start
|
||||
|
||||
If the serial monitor log shows the following :
|
||||
|
||||
```
|
||||
I (465) app: Already provisioned, starting Wi-Fi STA
|
||||
```
|
||||
|
||||
it means either the device has been provisioned earlier with or without success (e.g. scenario covered in above section), or that the Wi-Fi credentials were already set by some other application flashed previously onto your device. On setting the log level to DEBUG this is clearly evident :
|
||||
|
||||
```
|
||||
D (455) network_prov_mgr: Found Wi-Fi SSID : myssid
|
||||
D (465) network_prov_mgr: Found Wi-Fi Password : m********d
|
||||
I (465) app: Already provisioned, starting Wi-Fi STA
|
||||
```
|
||||
|
||||
To fix this we simple need to erase the NVS partition from flash. First we need to find out its address and size. This can be seen from the monitor log on the top right after reboot.
|
||||
|
||||
```
|
||||
I (47) boot: Partition Table:
|
||||
I (50) boot: ## Label Usage Type ST Offset Length
|
||||
I (58) boot: 0 nvs WiFi data 01 02 00009000 00006000
|
||||
I (65) boot: 1 phy_init RF data 01 01 0000f000 00001000
|
||||
I (73) boot: 2 factory factory app 00 00 00010000 00124f80
|
||||
I (80) boot: End of partition table
|
||||
```
|
||||
|
||||
Now erase NVS partition by running the following commands :
|
||||
|
||||
```
|
||||
$IDF_PATH/components/esptool_py/esptool/esptool.py erase_region 0x9000 0x6000
|
||||
```
|
||||
|
||||
### Bluetooth Pairing Request during provisioning
|
||||
|
||||
ESP-IDF now has functionality to enforce link encryption requirement while performing GATT write on characteristics of provisioning service. This will however result in a pairing pop-up dialog, if link is not encrypted. This feature is disabled by default. In order to enable this feature, please set `CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION=y` in the sdkconfig or select the configuration using "idf.py menuconfig" .
|
||||
|
||||
```
|
||||
Component Config --> Wi-Fi Provisioning Manager --> Force Link Encryption during Characteristic Read/Write
|
||||
|
||||
```
|
||||
Recompiling the application with above changes should suffice to enable this functionality.
|
||||
|
||||
|
||||
### Unsupported platform
|
||||
|
||||
If the platform requirement, for running `esp_prov` is not satisfied, then the script execution will fallback to console mode, in which case the full process (involving user inputs) will look like this :
|
||||
|
||||
```
|
||||
==== Esp_Prov Version: v1.0 ====
|
||||
BLE client is running in console mode
|
||||
This could be due to your platform not being supported or dependencies not being met
|
||||
Please ensure all pre-requisites are met to run the full fledged client
|
||||
BLECLI >> Please connect to BLE device `PROV_01B1E8` manually using your tool of choice
|
||||
BLECLI >> Was the device connected successfully? [y/n] y
|
||||
BLECLI >> List available attributes of the connected device
|
||||
BLECLI >> Is the service UUID '0000ffff-0000-1000-8000-00805f9b34fb' listed among available attributes? [y/n] y
|
||||
BLECLI >> Is the characteristic UUID '0000ff53-0000-1000-8000-00805f9b34fb' listed among available attributes? [y/n] y
|
||||
BLECLI >> Is the characteristic UUID '0000ff51-0000-1000-8000-00805f9b34fb' listed among available attributes? [y/n] y
|
||||
BLECLI >> Is the characteristic UUID '0000ff52-0000-1000-8000-00805f9b34fb' listed among available attributes? [y/n] y
|
||||
|
||||
==== Verifying protocol version ====
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff53-0000-1000-8000-00805f9b34fb' :
|
||||
>> 56302e31
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 53554343455353
|
||||
==== Verified protocol version successfully ====
|
||||
|
||||
==== Starting Session ====
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff51-0000-1000-8000-00805f9b34fb' :
|
||||
>> 10015a25a201220a20ae6d9d5d1029f8c366892252d2d5a0ffa7ce1ee5829312545dd5f2aba057294d
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 10015a390801aa0134122048008bfc365fad4753dc75912e0c764d60749cb26dd609595b6fbc72e12614031a1089733af233c7448e7d7fb7963682c6d8
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff51-0000-1000-8000-00805f9b34fb' :
|
||||
>> 10015a270802b2012212204051088dc294fe4621fac934a8ea22e948fcc3e8ac458aac088ce705c65dbfb9
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 10015a270803ba01221a20c8d38059d5206a3d92642973ac6ba8ac2f6ecf2b7a3632964eb35a0f20133adb
|
||||
==== Session Established ====
|
||||
|
||||
==== Sending Wifi credential to esp32 ====
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff52-0000-1000-8000-00805f9b34fb' :
|
||||
>> 98471ac4019a46765c28d87df8c8ae71c1ae6cfe0bc9c615bc6d2c
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 3271f39a
|
||||
==== Wifi Credentials sent successfully ====
|
||||
|
||||
==== Applying config to esp32 ====
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff52-0000-1000-8000-00805f9b34fb' :
|
||||
>> 5355
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 1664db24
|
||||
==== Apply config sent successfully ====
|
||||
|
||||
==== Wifi connection state ====
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff52-0000-1000-8000-00805f9b34fb' :
|
||||
>> 290d
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 505f72a9f8521025c1964d7789c4d7edc56aedebd144e1b667bc7c0975757b80cc091aa9f3e95b06eaefbc30290fa1
|
||||
++++ WiFi state: connected ++++
|
||||
==== Provisioning was successful ====
|
||||
```
|
||||
|
||||
The write data is to be copied from the console output ```>>``` to the platform specific application and the data read from the application is to be pasted at the user input prompt ```<<``` of the console, in the format (hex) indicated in above sample log.
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "app_main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,114 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice EXAMPLE_PROV_TRANSPORT
|
||||
bool "Provisioning Transport"
|
||||
default EXAMPLE_PROV_TRANSPORT_SOFTAP if IDF_TARGET_ESP32S2
|
||||
default EXAMPLE_PROV_TRANSPORT_BLE
|
||||
help
|
||||
Wi-Fi provisioning component offers both, SoftAP and BLE transports. Choose any one.
|
||||
|
||||
config EXAMPLE_PROV_TRANSPORT_BLE
|
||||
bool "BLE"
|
||||
select BT_ENABLED
|
||||
depends on !IDF_TARGET_ESP32S2
|
||||
config EXAMPLE_PROV_TRANSPORT_SOFTAP
|
||||
bool "Soft AP"
|
||||
select LWIP_IPV4
|
||||
endchoice
|
||||
|
||||
choice EXAMPLE_PROV_SECURITY_VERSION
|
||||
bool "Protocomm security version"
|
||||
default EXAMPLE_PROV_SECURITY_VERSION_2
|
||||
help
|
||||
Wi-Fi provisioning component offers 3 security versions.
|
||||
The example offers a choice between security version 1 and 2.
|
||||
|
||||
config EXAMPLE_PROV_SECURITY_VERSION_1
|
||||
bool "Security version 1"
|
||||
select ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1
|
||||
|
||||
config EXAMPLE_PROV_SECURITY_VERSION_2
|
||||
bool "Security version 2"
|
||||
select ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2
|
||||
endchoice
|
||||
|
||||
choice EXAMPLE_PROV_MODE
|
||||
bool "Security version 2 mode"
|
||||
depends on EXAMPLE_PROV_SECURITY_VERSION_2
|
||||
default EXAMPLE_PROV_SEC2_DEV_MODE
|
||||
|
||||
config EXAMPLE_PROV_SEC2_DEV_MODE
|
||||
bool "Security version 2 development mode"
|
||||
depends on EXAMPLE_PROV_SECURITY_VERSION_2
|
||||
help
|
||||
This enables the development mode for
|
||||
security version 2.
|
||||
Please note that this mode is NOT recommended for production purpose.
|
||||
|
||||
config EXAMPLE_PROV_SEC2_PROD_MODE
|
||||
bool "Security version 2 production mode"
|
||||
depends on EXAMPLE_PROV_SECURITY_VERSION_2
|
||||
help
|
||||
This enables the production mode for
|
||||
security version 2.
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_PROV_TRANSPORT
|
||||
int
|
||||
default 1 if EXAMPLE_PROV_TRANSPORT_BLE
|
||||
default 2 if EXAMPLE_PROV_TRANSPORT_SOFTAP
|
||||
|
||||
config EXAMPLE_PROV_ENABLE_APP_CALLBACK
|
||||
bool "Enable provisioning manager app callback"
|
||||
default n
|
||||
help
|
||||
This is for advanced use-cases like modifying Wi-Fi configuration parameters. This
|
||||
executes a blocking app callback when any provisioning event is triggered.
|
||||
|
||||
config EXAMPLE_RESET_PROVISIONED
|
||||
bool
|
||||
default n
|
||||
prompt "Reset provisioned status of the device"
|
||||
help
|
||||
This erases the NVS to reset provisioned status of the device on every reboot.
|
||||
Provisioned status is determined by the Wi-Fi STA configuration, saved on the NVS.
|
||||
|
||||
config EXAMPLE_RESET_PROV_MGR_ON_FAILURE
|
||||
bool
|
||||
default y
|
||||
prompt "Reset provisioned credentials and state machine after session failure"
|
||||
help
|
||||
Enable resetting provisioned credentials and state machine after session failure.
|
||||
This will restart the provisioning service after retries are exhausted.
|
||||
|
||||
config EXAMPLE_PROV_MGR_CONNECTION_CNT
|
||||
int
|
||||
default 5
|
||||
prompt "Max connection attempts before resetting provisioning state machine"
|
||||
depends on EXAMPLE_RESET_PROV_MGR_ON_FAILURE
|
||||
help
|
||||
Set the total number of connection attempts to avoid reconnecting to an inexistent AP or if credentials
|
||||
are misconfigured. Provisioned credentials are erased and internal state machine
|
||||
is reset after this threshold is reached.
|
||||
|
||||
config EXAMPLE_PROV_SHOW_QR
|
||||
bool "Show provisioning QR code"
|
||||
default y
|
||||
help
|
||||
Show the QR code for provisioning.
|
||||
|
||||
config EXAMPLE_PROV_USING_BLUEDROID
|
||||
bool
|
||||
depends on (BT_BLUEDROID_ENABLED && (IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3))
|
||||
select BT_BLE_42_FEATURES_SUPPORTED
|
||||
default y
|
||||
help
|
||||
This enables BLE 4.2 features for Bluedroid.
|
||||
|
||||
config EXAMPLE_REPROVISIONING
|
||||
bool "Re-provisioning"
|
||||
help
|
||||
Enable re-provisioning - allow the device to provision for new credentials
|
||||
after previous successful provisioning.
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,560 @@
|
||||
/* Wi-Fi Provisioning Manager Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/event_groups.h>
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_event.h>
|
||||
#include <nvs_flash.h>
|
||||
|
||||
#include <network_provisioning/manager.h>
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE
|
||||
#include <network_provisioning/scheme_ble.h>
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_BLE */
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP
|
||||
#include <network_provisioning/scheme_softap.h>
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP */
|
||||
#include "qrcode.h"
|
||||
|
||||
static const char *TAG = "app";
|
||||
|
||||
#if CONFIG_EXAMPLE_PROV_SECURITY_VERSION_2
|
||||
#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE
|
||||
#define EXAMPLE_PROV_SEC2_USERNAME "wifiprov"
|
||||
#define EXAMPLE_PROV_SEC2_PWD "abcd1234"
|
||||
|
||||
/* This salt,verifier has been generated for username = "wifiprov" and password = "abcd1234"
|
||||
* IMPORTANT NOTE: For production cases, this must be unique to every device
|
||||
* and should come from device manufacturing partition.*/
|
||||
static const char sec2_salt[] = {
|
||||
0x03, 0x6e, 0xe0, 0xc7, 0xbc, 0xb9, 0xed, 0xa8, 0x4c, 0x9e, 0xac, 0x97, 0xd9, 0x3d, 0xec, 0xf4
|
||||
};
|
||||
|
||||
static const char sec2_verifier[] = {
|
||||
0x7c, 0x7c, 0x85, 0x47, 0x65, 0x08, 0x94, 0x6d, 0xd6, 0x36, 0xaf, 0x37, 0xd7, 0xe8, 0x91, 0x43,
|
||||
0x78, 0xcf, 0xfd, 0x61, 0x6c, 0x59, 0xd2, 0xf8, 0x39, 0x08, 0x12, 0x72, 0x38, 0xde, 0x9e, 0x24,
|
||||
0xa4, 0x70, 0x26, 0x1c, 0xdf, 0xa9, 0x03, 0xc2, 0xb2, 0x70, 0xe7, 0xb1, 0x32, 0x24, 0xda, 0x11,
|
||||
0x1d, 0x97, 0x18, 0xdc, 0x60, 0x72, 0x08, 0xcc, 0x9a, 0xc9, 0x0c, 0x48, 0x27, 0xe2, 0xae, 0x89,
|
||||
0xaa, 0x16, 0x25, 0xb8, 0x04, 0xd2, 0x1a, 0x9b, 0x3a, 0x8f, 0x37, 0xf6, 0xe4, 0x3a, 0x71, 0x2e,
|
||||
0xe1, 0x27, 0x86, 0x6e, 0xad, 0xce, 0x28, 0xff, 0x54, 0x46, 0x60, 0x1f, 0xb9, 0x96, 0x87, 0xdc,
|
||||
0x57, 0x40, 0xa7, 0xd4, 0x6c, 0xc9, 0x77, 0x54, 0xdc, 0x16, 0x82, 0xf0, 0xed, 0x35, 0x6a, 0xc4,
|
||||
0x70, 0xad, 0x3d, 0x90, 0xb5, 0x81, 0x94, 0x70, 0xd7, 0xbc, 0x65, 0xb2, 0xd5, 0x18, 0xe0, 0x2e,
|
||||
0xc3, 0xa5, 0xf9, 0x68, 0xdd, 0x64, 0x7b, 0xb8, 0xb7, 0x3c, 0x9c, 0xfc, 0x00, 0xd8, 0x71, 0x7e,
|
||||
0xb7, 0x9a, 0x7c, 0xb1, 0xb7, 0xc2, 0xc3, 0x18, 0x34, 0x29, 0x32, 0x43, 0x3e, 0x00, 0x99, 0xe9,
|
||||
0x82, 0x94, 0xe3, 0xd8, 0x2a, 0xb0, 0x96, 0x29, 0xb7, 0xdf, 0x0e, 0x5f, 0x08, 0x33, 0x40, 0x76,
|
||||
0x52, 0x91, 0x32, 0x00, 0x9f, 0x97, 0x2c, 0x89, 0x6c, 0x39, 0x1e, 0xc8, 0x28, 0x05, 0x44, 0x17,
|
||||
0x3f, 0x68, 0x02, 0x8a, 0x9f, 0x44, 0x61, 0xd1, 0xf5, 0xa1, 0x7e, 0x5a, 0x70, 0xd2, 0xc7, 0x23,
|
||||
0x81, 0xcb, 0x38, 0x68, 0xe4, 0x2c, 0x20, 0xbc, 0x40, 0x57, 0x76, 0x17, 0xbd, 0x08, 0xb8, 0x96,
|
||||
0xbc, 0x26, 0xeb, 0x32, 0x46, 0x69, 0x35, 0x05, 0x8c, 0x15, 0x70, 0xd9, 0x1b, 0xe9, 0xbe, 0xcc,
|
||||
0xa9, 0x38, 0xa6, 0x67, 0xf0, 0xad, 0x50, 0x13, 0x19, 0x72, 0x64, 0xbf, 0x52, 0xc2, 0x34, 0xe2,
|
||||
0x1b, 0x11, 0x79, 0x74, 0x72, 0xbd, 0x34, 0x5b, 0xb1, 0xe2, 0xfd, 0x66, 0x73, 0xfe, 0x71, 0x64,
|
||||
0x74, 0xd0, 0x4e, 0xbc, 0x51, 0x24, 0x19, 0x40, 0x87, 0x0e, 0x92, 0x40, 0xe6, 0x21, 0xe7, 0x2d,
|
||||
0x4e, 0x37, 0x76, 0x2f, 0x2e, 0xe2, 0x68, 0xc7, 0x89, 0xe8, 0x32, 0x13, 0x42, 0x06, 0x84, 0x84,
|
||||
0x53, 0x4a, 0xb3, 0x0c, 0x1b, 0x4c, 0x8d, 0x1c, 0x51, 0x97, 0x19, 0xab, 0xae, 0x77, 0xff, 0xdb,
|
||||
0xec, 0xf0, 0x10, 0x95, 0x34, 0x33, 0x6b, 0xcb, 0x3e, 0x84, 0x0f, 0xb9, 0xd8, 0x5f, 0xb8, 0xa0,
|
||||
0xb8, 0x55, 0x53, 0x3e, 0x70, 0xf7, 0x18, 0xf5, 0xce, 0x7b, 0x4e, 0xbf, 0x27, 0xce, 0xce, 0xa8,
|
||||
0xb3, 0xbe, 0x40, 0xc5, 0xc5, 0x32, 0x29, 0x3e, 0x71, 0x64, 0x9e, 0xde, 0x8c, 0xf6, 0x75, 0xa1,
|
||||
0xe6, 0xf6, 0x53, 0xc8, 0x31, 0xa8, 0x78, 0xde, 0x50, 0x40, 0xf7, 0x62, 0xde, 0x36, 0xb2, 0xba
|
||||
};
|
||||
#endif
|
||||
|
||||
static esp_err_t example_get_sec2_salt(const char **salt, uint16_t *salt_len)
|
||||
{
|
||||
#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE
|
||||
ESP_LOGI(TAG, "Development mode: using hard coded salt");
|
||||
*salt = sec2_salt;
|
||||
*salt_len = sizeof(sec2_salt);
|
||||
return ESP_OK;
|
||||
#elif CONFIG_EXAMPLE_PROV_SEC2_PROD_MODE
|
||||
ESP_LOGE(TAG, "Not implemented!");
|
||||
return ESP_FAIL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static esp_err_t example_get_sec2_verifier(const char **verifier, uint16_t *verifier_len)
|
||||
{
|
||||
#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE
|
||||
ESP_LOGI(TAG, "Development mode: using hard coded verifier");
|
||||
*verifier = sec2_verifier;
|
||||
*verifier_len = sizeof(sec2_verifier);
|
||||
return ESP_OK;
|
||||
#elif CONFIG_EXAMPLE_PROV_SEC2_PROD_MODE
|
||||
/* This code needs to be updated with appropriate implementation to provide verifier */
|
||||
ESP_LOGE(TAG, "Not implemented!");
|
||||
return ESP_FAIL;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Signal Wi-Fi events on this event-group */
|
||||
const int WIFI_CONNECTED_EVENT = BIT0;
|
||||
static EventGroupHandle_t wifi_event_group;
|
||||
|
||||
#define PROV_QR_VERSION "v1"
|
||||
#define PROV_TRANSPORT_SOFTAP "softap"
|
||||
#define PROV_TRANSPORT_BLE "ble"
|
||||
#define QRCODE_BASE_URL "https://espressif.github.io/esp-jumpstart/qrcode.html"
|
||||
|
||||
/* Event handler for catching system events */
|
||||
static void event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
if (event_base == NETWORK_PROV_EVENT) {
|
||||
switch (event_id) {
|
||||
case NETWORK_PROV_START:
|
||||
ESP_LOGI(TAG, "Provisioning started");
|
||||
break;
|
||||
case NETWORK_PROV_WIFI_CRED_RECV: {
|
||||
wifi_sta_config_t *wifi_sta_cfg = (wifi_sta_config_t *)event_data;
|
||||
ESP_LOGI(TAG, "Received Wi-Fi credentials"
|
||||
"\n\tSSID : %s\n\tPassword : %s",
|
||||
(const char *) wifi_sta_cfg->ssid,
|
||||
(const char *) wifi_sta_cfg->password);
|
||||
break;
|
||||
}
|
||||
case NETWORK_PROV_WIFI_CRED_FAIL: {
|
||||
network_prov_wifi_sta_fail_reason_t *reason = (network_prov_wifi_sta_fail_reason_t *)event_data;
|
||||
ESP_LOGE(TAG, "Provisioning failed!\n\tReason : %s"
|
||||
"\n\tPlease reset to factory and retry provisioning",
|
||||
(*reason == NETWORK_PROV_WIFI_STA_AUTH_ERROR) ?
|
||||
"Wi-Fi station authentication failed" : "Wi-Fi access-point not found");
|
||||
#ifdef CONFIG_EXAMPLE_RESET_PROV_MGR_ON_FAILURE
|
||||
/* Reset the state machine on provisioning failure.
|
||||
* This is enabled by the CONFIG_EXAMPLE_RESET_PROV_MGR_ON_FAILURE configuration.
|
||||
* It allows the provisioning manager to retry the provisioning process
|
||||
* based on the number of attempts specified in wifi_conn_attempts. After attempting
|
||||
* the maximum number of retries, the provisioning manager will reset the state machine
|
||||
* and the provisioning process will be terminated.
|
||||
*/
|
||||
network_prov_mgr_reset_wifi_sm_state_on_failure();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case NETWORK_PROV_WIFI_CRED_SUCCESS:
|
||||
ESP_LOGI(TAG, "Provisioning successful");
|
||||
break;
|
||||
case NETWORK_PROV_END:
|
||||
/* De-initialize manager once provisioning is finished */
|
||||
esp_err_t err = network_prov_mgr_deinit();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to de-initialize provisioning manager: %s", esp_err_to_name(err));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (event_base == WIFI_EVENT) {
|
||||
switch (event_id) {
|
||||
case WIFI_EVENT_STA_START:
|
||||
esp_wifi_connect();
|
||||
break;
|
||||
case WIFI_EVENT_STA_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "Disconnected. Connecting to the AP again...");
|
||||
esp_wifi_connect();
|
||||
break;
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP
|
||||
case WIFI_EVENT_AP_STACONNECTED:
|
||||
ESP_LOGI(TAG, "SoftAP transport: Connected!");
|
||||
break;
|
||||
case WIFI_EVENT_AP_STADISCONNECTED:
|
||||
ESP_LOGI(TAG, "SoftAP transport: Disconnected!");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
|
||||
ESP_LOGI(TAG, "Connected with IP Address:" IPSTR, IP2STR(&event->ip_info.ip));
|
||||
/* Signal main application to continue execution */
|
||||
xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_EVENT);
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE
|
||||
} else if (event_base == PROTOCOMM_TRANSPORT_BLE_EVENT) {
|
||||
switch (event_id) {
|
||||
case PROTOCOMM_TRANSPORT_BLE_CONNECTED:
|
||||
ESP_LOGI(TAG, "BLE transport: Connected!");
|
||||
break;
|
||||
case PROTOCOMM_TRANSPORT_BLE_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "BLE transport: Disconnected!");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
} else if (event_base == PROTOCOMM_SECURITY_SESSION_EVENT) {
|
||||
switch (event_id) {
|
||||
case PROTOCOMM_SECURITY_SESSION_SETUP_OK:
|
||||
ESP_LOGI(TAG, "Secured session established!");
|
||||
break;
|
||||
case PROTOCOMM_SECURITY_SESSION_INVALID_SECURITY_PARAMS:
|
||||
ESP_LOGE(TAG, "Received invalid security parameters for establishing secure session!");
|
||||
break;
|
||||
case PROTOCOMM_SECURITY_SESSION_CREDENTIALS_MISMATCH:
|
||||
ESP_LOGE(TAG, "Received incorrect username and/or PoP for establishing secure session!");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void wifi_init_sta(void)
|
||||
{
|
||||
/* Start Wi-Fi in station mode */
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
}
|
||||
|
||||
static void get_device_service_name(char *service_name, size_t max)
|
||||
{
|
||||
uint8_t eth_mac[6];
|
||||
const char *ssid_prefix = "PROV_";
|
||||
esp_wifi_get_mac(WIFI_IF_STA, eth_mac);
|
||||
snprintf(service_name, max, "%s%02X%02X%02X",
|
||||
ssid_prefix, eth_mac[3], eth_mac[4], eth_mac[5]);
|
||||
}
|
||||
|
||||
/* Handler for the optional provisioning endpoint registered by the application.
|
||||
* The data format can be chosen by applications. Here, we are using plain ascii text.
|
||||
* Applications can choose to use other formats like protobuf, JSON, XML, etc.
|
||||
* Note that memory for the response buffer must be allocated using heap as this buffer
|
||||
* gets freed by the protocomm layer once it has been sent by the transport layer.
|
||||
*/
|
||||
esp_err_t custom_prov_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,
|
||||
uint8_t **outbuf, ssize_t *outlen, void *priv_data)
|
||||
{
|
||||
if (inbuf) {
|
||||
ESP_LOGI(TAG, "Received data: %.*s", inlen, (char *)inbuf);
|
||||
}
|
||||
char response[] = "SUCCESS";
|
||||
*outbuf = (uint8_t *)strdup(response);
|
||||
if (*outbuf == NULL) {
|
||||
ESP_LOGE(TAG, "System out of memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
*outlen = strlen(response) + 1; /* +1 for NULL terminating byte */
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void wifi_prov_print_qr(const char *name, const char *username, const char *pop, const char *transport)
|
||||
{
|
||||
if (!name || !transport) {
|
||||
ESP_LOGW(TAG, "Cannot generate QR code payload. Data missing.");
|
||||
return;
|
||||
}
|
||||
char payload[150] = {0};
|
||||
if (pop) {
|
||||
#if CONFIG_EXAMPLE_PROV_SECURITY_VERSION_1
|
||||
snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
|
||||
",\"pop\":\"%s\",\"transport\":\"%s\"}",
|
||||
PROV_QR_VERSION, name, pop, transport);
|
||||
#elif CONFIG_EXAMPLE_PROV_SECURITY_VERSION_2
|
||||
snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
|
||||
",\"username\":\"%s\",\"pop\":\"%s\",\"transport\":\"%s\"}",
|
||||
PROV_QR_VERSION, name, username, pop, transport);
|
||||
#endif
|
||||
} else {
|
||||
snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
|
||||
",\"transport\":\"%s\",\"network\":\"wifi\"}",
|
||||
PROV_QR_VERSION, name, transport);
|
||||
}
|
||||
//TODO: Add the network protocol type to the QR code payload
|
||||
#ifdef CONFIG_EXAMPLE_PROV_SHOW_QR
|
||||
ESP_LOGI(TAG, "Scan this QR code from the provisioning application for Provisioning.");
|
||||
esp_qrcode_config_t cfg = ESP_QRCODE_CONFIG_DEFAULT();
|
||||
esp_qrcode_generate(&cfg, payload);
|
||||
#endif /* CONFIG_EXAMPLE_PROV_SHOW_QR */
|
||||
ESP_LOGI(TAG, "If QR code is not visible, copy paste the below URL in a browser.\n%s?data=%s", QRCODE_BASE_URL, payload);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_PROV_ENABLE_APP_CALLBACK
|
||||
void wifi_prov_app_callback(void *user_data, wifi_prov_cb_event_t event, void *event_data)
|
||||
{
|
||||
/**
|
||||
* This is blocking callback, any configurations that needs to be set when a particular
|
||||
* provisioning event is triggered can be set here.
|
||||
*/
|
||||
switch (event) {
|
||||
case WIFI_PROV_SET_STA_CONFIG: {
|
||||
/**
|
||||
* Wi-Fi configurations can be set here before the Wi-Fi is enabled in
|
||||
* STA mode.
|
||||
*/
|
||||
wifi_config_t *wifi_config = (wifi_config_t *)event_data;
|
||||
(void) wifi_config;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const wifi_prov_event_handler_t wifi_prov_event_handler = {
|
||||
.event_cb = wifi_prov_app_callback,
|
||||
.user_data = NULL,
|
||||
};
|
||||
#endif /* EXAMPLE_PROV_ENABLE_APP_CALLBACK */
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/* Initialize NVS partition */
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
/* NVS partition was truncated
|
||||
* and needs to be erased */
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
|
||||
/* Retry nvs_flash_init */
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
}
|
||||
|
||||
/* Initialize TCP/IP */
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
|
||||
/* Initialize the event loop */
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
wifi_event_group = xEventGroupCreate();
|
||||
|
||||
/* Register our event handler for Wi-Fi, IP and Provisioning related events */
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(NETWORK_PROV_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(PROTOCOMM_TRANSPORT_BLE_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
|
||||
#endif
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(PROTOCOMM_SECURITY_SESSION_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));
|
||||
|
||||
/* Initialize Wi-Fi including netif with default config */
|
||||
esp_netif_create_default_wifi_sta();
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP
|
||||
esp_netif_create_default_wifi_ap();
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP */
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
/* Configuration for the provisioning manager */
|
||||
network_prov_mgr_config_t config = {
|
||||
#ifdef CONFIG_EXAMPLE_RESET_PROV_MGR_ON_FAILURE
|
||||
.network_prov_wifi_conn_cfg = {
|
||||
.wifi_conn_attempts = CONFIG_EXAMPLE_PROV_MGR_CONNECTION_CNT,
|
||||
},
|
||||
#endif
|
||||
/* What is the Provisioning Scheme that we want ?
|
||||
* network_prov_scheme_softap or network_prov_scheme_ble */
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE
|
||||
.scheme = network_prov_scheme_ble,
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_BLE */
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP
|
||||
.scheme = network_prov_scheme_softap,
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP */
|
||||
#ifdef CONFIG_EXAMPLE_PROV_ENABLE_APP_CALLBACK
|
||||
.app_event_handler = wifi_prov_event_handler,
|
||||
#endif /* EXAMPLE_PROV_ENABLE_APP_CALLBACK */
|
||||
|
||||
/* Any default scheme specific event handler that you would
|
||||
* like to choose. Since our example application requires
|
||||
* neither BT nor BLE, we can choose to release the associated
|
||||
* memory once provisioning is complete, or not needed
|
||||
* (in case when device is already provisioned). Choosing
|
||||
* appropriate scheme specific event handler allows the manager
|
||||
* to take care of this automatically. This can be set to
|
||||
* NETWORK_PROV_EVENT_HANDLER_NONE when using network_prov_scheme_softap*/
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE
|
||||
.scheme_event_handler = NETWORK_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_BLE */
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP
|
||||
.scheme_event_handler = NETWORK_PROV_EVENT_HANDLER_NONE
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP */
|
||||
};
|
||||
|
||||
/* Initialize provisioning manager with the
|
||||
* configuration parameters set above */
|
||||
ESP_ERROR_CHECK(network_prov_mgr_init(config));
|
||||
|
||||
bool provisioned = false;
|
||||
#ifdef CONFIG_EXAMPLE_RESET_PROVISIONED
|
||||
network_prov_mgr_reset_wifi_provisioning();
|
||||
#else
|
||||
/* Let's find out if the device is provisioned */
|
||||
ESP_ERROR_CHECK(network_prov_mgr_is_wifi_provisioned(&provisioned));
|
||||
|
||||
#endif
|
||||
/* If device is not yet provisioned start provisioning service */
|
||||
if (!provisioned) {
|
||||
ESP_LOGI(TAG, "Starting provisioning");
|
||||
|
||||
/* What is the Device Service Name that we want
|
||||
* This translates to :
|
||||
* - Wi-Fi SSID when scheme is network_prov_scheme_softap
|
||||
* - device name when scheme is network_prov_scheme_ble
|
||||
*/
|
||||
char service_name[12];
|
||||
get_device_service_name(service_name, sizeof(service_name));
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_PROV_SECURITY_VERSION_1
|
||||
/* What is the security level that we want (0, 1, 2):
|
||||
* - NETWORK_PROV_SECURITY_0 is simply plain text communication.
|
||||
* - NETWORK_PROV_SECURITY_1 is secure communication which consists of secure handshake
|
||||
* using X25519 key exchange and proof of possession (pop) and AES-CTR
|
||||
* for encryption/decryption of messages.
|
||||
* - NETWORK_PROV_SECURITY_2 SRP6a based authentication and key exchange
|
||||
* + AES-GCM encryption/decryption of messages
|
||||
*/
|
||||
network_prov_security_t security = NETWORK_PROV_SECURITY_1;
|
||||
|
||||
/* Do we want a proof-of-possession (ignored if Security 0 is selected):
|
||||
* - this should be a string with length > 0
|
||||
* - NULL if not used
|
||||
*/
|
||||
const char *pop = "abcd1234";
|
||||
|
||||
/* This is the structure for passing security parameters
|
||||
* for the protocomm security 1.
|
||||
*/
|
||||
network_prov_security1_params_t *sec_params = pop;
|
||||
|
||||
const char *username = NULL;
|
||||
|
||||
#elif CONFIG_EXAMPLE_PROV_SECURITY_VERSION_2
|
||||
network_prov_security_t security = NETWORK_PROV_SECURITY_2;
|
||||
/* The username must be the same one, which has been used in the generation of salt and verifier */
|
||||
|
||||
#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE
|
||||
/* This pop field represents the password that will be used to generate salt and verifier.
|
||||
* The field is present here in order to generate the QR code containing password.
|
||||
* In production this password field shall not be stored on the device */
|
||||
const char *username = EXAMPLE_PROV_SEC2_USERNAME;
|
||||
const char *pop = EXAMPLE_PROV_SEC2_PWD;
|
||||
#elif CONFIG_EXAMPLE_PROV_SEC2_PROD_MODE
|
||||
/* The username and password shall not be embedded in the firmware,
|
||||
* they should be provided to the user by other means.
|
||||
* e.g. QR code sticker */
|
||||
const char *username = NULL;
|
||||
const char *pop = NULL;
|
||||
#endif
|
||||
/* This is the structure for passing security parameters
|
||||
* for the protocomm security 2.
|
||||
* If dynamically allocated, sec2_params pointer and its content
|
||||
* must be valid till NETWORK_PROV_END event is triggered.
|
||||
*/
|
||||
network_prov_security2_params_t sec2_params = {};
|
||||
|
||||
ESP_ERROR_CHECK(example_get_sec2_salt(&sec2_params.salt, &sec2_params.salt_len));
|
||||
ESP_ERROR_CHECK(example_get_sec2_verifier(&sec2_params.verifier, &sec2_params.verifier_len));
|
||||
|
||||
network_prov_security2_params_t *sec_params = &sec2_params;
|
||||
#endif
|
||||
/* What is the service key (could be NULL)
|
||||
* This translates to :
|
||||
* - Wi-Fi password when scheme is network_prov_scheme_softap
|
||||
* (Minimum expected length: 8, maximum 64 for WPA2-PSK)
|
||||
* - simply ignored when scheme is network_prov_scheme_ble
|
||||
*/
|
||||
const char *service_key = NULL;
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE
|
||||
/* This step is only useful when scheme is network_prov_scheme_ble. This will
|
||||
* set a custom 128 bit UUID which will be included in the BLE advertisement
|
||||
* and will correspond to the primary GATT service that provides provisioning
|
||||
* endpoints as GATT characteristics. Each GATT characteristic will be
|
||||
* formed using the primary service UUID as base, with different auto assigned
|
||||
* 12th and 13th bytes (assume counting starts from 0th byte). The client side
|
||||
* applications must identify the endpoints by reading the User Characteristic
|
||||
* Description descriptor (0x2901) for each characteristic, which contains the
|
||||
* endpoint name of the characteristic */
|
||||
uint8_t custom_service_uuid[] = {
|
||||
/* LSB <---------------------------------------
|
||||
* ---------------------------------------> MSB */
|
||||
0xb4, 0xdf, 0x5a, 0x1c, 0x3f, 0x6b, 0xf4, 0xbf,
|
||||
0xea, 0x4a, 0x82, 0x03, 0x04, 0x90, 0x1a, 0x02,
|
||||
};
|
||||
|
||||
/* If your build fails with linker errors at this point, then you may have
|
||||
* forgotten to enable the BT stack or BTDM BLE settings in the SDK (e.g. see
|
||||
* the sdkconfig.defaults in the example project) */
|
||||
network_prov_scheme_ble_set_service_uuid(custom_service_uuid);
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_BLE */
|
||||
|
||||
/* An optional endpoint that applications can create if they expect to
|
||||
* get some additional custom data during provisioning workflow.
|
||||
* The endpoint name can be anything of your choice.
|
||||
* This call must be made before starting the provisioning.
|
||||
*/
|
||||
network_prov_mgr_endpoint_create("custom-data");
|
||||
|
||||
/* Do not stop and de-init provisioning even after success,
|
||||
* so that we can restart it later. */
|
||||
#ifdef CONFIG_EXAMPLE_REPROVISIONING
|
||||
network_prov_mgr_disable_auto_stop(1000);
|
||||
#endif
|
||||
/* Start provisioning service */
|
||||
ESP_ERROR_CHECK(network_prov_mgr_start_provisioning(security, (const void *) sec_params, service_name, service_key));
|
||||
|
||||
/* The handler for the optional endpoint created above.
|
||||
* This call must be made after starting the provisioning, and only if the endpoint
|
||||
* has already been created above.
|
||||
*/
|
||||
network_prov_mgr_endpoint_register("custom-data", custom_prov_data_handler, NULL);
|
||||
|
||||
/* Uncomment the following to wait for the provisioning to finish and then release
|
||||
* the resources of the manager. Since in this case de-initialization is triggered
|
||||
* by the default event loop handler, we don't need to call the following */
|
||||
// network_prov_mgr_wait();
|
||||
// network_prov_mgr_deinit();
|
||||
/* Print QR code for provisioning */
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE
|
||||
wifi_prov_print_qr(service_name, username, pop, PROV_TRANSPORT_BLE);
|
||||
#else /* CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP */
|
||||
wifi_prov_print_qr(service_name, username, pop, PROV_TRANSPORT_SOFTAP);
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_BLE */
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Already provisioned, starting Wi-Fi STA");
|
||||
|
||||
/* We don't need the manager as device is already provisioned,
|
||||
* so let's release it's resources */
|
||||
ESP_ERROR_CHECK(network_prov_mgr_deinit());
|
||||
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
|
||||
/* Start Wi-Fi station */
|
||||
wifi_init_sta();
|
||||
}
|
||||
|
||||
/* Wait for Wi-Fi connection */
|
||||
xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_EVENT, true, true, portMAX_DELAY);
|
||||
|
||||
/* Start main application now */
|
||||
#if CONFIG_EXAMPLE_REPROVISIONING
|
||||
while (1) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ESP_LOGI(TAG, "Hello World!");
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
/* Resetting provisioning state machine to enable re-provisioning */
|
||||
network_prov_mgr_reset_wifi_sm_state_for_reprovision();
|
||||
|
||||
/* Wait for Wi-Fi connection */
|
||||
xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_EVENT, true, true, portMAX_DELAY);
|
||||
}
|
||||
#else
|
||||
while (1) {
|
||||
ESP_LOGI(TAG, "Hello World!");
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
dependencies:
|
||||
espressif/network_provisioning:
|
||||
version: '*'
|
||||
espressif/qrcode:
|
||||
version: ^0.1.0
|
||||
version: 1.0.0
|
||||
@@ -0,0 +1,5 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||
nvs, data, nvs, , 0x6000,
|
||||
phy_init, data, phy, , 0x1000,
|
||||
factory, app, factory, , 0x180000,
|
||||
|
@@ -0,0 +1,8 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
|
||||
## For Bluedroid as binary is larger than default size
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
@@ -0,0 +1,5 @@
|
||||
# ESP32 specific default configurations
|
||||
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
@@ -0,0 +1,13 @@
|
||||
dependencies:
|
||||
espressif/cjson:
|
||||
rules:
|
||||
- if: idf_version >= 6.0
|
||||
version: ^1.7.19
|
||||
idf: '>=5.1'
|
||||
description: Network provisioning component for Wi-Fi or Thread devices
|
||||
repository: git://github.com/espressif/idf-extra-components.git
|
||||
repository_info:
|
||||
commit_sha: 2de4980640bbe3d2d69473d7251640039e185b92
|
||||
path: network_provisioning
|
||||
url: https://github.com/espressif/idf-extra-components/tree/master/network_provisioning
|
||||
version: 1.2.4
|
||||
@@ -0,0 +1,792 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <protocomm.h>
|
||||
|
||||
#include "esp_event.h"
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
#include "esp_wifi_types.h"
|
||||
#endif
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
#include "openthread/dataset.h"
|
||||
#endif
|
||||
#include "network_provisioning/network_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
ESP_EVENT_DECLARE_BASE(NETWORK_PROV_EVENT);
|
||||
|
||||
/**
|
||||
* @brief Events generated by manager
|
||||
*
|
||||
* These events are generated in order of declaration and, for the
|
||||
* stretch of time between initialization and de-initialization of
|
||||
* the manager, each event is signaled only once
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* Emitted when the manager is initialized
|
||||
*/
|
||||
NETWORK_PROV_INIT,
|
||||
|
||||
/**
|
||||
* Indicates that provisioning has started
|
||||
*/
|
||||
NETWORK_PROV_START,
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
/**
|
||||
* Emitted before accepting the wifi credentials to
|
||||
* set the wifi configurations according to requirement.
|
||||
* NOTE - In this case event_data shall be populated with a pointer to `wifi_config_t`.
|
||||
*/
|
||||
NETWORK_PROV_SET_WIFI_STA_CONFIG,
|
||||
|
||||
/**
|
||||
* Emitted when Wi-Fi AP credentials are received via `protocomm`
|
||||
* endpoint `network_config`. The event data in this case is a pointer
|
||||
* to the corresponding `wifi_sta_config_t` structure
|
||||
*/
|
||||
NETWORK_PROV_WIFI_CRED_RECV,
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
/**
|
||||
* Emitted when Thread Dataset is received via `protocomm` endpoint
|
||||
* `network_config`, The event data in this case is a pointer to the
|
||||
* corresponding `otOperationalDatasetTlvs` structure
|
||||
*/
|
||||
NETWORK_PROV_THREAD_DATASET_RECV,
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
/**
|
||||
* Emitted when device fails to connect to the AP of which the
|
||||
* credentials were received earlier on event `NETWORK_PROV_WIFI_CRED_RECV`.
|
||||
* The event data in this case is a pointer to the disconnection
|
||||
* reason code with type `network_prov_wifi_sta_fail_reason_t`
|
||||
*/
|
||||
NETWORK_PROV_WIFI_CRED_FAIL,
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
/**
|
||||
* Emitted when device fails to connect to the Thread network of which
|
||||
* dataset was received earlier on event `NETWORK_PROv_THREAD_DATASET_RECV`.
|
||||
* The event data in this case is a pointer to the disconnection
|
||||
* reason code with type `network_prov_thread_fail_reason_t`
|
||||
*/
|
||||
NETWORK_PROV_THREAD_DATASET_FAIL,
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
/**
|
||||
* Emitted when device successfully connects to the AP of which the
|
||||
* credentials were received earlier on event `NETWORK_PROV_WIFI_CRED_RECV`
|
||||
*/
|
||||
NETWORK_PROV_WIFI_CRED_SUCCESS,
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
/**
|
||||
* Emitted when device successfully connects to the Thread etwork of
|
||||
* which the dataset was received earlier on event
|
||||
* `NETWORK_PROV_THREAD_DATASET_RECV`
|
||||
*/
|
||||
NETWORK_PROV_THREAD_DATASET_SUCCESS,
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
|
||||
/**
|
||||
* Signals that provisioning service has stopped
|
||||
*/
|
||||
NETWORK_PROV_END,
|
||||
|
||||
/**
|
||||
* Signals that manager has been de-initialized
|
||||
*/
|
||||
NETWORK_PROV_DEINIT,
|
||||
} network_prov_cb_event_t;
|
||||
|
||||
typedef void (*network_prov_cb_func_t)(void *user_data, network_prov_cb_event_t event, void *event_data);
|
||||
|
||||
/**
|
||||
* @brief Event handler that is used by the manager while
|
||||
* provisioning service is active
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* Callback function to be executed on provisioning events
|
||||
*/
|
||||
network_prov_cb_func_t event_cb;
|
||||
|
||||
/**
|
||||
* User context data to pass as parameter to callback function
|
||||
*/
|
||||
void *user_data;
|
||||
} network_prov_event_handler_t;
|
||||
|
||||
/**
|
||||
* @brief Structure holding the configuration related to Wi-Fi provisioning
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* Maximum number of allowed connection attempts for Wi-Fi. If value 0
|
||||
* same as legacy behavior of infinite connection attempts.
|
||||
*/
|
||||
uint32_t wifi_conn_attempts;
|
||||
} network_prov_wifi_conn_cfg_t;
|
||||
|
||||
/**
|
||||
* @brief Event handler can be set to none if not used
|
||||
*/
|
||||
#define NETWORK_PROV_EVENT_HANDLER_NONE { \
|
||||
.event_cb = NULL, \
|
||||
.user_data = NULL \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Structure for specifying the provisioning scheme to be
|
||||
* followed by the manager
|
||||
*
|
||||
* @note Ready to use schemes are available:
|
||||
* - network_prov_scheme_ble : for provisioning over BLE transport + GATT server
|
||||
* - network_prov_scheme_softap : for provisioning over SoftAP transport + HTTP server
|
||||
* - network_prov_scheme_console : for provisioning over Serial UART transport + Console (for debugging)
|
||||
*/
|
||||
typedef struct network_prov_scheme {
|
||||
/**
|
||||
* Function which is to be called by the manager when it is to
|
||||
* start the provisioning service associated with a protocomm instance
|
||||
* and a scheme specific configuration
|
||||
*/
|
||||
esp_err_t (*prov_start) (protocomm_t *pc, void *config);
|
||||
|
||||
/**
|
||||
* Function which is to be called by the manager to stop the
|
||||
* provisioning service previously associated with a protocomm instance
|
||||
*/
|
||||
esp_err_t (*prov_stop) (protocomm_t *pc);
|
||||
|
||||
/**
|
||||
* Function which is to be called by the manager to generate
|
||||
* a new configuration for the provisioning service, that is
|
||||
* to be passed to prov_start()
|
||||
*/
|
||||
void *(*new_config) (void);
|
||||
|
||||
/**
|
||||
* Function which is to be called by the manager to delete a
|
||||
* configuration generated using new_config()
|
||||
*/
|
||||
void (*delete_config) (void *config);
|
||||
|
||||
/**
|
||||
* Function which is to be called by the manager to set the
|
||||
* service name and key values in the configuration structure
|
||||
*/
|
||||
esp_err_t (*set_config_service) (void *config, const char *service_name, const char *service_key);
|
||||
|
||||
/**
|
||||
* Function which is to be called by the manager to set a protocomm endpoint
|
||||
* with an identifying name and UUID in the configuration structure
|
||||
*/
|
||||
esp_err_t (*set_config_endpoint) (void *config, const char *endpoint_name, uint16_t uuid);
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
/**
|
||||
* Sets mode of operation of Wi-Fi during provisioning
|
||||
* This is set to :
|
||||
* - WIFI_MODE_APSTA for SoftAP transport
|
||||
* - WIFI_MODE_STA for BLE transport
|
||||
*/
|
||||
wifi_mode_t wifi_mode;
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
} network_prov_scheme_t;
|
||||
|
||||
/**
|
||||
* @brief Structure for specifying the manager configuration
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* Provisioning scheme to use. Following schemes are already available:
|
||||
* - network_prov_scheme_ble : for provisioning over BLE transport + GATT server
|
||||
* - network_prov_scheme_softap : for provisioning over SoftAP transport + HTTP server + mDNS (optional)
|
||||
* - network_prov_scheme_console : for provisioning over Serial UART transport + Console (for debugging)
|
||||
*/
|
||||
network_prov_scheme_t scheme;
|
||||
|
||||
/**
|
||||
* Event handler required by the scheme for incorporating scheme specific
|
||||
* behavior while provisioning manager is running. Various options may be
|
||||
* provided by the scheme for setting this field. Use NETWORK_PROV_EVENT_HANDLER_NONE
|
||||
* when not used. When using scheme network_prov_scheme_ble, the following
|
||||
* options are available:
|
||||
* - NETWORK_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM
|
||||
* - NETWORK_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BLE
|
||||
* - NETWORK_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BT
|
||||
*/
|
||||
network_prov_event_handler_t scheme_event_handler;
|
||||
|
||||
/**
|
||||
* Event handler that can be set for the purpose of incorporating application
|
||||
* specific behavior. Use NETWORK_PROV_EVENT_HANDLER_NONE when not used.
|
||||
*/
|
||||
network_prov_event_handler_t app_event_handler;
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
/**
|
||||
* This config holds the Wi-Fi provisioning related configurations.
|
||||
*/
|
||||
network_prov_wifi_conn_cfg_t network_prov_wifi_conn_cfg;
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
} network_prov_mgr_config_t;
|
||||
|
||||
/**
|
||||
* @brief Security modes supported by the Provisioning Manager.
|
||||
*
|
||||
* These are same as the security modes provided by protocomm
|
||||
*/
|
||||
typedef enum network_prov_security {
|
||||
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0
|
||||
/**
|
||||
* No security (plain-text communication)
|
||||
*/
|
||||
NETWORK_PROV_SECURITY_0 = 0,
|
||||
#endif
|
||||
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1
|
||||
/**
|
||||
* This secure communication mode consists of
|
||||
* X25519 key exchange
|
||||
* + proof of possession (pop) based authentication
|
||||
* + AES-CTR encryption
|
||||
*/
|
||||
NETWORK_PROV_SECURITY_1 = 1,
|
||||
#endif
|
||||
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2
|
||||
/**
|
||||
* This secure communication mode consists of
|
||||
* SRP6a based authentication and key exchange
|
||||
* + AES-GCM encryption/decryption
|
||||
*/
|
||||
NETWORK_PROV_SECURITY_2 = 2
|
||||
#endif
|
||||
#if !CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0 && !CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1 && !CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2
|
||||
#error "All of the protocomm security versions are disabled. Make sure to enable at least one security version."
|
||||
#endif
|
||||
} network_prov_security_t;
|
||||
|
||||
/**
|
||||
* @brief Security 1 params structure
|
||||
* This needs to be passed when using NETWORK_PROV_SECURITY_1
|
||||
*/
|
||||
typedef const char network_prov_security1_params_t;
|
||||
|
||||
/**
|
||||
* @brief Security 2 params structure
|
||||
* This needs to be passed when using NETWORK_PROV_SECURITY_2
|
||||
*/
|
||||
typedef protocomm_security2_params_t network_prov_security2_params_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize provisioning manager instance
|
||||
*
|
||||
* Configures the manager and allocates internal resources
|
||||
*
|
||||
* Configuration specifies the provisioning scheme (transport)
|
||||
* and event handlers
|
||||
*
|
||||
* Event NETWORK_PROV_INIT is emitted right after initialization
|
||||
* is complete
|
||||
*
|
||||
* @param[in] config Configuration structure
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Success
|
||||
* - ESP_FAIL : Fail
|
||||
*/
|
||||
esp_err_t network_prov_mgr_init(network_prov_mgr_config_t config);
|
||||
|
||||
/**
|
||||
* @brief Stop provisioning (if running) and release
|
||||
* resource used by the manager
|
||||
*
|
||||
* Event NETWORK_PROV_DEINIT is emitted right after de-initialization
|
||||
* is finished
|
||||
*
|
||||
* If provisioning service is still active when this API is called,
|
||||
* it first stops the service, hence emitting NETWORK_PROV_END, and
|
||||
* then performs the de-initialization
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Success
|
||||
* - ESP_FAIL : Failed to post event NETWORK_PROV_DEINIT or NETWORK_PROV_END
|
||||
* - ESP_ERR_NO_MEM : Out of memory (as may be returned by esp_event_post)
|
||||
*/
|
||||
esp_err_t network_prov_mgr_deinit(void);
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
/**
|
||||
* @brief Checks if device is provisioned
|
||||
*
|
||||
* This checks if Wi-Fi credentials are present on the NVS
|
||||
*
|
||||
* The Wi-Fi credentials are assumed to be kept in the same
|
||||
* NVS namespace as used by esp_wifi component
|
||||
*
|
||||
* If one were to call esp_wifi_set_config() directly instead
|
||||
* of going through the provisioning process, this function will
|
||||
* still yield true (i.e. device will be found to be provisioned)
|
||||
*
|
||||
* @note Calling network_prov_mgr_start_provisioning() automatically
|
||||
* resets the provision state, irrespective of what the
|
||||
* state was prior to making the call.
|
||||
*
|
||||
* @param[out] provisioned True if provisioned, else false
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Retrieved provision state successfully
|
||||
* - ESP_FAIL : Wi-Fi not initialized
|
||||
* - ESP_ERR_INVALID_ARG : Null argument supplied
|
||||
*/
|
||||
esp_err_t network_prov_mgr_is_wifi_provisioned(bool *provisioned);
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
/**
|
||||
* @brief Checks if device is provisioned
|
||||
*
|
||||
* This checks if there is active dataset for Thread device
|
||||
*
|
||||
* @note Calling network_prov_mgr_start_provisioning() automatically
|
||||
* resets the provision state, irrespective of what the
|
||||
* state was prior to making the call.
|
||||
*
|
||||
* @param[out] provisioned True if provisioned, else false
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Retrieved provision state successfully
|
||||
* - ESP_FAIL : Not initialized
|
||||
* - ESP_ERR_INVALID_ARG : Null argument supplied
|
||||
*/
|
||||
esp_err_t network_prov_mgr_is_thread_provisioned(bool *provisioned);
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
|
||||
/**
|
||||
* @brief Checks whether the provisioning state machine is idle
|
||||
*
|
||||
* @return True if state machine is idle, else false
|
||||
*/
|
||||
bool network_prov_mgr_is_sm_idle(void);
|
||||
|
||||
/**
|
||||
* @brief Start provisioning service
|
||||
*
|
||||
* This starts the provisioning service according to the scheme
|
||||
* configured at the time of initialization. For scheme :
|
||||
* - network_prov_scheme_ble : This starts protocomm_ble, which internally initializes
|
||||
* BLE transport and starts GATT server for handling
|
||||
* provisioning requests
|
||||
* - network_prov_scheme_softap : This activates SoftAP mode of Wi-Fi and starts
|
||||
* protocomm_httpd, which internally starts an HTTP
|
||||
* server for handling provisioning requests (If mDNS is
|
||||
* active it also starts advertising service with type
|
||||
* _esp_wifi_prov._tcp)
|
||||
*
|
||||
* Event NETWORK_PROV_START is emitted right after provisioning starts without failure
|
||||
*
|
||||
* @note This API will start provisioning service even if device is found to be
|
||||
* already provisioned, i.e. network_prov_mgr_is_wifi_provisioned() yields true
|
||||
*
|
||||
* @param[in] security Specify which protocomm security scheme to use :
|
||||
* - NETWORK_PROV_SECURITY_0 : For no security
|
||||
* - NETWORK_PROV_SECURITY_1 : x25519 secure handshake for session
|
||||
* establishment followed by AES-CTR encryption of provisioning messages
|
||||
* - NETWORK_PROV_SECURITY_2: SRP6a based authentication and key exchange
|
||||
* followed by AES-GCM encryption/decryption of provisioning messages
|
||||
* @param[in] network_prov_sec_params
|
||||
* Pointer to security params (NULL if not needed).
|
||||
* This is not needed for protocomm security 0
|
||||
* This pointer should hold the struct of type
|
||||
* network_prov_security1_params_t for protocomm security 1
|
||||
* and network_prov_security2_params_t for protocomm security 2 respectively.
|
||||
* This pointer and its contents should be valid till the provisioning service is
|
||||
* running and has not been stopped or de-inited.
|
||||
* @param[in] service_name Unique name of the service. This translates to:
|
||||
* - Wi-Fi SSID when provisioning mode is softAP
|
||||
* - Device name when provisioning mode is BLE
|
||||
* @param[in] service_key Key required by client to access the service (NULL if not needed).
|
||||
* This translates to:
|
||||
* - Wi-Fi password when provisioning mode is softAP
|
||||
* - ignored when provisioning mode is BLE
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Provisioning started successfully
|
||||
* - ESP_FAIL : Failed to start provisioning service
|
||||
* - ESP_ERR_INVALID_STATE : Provisioning manager not initialized or already started
|
||||
*/
|
||||
esp_err_t network_prov_mgr_start_provisioning(network_prov_security_t security, const void *network_prov_sec_params, const char *service_name, const char *service_key);
|
||||
|
||||
/**
|
||||
* @brief Stop provisioning service
|
||||
*
|
||||
* If provisioning service is active, this API will initiate a process to stop
|
||||
* the service and return. Once the service actually stops, the event NETWORK_PROV_END
|
||||
* will be emitted.
|
||||
*
|
||||
* If network_prov_mgr_deinit() is called without calling this API first, it will
|
||||
* automatically stop the provisioning service and emit the NETWORK_PROV_END, followed
|
||||
* by NETWORK_PROV_DEINIT, before returning.
|
||||
*
|
||||
* This API will generally be used along with network_prov_mgr_disable_auto_stop()
|
||||
* in the scenario when the main application has registered its own endpoints,
|
||||
* and wishes that the provisioning service is stopped only when some protocomm
|
||||
* command from the client side application is received.
|
||||
*
|
||||
* Calling this API inside an endpoint handler, with sufficient cleanup_delay,
|
||||
* will allow the response / acknowledgment to be sent successfully before the
|
||||
* underlying protocomm service is stopped.
|
||||
*
|
||||
* Cleaup_delay is set when calling network_prov_mgr_disable_auto_stop().
|
||||
* If not specified, it defaults to 1000ms.
|
||||
*
|
||||
* For straightforward cases, using this API is usually not necessary as
|
||||
* provisioning is stopped automatically once NETWORK_PROV_CRED_SUCCESS is emitted.
|
||||
* Stopping is delayed (maximum 30 seconds) thus allowing the client side
|
||||
* application to query for network state, i.e. after receiving the first query
|
||||
* and sending `network state connected` response the service is stopped immediately.
|
||||
*/
|
||||
void network_prov_mgr_stop_provisioning(void);
|
||||
|
||||
/**
|
||||
* @brief Wait for provisioning service to finish
|
||||
*
|
||||
* Calling this API will block until provisioning service is stopped
|
||||
* i.e. till event NETWORK_PROV_END is emitted.
|
||||
*
|
||||
* This will not block if provisioning is not started or not initialized.
|
||||
*/
|
||||
void network_prov_mgr_wait(void);
|
||||
|
||||
/**
|
||||
* @brief Disable auto stopping of provisioning service upon completion
|
||||
*
|
||||
* By default, once provisioning is complete, the provisioning service is automatically
|
||||
* stopped, and all endpoints (along with those registered by main application) are
|
||||
* deactivated.
|
||||
*
|
||||
* This API is useful in the case when main application wishes to close provisioning service
|
||||
* only after it receives some protocomm command from the client side app. For example, after
|
||||
* connecting to network, the device may want to connect to the cloud, and only once that is
|
||||
* successfully, the device is said to be fully configured. But, then it is upto the main
|
||||
* application to explicitly call network_prov_mgr_stop_provisioning() later when the device is
|
||||
* fully configured and the provisioning service is no longer required.
|
||||
*
|
||||
* @note This must be called before executing network_prov_mgr_start_provisioning()
|
||||
*
|
||||
* @param[in] cleanup_delay Sets the delay after which the actual cleanup of transport related
|
||||
* resources is done after a call to network_prov_mgr_stop_provisioning()
|
||||
* returns. Minimum allowed value is 100ms. If not specified, this will
|
||||
* default to 1000ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Success
|
||||
* - ESP_ERR_INVALID_STATE : Manager not initialized or
|
||||
* provisioning service already started
|
||||
*/
|
||||
esp_err_t network_prov_mgr_disable_auto_stop(uint32_t cleanup_delay);
|
||||
|
||||
/**
|
||||
* @brief Set application version and capabilities in the JSON data returned by
|
||||
* proto-ver endpoint
|
||||
*
|
||||
* This function can be called multiple times, to specify information about the various
|
||||
* application specific services running on the device, identified by unique labels.
|
||||
*
|
||||
* The provisioning service itself registers an entry in the JSON data, by the label "prov",
|
||||
* containing only provisioning service version and capabilities. Application services should
|
||||
* use a label other than "prov" so as not to overwrite this.
|
||||
*
|
||||
* @note This must be called before executing network_prov_mgr_start_provisioning()
|
||||
*
|
||||
* @param[in] label String indicating the application name.
|
||||
*
|
||||
* @param[in] version String indicating the application version.
|
||||
* There is no constraint on format.
|
||||
*
|
||||
* @param[in] capabilities Array of strings with capabilities.
|
||||
* These could be used by the client side app to know
|
||||
* the application registered endpoint capabilities
|
||||
*
|
||||
* @param[in] total_capabilities Size of capabilities array
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Success
|
||||
* - ESP_ERR_INVALID_STATE : Manager not initialized or
|
||||
* provisioning service already started
|
||||
* - ESP_ERR_NO_MEM : Failed to allocate memory for version string
|
||||
* - ESP_ERR_INVALID_ARG : Null argument
|
||||
*/
|
||||
esp_err_t network_prov_mgr_set_app_info(const char *label, const char *version,
|
||||
const char **capabilities, size_t total_capabilities);
|
||||
|
||||
/**
|
||||
* @brief Create an additional endpoint and allocate internal resources for it
|
||||
*
|
||||
* This API is to be called by the application if it wants to create an additional
|
||||
* endpoint. All additional endpoints will be assigned UUIDs starting from 0xFF54
|
||||
* and so on in the order of execution.
|
||||
*
|
||||
* protocomm handler for the created endpoint is to be registered later using
|
||||
* network_prov_mgr_endpoint_register() after provisioning has started.
|
||||
*
|
||||
* @note This API can only be called BEFORE provisioning is started
|
||||
*
|
||||
* @note Additional endpoints can be used for configuring client provided
|
||||
* parameters other than Wi-Fi credentials or Thread dataset, that are necessary
|
||||
* for the main application and hence must be set prior to starting the application
|
||||
*
|
||||
* @note After session establishment, the additional endpoints must be targeted
|
||||
* first by the client side application before sending Wi-Fi/Thread configuration,
|
||||
* because once Wi-Fi/Thread configuration finishes the provisioning service is
|
||||
* stopped and hence all endpoints are unregistered
|
||||
*
|
||||
* @param[in] ep_name unique name of the endpoint
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Success
|
||||
* - ESP_FAIL : Failure
|
||||
*/
|
||||
esp_err_t network_prov_mgr_endpoint_create(const char *ep_name);
|
||||
|
||||
/**
|
||||
* @brief Register a handler for the previously created endpoint
|
||||
*
|
||||
* This API can be called by the application to register a protocomm handler
|
||||
* to any endpoint that was created using network_prov_mgr_endpoint_create().
|
||||
*
|
||||
* @note This API can only be called AFTER provisioning has started
|
||||
*
|
||||
* @note Additional endpoints can be used for configuring client provided
|
||||
* parameters other than Wi-Fi credentials or Thread dataset, that are necessary
|
||||
* for the main application and hence must be set prior to starting the application
|
||||
*
|
||||
* @note After session establishment, the additional endpoints must be targeted
|
||||
* first by the client side application before sending Wi-Fi/Thread configuration,
|
||||
* because once Wi-Fi/Thread configuration finishes the provisioning service is
|
||||
* stopped and hence all endpoints are unregistered
|
||||
*
|
||||
* @param[in] ep_name Name of the endpoint
|
||||
* @param[in] handler Endpoint handler function
|
||||
* @param[in] user_ctx User data
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Success
|
||||
* - ESP_FAIL : Failure
|
||||
*/
|
||||
esp_err_t network_prov_mgr_endpoint_register(const char *ep_name,
|
||||
protocomm_req_handler_t handler,
|
||||
void *user_ctx);
|
||||
|
||||
/**
|
||||
* @brief Unregister the handler for an endpoint
|
||||
*
|
||||
* This API can be called if the application wants to selectively
|
||||
* unregister the handler of an endpoint while the provisioning
|
||||
* is still in progress.
|
||||
*
|
||||
* All the endpoint handlers are unregistered automatically when
|
||||
* the provisioning stops.
|
||||
*
|
||||
* @param[in] ep_name Name of the endpoint
|
||||
*/
|
||||
void network_prov_mgr_endpoint_unregister(const char *ep_name);
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
/**
|
||||
* @brief Get state of Wi-Fi Station during provisioning
|
||||
*
|
||||
* @param[out] state Pointer to network_prov_wifi_sta_state_t
|
||||
* variable to be filled
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Successfully retrieved Wi-Fi state
|
||||
* - ESP_FAIL : Provisioning app not running
|
||||
*/
|
||||
esp_err_t network_prov_mgr_get_wifi_state(network_prov_wifi_sta_state_t *state);
|
||||
|
||||
/**
|
||||
* @brief Get reason code in case of Wi-Fi station
|
||||
* disconnection during provisioning
|
||||
*
|
||||
* @param[out] reason Pointer to network_prov_wifi_sta_fail_reason_t
|
||||
* variable to be filled
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Successfully retrieved Wi-Fi disconnect reason
|
||||
* - ESP_FAIL : Provisioning app not running
|
||||
*/
|
||||
esp_err_t network_prov_mgr_get_wifi_disconnect_reason(network_prov_wifi_sta_fail_reason_t *reason);
|
||||
|
||||
/**
|
||||
* @brief Runs Wi-Fi as Station with the supplied configuration
|
||||
*
|
||||
* Configures the Wi-Fi station mode to connect to the AP with
|
||||
* SSID and password specified in config structure and sets
|
||||
* Wi-Fi to run as station.
|
||||
*
|
||||
* This is automatically called by provisioning service upon
|
||||
* receiving new credentials.
|
||||
*
|
||||
* If credentials are to be supplied to the manager via a
|
||||
* different mode other than through protocomm, then this
|
||||
* API needs to be called.
|
||||
*
|
||||
* Event NETWORK_PROV_CRED_RECV is emitted after credentials have
|
||||
* been applied and Wi-Fi station started
|
||||
*
|
||||
* @param[in] wifi_cfg Pointer to Wi-Fi configuration structure
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Wi-Fi configured and started successfully
|
||||
* - ESP_FAIL : Failed to set configuration
|
||||
*/
|
||||
esp_err_t network_prov_mgr_configure_wifi_sta(wifi_config_t *wifi_cfg);
|
||||
|
||||
/**
|
||||
* @brief Reset Wi-Fi provisioning config
|
||||
*
|
||||
* Calling this API will restore WiFi stack persistent settings to default values.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Reset provisioning config successfully
|
||||
* - ESP_FAIL : Failed to reset provisioning config
|
||||
*/
|
||||
esp_err_t network_prov_mgr_reset_wifi_provisioning(void);
|
||||
|
||||
/**
|
||||
* @brief Reset internal state machine and clear provisioned credentials.
|
||||
*
|
||||
* This API should be used to restart provisioning ONLY in the case
|
||||
* of provisioning failures without rebooting the device.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Reset provisioning state machine successfully
|
||||
* - ESP_FAIL : Failed to reset provisioning state machine
|
||||
* - ESP_ERR_INVALID_STATE : Manager not initialized
|
||||
*/
|
||||
esp_err_t network_prov_mgr_reset_wifi_sm_state_on_failure(void);
|
||||
|
||||
/**
|
||||
* @brief Reset internal state machine and clear provisioned credentials.
|
||||
*
|
||||
* This API can be used to restart provisioning ONLY in case the device is
|
||||
* to be provisioned again for new credentials after a previous successful
|
||||
* provisioning without rebooting the device.
|
||||
*
|
||||
* @note This API can be used only if provisioning auto-stop has been
|
||||
* disabled using network_prov_mgr_disable_auto_stop()
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Reset provisioning state machine successfully
|
||||
* - ESP_FAIL : Failed to reset provisioning state machine
|
||||
* - ESP_ERR_INVALID_STATE : Manager not initialized
|
||||
*/
|
||||
esp_err_t network_prov_mgr_reset_wifi_sm_state_for_reprovision(void);
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
/**
|
||||
* @brief Reset Thread provisioning config
|
||||
*
|
||||
* Calling this API will restore Thread stack persistent settings to default values.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Reset provisioning config successfully
|
||||
* - ESP_FAIL : Failed to reset provisioning config
|
||||
*/
|
||||
esp_err_t network_prov_mgr_reset_thread_provisioning(void);
|
||||
|
||||
/**
|
||||
* @brief Get state of Thread during provisioning
|
||||
*
|
||||
* @param[out] state Pointer to network_prov_thread_state_t
|
||||
* variable to be filled
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Successfully retrieved Thread state
|
||||
* - ESP_FAIL : Provisioning app not running
|
||||
*/
|
||||
esp_err_t network_prov_mgr_get_thread_state(network_prov_thread_state_t *state);
|
||||
|
||||
/**
|
||||
* @brief Get reason code in case of thread detached during provisioning
|
||||
*
|
||||
* @param[out] reason Pointer to network_prov_thread_fail_reason_t
|
||||
* variable to be filled
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Successfully retrieved thread detached reason
|
||||
* - ESP_FAIL : Provisioning app not running
|
||||
*/
|
||||
esp_err_t network_prov_mgr_get_thread_detached_reason(network_prov_thread_fail_reason_t *reason);
|
||||
|
||||
/**
|
||||
* @brief Runs Thread with the supplied configuration
|
||||
*
|
||||
* Configures the Thread Dataset so that the device can be attached
|
||||
* to a specific Thread network
|
||||
*
|
||||
* This is automatically called by provisioning service upon
|
||||
* receiving new Thread dataset.
|
||||
*
|
||||
* If the dataset is to be supplied to the manager via a
|
||||
* different mode other than through protocomm, then this
|
||||
* API needs to be called.
|
||||
*
|
||||
* Event THREAD_PROV_CRED_RECV is emitted after credentials have
|
||||
* been applied and Thread started
|
||||
*
|
||||
* @param[in] thread_dataset Pointer to Dataset Tlvs structure
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Thread dataset configured and started successfully
|
||||
* - ESP_FAIL : Failed to set configuration
|
||||
*/
|
||||
esp_err_t network_prov_mgr_configure_thread_dataset(otOperationalDatasetTlvs *thread_dataset);
|
||||
|
||||
/**
|
||||
* @brief Reset internal state machine and clear provisioned credentials.
|
||||
*
|
||||
* This API should be used to restart provisioning ONLY in the case
|
||||
* of provisioning failures without rebooting the device.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Reset provisioning state machine successfully
|
||||
* - ESP_FAIL : Failed to reset provisioning state machine
|
||||
* - ESP_ERR_INVALID_STATE : Manager not initialized
|
||||
*/
|
||||
esp_err_t network_prov_mgr_reset_thread_sm_state_on_failure(void);
|
||||
|
||||
/**
|
||||
* @brief Reset internal state machine and clear provisioned credentials.
|
||||
*
|
||||
* This API can be used to restart provisioning ONLY in case the device is
|
||||
* to be provisioned again for new credentials after a previous successful
|
||||
* provisioning without rebooting the device.
|
||||
*
|
||||
* @note This API can be used only if provisioning auto-stop has been
|
||||
* disabled using network_prov_mgr_disable_auto_stop()
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Reset provisioning state machine successfully
|
||||
* - ESP_FAIL : Failed to reset provisioning state machine
|
||||
* - ESP_ERR_INVALID_STATE : Manager not initialized
|
||||
*/
|
||||
esp_err_t network_prov_mgr_reset_thread_sm_state_for_reprovision(void);
|
||||
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _NETWORK_PROV_CONFIG_H_
|
||||
#define _NETWORK_PROV_CONFIG_H_
|
||||
|
||||
#include "esp_netif_ip_addr.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
/**
|
||||
* @brief WiFi STA status for conveying back to the provisioning master
|
||||
*/
|
||||
typedef enum {
|
||||
NETWORK_PROV_WIFI_STA_CONNECTING,
|
||||
NETWORK_PROV_WIFI_STA_CONNECTED,
|
||||
NETWORK_PROV_WIFI_STA_DISCONNECTED,
|
||||
NETWORK_PROV_WIFI_STA_CONN_ATTEMPT_FAILED
|
||||
} network_prov_wifi_sta_state_t;
|
||||
|
||||
/**
|
||||
* @brief WiFi STA connection fail reason
|
||||
*/
|
||||
typedef enum {
|
||||
NETWORK_PROV_WIFI_STA_AUTH_ERROR,
|
||||
NETWORK_PROV_WIFI_STA_AP_NOT_FOUND
|
||||
} network_prov_wifi_sta_fail_reason_t;
|
||||
|
||||
/**
|
||||
* @brief WiFi STA connected status information
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* IP Address received by station
|
||||
*/
|
||||
char ip_addr[IP4ADDR_STRLEN_MAX];
|
||||
|
||||
char bssid[6]; /*!< BSSID of the AP to which connection was estalished */
|
||||
char ssid[33]; /*!< SSID of the to which connection was estalished */
|
||||
uint8_t channel; /*!< Channel of the AP */
|
||||
uint8_t auth_mode; /*!< Authorization mode of the AP */
|
||||
} network_prov_wifi_sta_conn_info_t;
|
||||
|
||||
/**
|
||||
* @brief WiFi STA connecting status information
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t attempts_remaining; /*!< Number of Wi-Fi connection attempts remaining */
|
||||
} network_prov_wifi_sta_connecting_info_t;
|
||||
|
||||
/**
|
||||
* @brief WiFi status data to be sent in response to `get_status` request from master
|
||||
*/
|
||||
typedef struct {
|
||||
network_prov_wifi_sta_state_t wifi_state; /*!< WiFi state of the station */
|
||||
union {
|
||||
/**
|
||||
* Reason for disconnection (valid only when `wifi_state` is `WIFI_STATION_DISCONNECTED`)
|
||||
*/
|
||||
network_prov_wifi_sta_fail_reason_t fail_reason;
|
||||
|
||||
/**
|
||||
* Connection information (valid only when `wifi_state` is `WIFI_STATION_CONNECTED`)
|
||||
*/
|
||||
network_prov_wifi_sta_conn_info_t conn_info;
|
||||
|
||||
/**
|
||||
* Connecting information (valid only when `wifi_state` is `WIFI_STATION_CONNECTING`)
|
||||
*/
|
||||
network_prov_wifi_sta_connecting_info_t connecting_info;
|
||||
};
|
||||
} network_prov_config_get_wifi_data_t;
|
||||
|
||||
/**
|
||||
* @brief WiFi config data received by slave during `set_config` request from master
|
||||
*/
|
||||
typedef struct {
|
||||
char ssid[33]; /*!< SSID of the AP to which the slave is to be connected */
|
||||
char password[64]; /*!< Password of the AP */
|
||||
char bssid[6]; /*!< BSSID of the AP */
|
||||
uint8_t channel; /*!< Channel of the AP */
|
||||
} network_prov_config_set_wifi_data_t;
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
/**
|
||||
* @brief Thread status for conveying back to the provisioning master
|
||||
*/
|
||||
typedef enum {
|
||||
NETWORK_PROV_THREAD_ATTACHING,
|
||||
NETWORK_PROV_THREAD_ATTACHED,
|
||||
NETWORK_PROV_THREAD_DETACHED,
|
||||
} network_prov_thread_state_t;
|
||||
|
||||
/**
|
||||
* @brief Thread attaching fail reason
|
||||
*/
|
||||
typedef enum {
|
||||
NETWORK_PROV_THREAD_DATASET_INVALID,
|
||||
NETWORK_PROV_THREAD_NETWORK_NOT_FOUND,
|
||||
} network_prov_thread_fail_reason_t;
|
||||
|
||||
/**
|
||||
* @brief Thread attached status information
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t pan_id; /*!< PAN ID */
|
||||
uint16_t channel; /*!< Channel */
|
||||
char name[17]; /*!< Network Name */
|
||||
uint8_t ext_pan_id[8]; /*!< Extended PAN ID */
|
||||
} network_prov_thread_conn_info_t;
|
||||
|
||||
/**
|
||||
* @brief Thread status data to be sent in response to `get_status` request from master
|
||||
*/
|
||||
typedef struct {
|
||||
network_prov_thread_state_t thread_state;
|
||||
union {
|
||||
/**
|
||||
* Reason for disconnection (valid only when `thread_state` is `THREAD_DETACHED`)
|
||||
*/
|
||||
network_prov_thread_fail_reason_t fail_reason;
|
||||
|
||||
/**
|
||||
* Connection information (valid only when `thread_state` is `THREAD_ATTACHED`)
|
||||
*/
|
||||
network_prov_thread_conn_info_t conn_info;
|
||||
};
|
||||
} network_prov_config_get_thread_data_t;
|
||||
|
||||
/**
|
||||
* @brief Thread config data received by slave during `set_config` request from master
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t dataset[254];
|
||||
uint8_t length;
|
||||
} network_prov_config_set_thread_data_t;
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
|
||||
/**
|
||||
* @brief Type of context data passed to each get/set/apply handler
|
||||
* function set in `network_prov_config_handlers` structure.
|
||||
*
|
||||
* This is passed as an opaque pointer, thereby allowing it be defined
|
||||
* later in application code as per requirements.
|
||||
*/
|
||||
typedef struct network_prov_ctx network_prov_ctx_t;
|
||||
|
||||
/**
|
||||
* @brief Internal handlers for receiving and responding to protocomm
|
||||
* requests from master
|
||||
*
|
||||
* This is to be passed as priv_data for protocomm request handler
|
||||
* (refer to `network_prov_config_data_handler()`) when calling `protocomm_add_endpoint()`.
|
||||
*/
|
||||
typedef struct network_prov_config_handlers {
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
/**
|
||||
* Handler function called when connection status
|
||||
* of the slave (in WiFi station mode) is requested
|
||||
*/
|
||||
esp_err_t (*wifi_get_status_handler)(network_prov_config_get_wifi_data_t *resp_data,
|
||||
network_prov_ctx_t **ctx);
|
||||
|
||||
/**
|
||||
* Handler function called when WiFi connection configuration
|
||||
* (eg. AP SSID, password, etc.) of the slave (in WiFi station mode)
|
||||
* is to be set to user provided values
|
||||
*/
|
||||
esp_err_t (*wifi_set_config_handler)(const network_prov_config_set_wifi_data_t *req_data,
|
||||
network_prov_ctx_t **ctx);
|
||||
|
||||
/**
|
||||
* Handler function for applying the configuration that was set in
|
||||
* `set_config_handler`. After applying the station may get connected to
|
||||
* the AP or may fail to connect. The slave must be ready to convey the
|
||||
* updated connection status information when `get_status_handler` is
|
||||
* invoked again by the master.
|
||||
*/
|
||||
esp_err_t (*wifi_apply_config_handler)(network_prov_ctx_t **ctx);
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
esp_err_t (*thread_get_status_handler)(network_prov_config_get_thread_data_t *resp_data,
|
||||
network_prov_ctx_t **ctx);
|
||||
|
||||
esp_err_t (*thread_set_config_handler)(const network_prov_config_set_thread_data_t *req_data,
|
||||
network_prov_ctx_t **ctx);
|
||||
|
||||
esp_err_t (*thread_apply_config_handler)(network_prov_ctx_t **ctx);
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
|
||||
/**
|
||||
* Context pointer to be passed to above handler functions upon invocation
|
||||
*/
|
||||
network_prov_ctx_t *ctx;
|
||||
} network_prov_config_handlers_t;
|
||||
|
||||
/**
|
||||
* @brief Handler for receiving and responding to requests from master
|
||||
*
|
||||
* This is to be registered as the `network_config` endpoint handler
|
||||
* (protocomm `protocomm_req_handler_t`) using `protocomm_add_endpoint()`
|
||||
*/
|
||||
esp_err_t network_prov_config_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,
|
||||
uint8_t **outbuf, ssize_t *outlen, void *priv_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _PROV_NETWORK_SCAN_H_
|
||||
#define _PROV_NETWORK_SCAN_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <sdkconfig.h>
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
#include <esp_wifi.h>
|
||||
|
||||
#define WIFI_SSID_LEN sizeof(((wifi_ap_record_t *)0)->ssid)
|
||||
#define WIFI_BSSID_LEN sizeof(((wifi_ap_record_t *)0)->bssid)
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
#include <openthread/dataset.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
|
||||
/**
|
||||
* @brief Type of context data passed to each get/set/apply handler
|
||||
* function set in `network_prov_scan_handlers` structure.
|
||||
*
|
||||
* This is passed as an opaque pointer, thereby allowing it be defined
|
||||
* later in application code as per requirements.
|
||||
*/
|
||||
typedef struct network_prov_scan_ctx network_prov_scan_ctx_t;
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
/**
|
||||
* @brief Structure of entries in the scan results list
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* SSID of Wi-Fi AP
|
||||
*/
|
||||
char ssid[WIFI_SSID_LEN];
|
||||
|
||||
/**
|
||||
* BSSID of Wi-Fi AP
|
||||
*/
|
||||
char bssid[WIFI_BSSID_LEN];
|
||||
|
||||
/**
|
||||
* Wi-Fi channel number
|
||||
*/
|
||||
uint8_t channel;
|
||||
|
||||
/**
|
||||
* Signal strength
|
||||
*/
|
||||
int rssi;
|
||||
|
||||
/**
|
||||
* Wi-Fi security mode
|
||||
*/
|
||||
uint8_t auth;
|
||||
} network_prov_scan_wifi_result_t;
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
typedef struct {
|
||||
uint16_t pan_id;
|
||||
uint8_t ext_pan_id[OT_EXT_ADDRESS_SIZE];
|
||||
char network_name[OT_NETWORK_NAME_MAX_SIZE + 1];
|
||||
uint16_t channel;
|
||||
uint8_t ext_addr[OT_EXT_ADDRESS_SIZE];
|
||||
int8_t rssi;
|
||||
uint8_t lqi;
|
||||
} network_prov_scan_thread_result_t;
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
|
||||
/**
|
||||
* @brief Internal handlers for receiving and responding to protocomm
|
||||
* requests from client
|
||||
*
|
||||
* This is to be passed as priv_data for protocomm request handler
|
||||
* (refer to `network_prov_scan_handler()`) when calling `protocomm_add_endpoint()`.
|
||||
*/
|
||||
typedef struct network_prov_scan_handlers {
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
/**
|
||||
* Handler function called when scan start command is received
|
||||
* with various scan parameters :
|
||||
*
|
||||
* blocking (input) - If true, the function should return only
|
||||
* when the scanning is finished
|
||||
*
|
||||
* passive (input) - If true, scan is to be started in passive
|
||||
* mode (this may be slower) instead of active mode
|
||||
*
|
||||
* group_channels (input) - This specifies whether to scan
|
||||
* all channels in one go (when zero) or perform scanning of
|
||||
* channels in groups, with 120ms delay between scanning of
|
||||
* consecutive groups, and the value of this parameter sets the
|
||||
* number of channels in each group. This is useful when transport
|
||||
* mode is SoftAP, where scanning all channels in one go may not
|
||||
* give the Wi-Fi driver enough time to send out beacons, and
|
||||
* hence may cause disconnection with any connected stations.
|
||||
* When scanning in groups, the manager will wait for at least
|
||||
* 120ms after completing scan on a group of channels, and thus
|
||||
* allow the driver to send out the beacons. For example, given
|
||||
* that the total number of Wi-Fi channels is 14, then setting
|
||||
* group_channels to 4, will create 5 groups, with each group
|
||||
* having 3 channels, except the last one which will have
|
||||
* 14 % 3 = 2 channels. So, when scan is started, the first 3
|
||||
* channels will be scanned, followed by a 120ms delay, and then
|
||||
* the next 3 channels, and so on, until all the 14 channels have
|
||||
* been scanned. One may need to adjust this parameter as having
|
||||
* only few channels in a group may slow down the overall scan
|
||||
* time, while having too many may again cause disconnection.
|
||||
* Usually a value of 4 should work for most cases. Note that
|
||||
* for any other mode of transport, e.g. BLE, this can be safely
|
||||
* set to 0, and hence achieve the fastest overall scanning time.
|
||||
*
|
||||
* period_ms (input) - Scan parameter specifying how long to
|
||||
* wait on each channel (in milli-seconds)
|
||||
*/
|
||||
esp_err_t (*wifi_scan_start)(bool blocking, bool passive,
|
||||
uint8_t group_channels, uint32_t period_ms,
|
||||
network_prov_scan_ctx_t **ctx);
|
||||
|
||||
/**
|
||||
* Handler function called when scan status is requested. Status
|
||||
* is given the parameters :
|
||||
*
|
||||
* scan_finished (output) - When scan has finished this returns true
|
||||
*
|
||||
* result_count (output) - This gives the total number of results
|
||||
* obtained till now. If scan is yet happening this number will
|
||||
* keep on updating
|
||||
*/
|
||||
esp_err_t (*wifi_scan_status)(bool *scan_finished,
|
||||
uint16_t *result_count,
|
||||
network_prov_scan_ctx_t **ctx);
|
||||
|
||||
/**
|
||||
* Handler function called when scan result is requested. Parameters :
|
||||
*
|
||||
* scan_result - For fetching scan results. This can be called even
|
||||
* if scan is still on going
|
||||
*
|
||||
* start_index (input) - Starting index from where to fetch the
|
||||
* entries from the results list
|
||||
*
|
||||
* count (input) - Number of entries to fetch from the starting index
|
||||
*
|
||||
* entries (output) - List of entries returned. Each entry consists
|
||||
* of ssid, channel and rssi information
|
||||
*/
|
||||
esp_err_t (*wifi_scan_result)(uint16_t result_index,
|
||||
network_prov_scan_wifi_result_t *result,
|
||||
network_prov_scan_ctx_t **ctx);
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
esp_err_t (*thread_scan_start)(bool blocking, uint32_t channel_mask, network_prov_scan_ctx_t **ctx);
|
||||
|
||||
esp_err_t (*thread_scan_status)(bool *scan_finished,
|
||||
uint16_t *result_count,
|
||||
network_prov_scan_ctx_t **ctx);
|
||||
|
||||
esp_err_t (*thread_scan_result)(uint16_t result_index,
|
||||
network_prov_scan_thread_result_t *result,
|
||||
network_prov_scan_ctx_t **ctx);
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
|
||||
/**
|
||||
* Context pointer to be passed to above handler functions upon invocation
|
||||
*/
|
||||
network_prov_scan_ctx_t *ctx;
|
||||
} network_prov_scan_handlers_t;
|
||||
|
||||
/**
|
||||
* @brief Handler for sending on demand Wi-Fi scan results
|
||||
*
|
||||
* This is to be registered as the `prov-scan` endpoint handler
|
||||
* (protocomm `protocomm_req_handler_t`) using `protocomm_add_endpoint()`
|
||||
*/
|
||||
esp_err_t network_prov_scan_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,
|
||||
uint8_t **outbuf, ssize_t *outlen, void *priv_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_ble.h>
|
||||
|
||||
#include "network_provisioning/manager.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Scheme that can be used by manager for provisioning
|
||||
* over BLE transport with GATT server
|
||||
*/
|
||||
extern const network_prov_scheme_t network_prov_scheme_ble;
|
||||
|
||||
/* This scheme specific event handler is to be used when application
|
||||
* doesn't require BT and BLE after provisioning has finished */
|
||||
#define NETWORK_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM { \
|
||||
.event_cb = network_prov_scheme_ble_event_cb_free_btdm, \
|
||||
.user_data = NULL \
|
||||
}
|
||||
|
||||
/* This scheme specific event handler is to be used when application
|
||||
* doesn't require BLE to be active after provisioning has finished */
|
||||
#define NETWORK_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BLE { \
|
||||
.event_cb = network_prov_scheme_ble_event_cb_free_ble, \
|
||||
.user_data = NULL \
|
||||
}
|
||||
|
||||
/* This scheme specific event handler is to be used when application
|
||||
* doesn't require BT to be active after provisioning has finished */
|
||||
#define NETWORK_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BT { \
|
||||
.event_cb = network_prov_scheme_ble_event_cb_free_bt, \
|
||||
.user_data = NULL \
|
||||
}
|
||||
|
||||
void network_prov_scheme_ble_event_cb_free_btdm(void *user_data, network_prov_cb_event_t event, void *event_data);
|
||||
void network_prov_scheme_ble_event_cb_free_ble (void *user_data, network_prov_cb_event_t event, void *event_data);
|
||||
void network_prov_scheme_ble_event_cb_free_bt (void *user_data, network_prov_cb_event_t event, void *event_data);
|
||||
|
||||
/**
|
||||
* @brief Set the 128 bit GATT service UUID used for provisioning
|
||||
*
|
||||
* This API is used to override the default 128 bit provisioning
|
||||
* service UUID, which is 0000ffff-0000-1000-8000-00805f9b34fb.
|
||||
*
|
||||
* This must be called before starting provisioning, i.e. before
|
||||
* making a call to network_prov_mgr_start_provisioning(), otherwise
|
||||
* the default UUID will be used.
|
||||
*
|
||||
* @note The data being pointed to by the argument must be valid
|
||||
* at least till provisioning is started. Upon start, the
|
||||
* manager will store an internal copy of this UUID, and
|
||||
* this data can be freed or invalidated afterwards.
|
||||
*
|
||||
* @param[in] uuid128 A custom 128 bit UUID
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Success
|
||||
* - ESP_ERR_INVALID_ARG : Null argument
|
||||
*/
|
||||
esp_err_t network_prov_scheme_ble_set_service_uuid(uint8_t *uuid128);
|
||||
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
|
||||
/**
|
||||
* @brief Keep the BLE on after provisioning
|
||||
*
|
||||
* This API is used to specify whether the BLE should remain on
|
||||
* after the provisioning process has stopped.
|
||||
*
|
||||
* This must be called before starting provisioning, i.e. before
|
||||
* making a call to network_prov_mgr_start_provisioning(), otherwise
|
||||
* the default behavior will be used.
|
||||
*
|
||||
* @note The value being pointed to by the argument must be valid
|
||||
* at least until provisioning is started. Upon start, the
|
||||
* manager will store an internal copy of this value, and
|
||||
* this data can be freed or invalidated afterwards.
|
||||
*
|
||||
* @param[in] is_on_after_ble_stop A boolean indicating if BLE should remain on after provisioning
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Success
|
||||
* - ESP_ERR_INVALID_ARG : Null argument
|
||||
*/
|
||||
esp_err_t network_prov_mgr_keep_ble_on(uint8_t is_on_after_ble_stop);
|
||||
|
||||
/**
|
||||
* @brief Set Bluetooth Random address
|
||||
*
|
||||
* This must be called before starting provisioning, i.e. before
|
||||
* making a call to network_prov_mgr_start_provisioning().
|
||||
*
|
||||
* This API can be used in cases where a new identity address is to be used during
|
||||
* provisioning. This will result in this device being treated as a new device by remote
|
||||
* devices.
|
||||
*
|
||||
* @note This API will change the existing BD address for the device. The address once
|
||||
* set will remain unchanged until BLE stack tear down happens when
|
||||
* network_prov_mgr_deinit is invoked.
|
||||
*
|
||||
* This API is only to be called to set random address. Re-invoking this API
|
||||
* after provisioning is started will have no effect.
|
||||
*
|
||||
* @param[in] rand_addr The static random address to be set of length 6 bytes.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Success
|
||||
* - ESP_ERR_INVALID_ARG : Null argument
|
||||
*/
|
||||
esp_err_t network_prov_scheme_ble_set_random_addr(const uint8_t *rand_addr);
|
||||
#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
|
||||
|
||||
/**
|
||||
* @brief Set manufacturer specific data in scan response
|
||||
*
|
||||
* This must be called before starting provisioning, i.e. before
|
||||
* making a call to network_prov_mgr_start_provisioning().
|
||||
*
|
||||
* @note It is important to understand that length of custom manufacturer
|
||||
* data should be within limits. The manufacturer data goes into scan
|
||||
* response along with BLE device name. By default, BLE device name
|
||||
* length is of 11 Bytes, however it can vary as per application use
|
||||
* case. So, one has to honour the scan response data size limits i.e.
|
||||
* (mfg_data_len + 2) < 31 - (device_name_length + 2 ). If the
|
||||
* mfg_data length exceeds this limit, the length will be truncated.
|
||||
*
|
||||
* @param[in] mfg_data Custom manufacturer data
|
||||
* @param[in] mfg_data_len Manufacturer data length
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Success
|
||||
* - ESP_ERR_INVALID_ARG : Null argument
|
||||
*/
|
||||
esp_err_t network_prov_scheme_ble_set_mfg_data(uint8_t *mfg_data, ssize_t mfg_data_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_console.h>
|
||||
|
||||
#include "network_provisioning/manager.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Scheme that can be used by manager for provisioning
|
||||
* over console (Serial UART)
|
||||
*/
|
||||
extern const network_prov_scheme_t network_prov_scheme_console;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_httpd.h>
|
||||
|
||||
#include "network_provisioning/manager.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Scheme that can be used by manager for provisioning
|
||||
* over SoftAP transport with HTTP server
|
||||
*/
|
||||
extern const network_prov_scheme_t network_prov_scheme_softap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Provide HTTPD Server handle externally.
|
||||
*
|
||||
* Useful in cases wherein applications need the webserver for some
|
||||
* different operations, and do not want the wifi provisioning component
|
||||
* to start/stop a new instance.
|
||||
*
|
||||
* @note This API should be called before network_prov_mgr_start_provisioning()
|
||||
*
|
||||
* @param[in] handle Handle to HTTPD server instance
|
||||
*/
|
||||
void network_prov_scheme_softap_set_httpd_handle(void *handle);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,556 @@
|
||||
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
|
||||
/* Generated from: network_config.proto */
|
||||
|
||||
#ifndef PROTOBUF_C_network_5fconfig_2eproto__INCLUDED
|
||||
#define PROTOBUF_C_network_5fconfig_2eproto__INCLUDED
|
||||
|
||||
#include <protobuf-c/protobuf-c.h>
|
||||
|
||||
PROTOBUF_C__BEGIN_DECLS
|
||||
|
||||
#if PROTOBUF_C_VERSION_NUMBER < 1003000
|
||||
# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
|
||||
#elif 1004000 < PROTOBUF_C_MIN_COMPILER_VERSION
|
||||
# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
|
||||
#endif
|
||||
|
||||
#include "constants.pb-c.h"
|
||||
#include "network_constants.pb-c.h"
|
||||
|
||||
typedef struct CmdGetWifiStatus CmdGetWifiStatus;
|
||||
typedef struct RespGetWifiStatus RespGetWifiStatus;
|
||||
typedef struct CmdGetThreadStatus CmdGetThreadStatus;
|
||||
typedef struct RespGetThreadStatus RespGetThreadStatus;
|
||||
typedef struct CmdSetWifiConfig CmdSetWifiConfig;
|
||||
typedef struct CmdSetThreadConfig CmdSetThreadConfig;
|
||||
typedef struct RespSetWifiConfig RespSetWifiConfig;
|
||||
typedef struct RespSetThreadConfig RespSetThreadConfig;
|
||||
typedef struct CmdApplyWifiConfig CmdApplyWifiConfig;
|
||||
typedef struct CmdApplyThreadConfig CmdApplyThreadConfig;
|
||||
typedef struct RespApplyWifiConfig RespApplyWifiConfig;
|
||||
typedef struct RespApplyThreadConfig RespApplyThreadConfig;
|
||||
typedef struct NetworkConfigPayload NetworkConfigPayload;
|
||||
|
||||
|
||||
/* --- enums --- */
|
||||
|
||||
typedef enum _NetworkConfigMsgType {
|
||||
NETWORK_CONFIG_MSG_TYPE__TypeCmdGetWifiStatus = 0,
|
||||
NETWORK_CONFIG_MSG_TYPE__TypeRespGetWifiStatus = 1,
|
||||
NETWORK_CONFIG_MSG_TYPE__TypeCmdSetWifiConfig = 2,
|
||||
NETWORK_CONFIG_MSG_TYPE__TypeRespSetWifiConfig = 3,
|
||||
NETWORK_CONFIG_MSG_TYPE__TypeCmdApplyWifiConfig = 4,
|
||||
NETWORK_CONFIG_MSG_TYPE__TypeRespApplyWifiConfig = 5,
|
||||
NETWORK_CONFIG_MSG_TYPE__TypeCmdGetThreadStatus = 6,
|
||||
NETWORK_CONFIG_MSG_TYPE__TypeRespGetThreadStatus = 7,
|
||||
NETWORK_CONFIG_MSG_TYPE__TypeCmdSetThreadConfig = 8,
|
||||
NETWORK_CONFIG_MSG_TYPE__TypeRespSetThreadConfig = 9,
|
||||
NETWORK_CONFIG_MSG_TYPE__TypeCmdApplyThreadConfig = 10,
|
||||
NETWORK_CONFIG_MSG_TYPE__TypeRespApplyThreadConfig = 11
|
||||
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(NETWORK_CONFIG_MSG_TYPE)
|
||||
} NetworkConfigMsgType;
|
||||
|
||||
/* --- messages --- */
|
||||
|
||||
struct CmdGetWifiStatus
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
};
|
||||
#define CMD_GET_WIFI_STATUS__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&cmd_get_wifi_status__descriptor) \
|
||||
}
|
||||
|
||||
|
||||
typedef enum {
|
||||
RESP_GET_WIFI_STATUS__STATE__NOT_SET = 0,
|
||||
RESP_GET_WIFI_STATUS__STATE_WIFI_FAIL_REASON = 10,
|
||||
RESP_GET_WIFI_STATUS__STATE_WIFI_CONNECTED = 11,
|
||||
RESP_GET_WIFI_STATUS__STATE_ATTEMPT_FAILED = 12
|
||||
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(RESP_GET_WIFI_STATUS__STATE__CASE)
|
||||
} RespGetWifiStatus__StateCase;
|
||||
|
||||
struct RespGetWifiStatus
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
Status status;
|
||||
WifiStationState wifi_sta_state;
|
||||
RespGetWifiStatus__StateCase state_case;
|
||||
union {
|
||||
WifiConnectFailedReason wifi_fail_reason;
|
||||
WifiConnectedState *wifi_connected;
|
||||
WifiAttemptFailed *attempt_failed;
|
||||
};
|
||||
};
|
||||
#define RESP_GET_WIFI_STATUS__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&resp_get_wifi_status__descriptor) \
|
||||
, STATUS__Success, WIFI_STATION_STATE__Connected, RESP_GET_WIFI_STATUS__STATE__NOT_SET, {0} }
|
||||
|
||||
|
||||
struct CmdGetThreadStatus
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
};
|
||||
#define CMD_GET_THREAD_STATUS__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&cmd_get_thread_status__descriptor) \
|
||||
}
|
||||
|
||||
|
||||
typedef enum {
|
||||
RESP_GET_THREAD_STATUS__STATE__NOT_SET = 0,
|
||||
RESP_GET_THREAD_STATUS__STATE_THREAD_FAIL_REASON = 10,
|
||||
RESP_GET_THREAD_STATUS__STATE_THREAD_ATTACHED = 11
|
||||
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(RESP_GET_THREAD_STATUS__STATE__CASE)
|
||||
} RespGetThreadStatus__StateCase;
|
||||
|
||||
struct RespGetThreadStatus
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
Status status;
|
||||
ThreadNetworkState thread_state;
|
||||
RespGetThreadStatus__StateCase state_case;
|
||||
union {
|
||||
ThreadAttachFailedReason thread_fail_reason;
|
||||
ThreadAttachState *thread_attached;
|
||||
};
|
||||
};
|
||||
#define RESP_GET_THREAD_STATUS__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&resp_get_thread_status__descriptor) \
|
||||
, STATUS__Success, THREAD_NETWORK_STATE__Attached, RESP_GET_THREAD_STATUS__STATE__NOT_SET, {0} }
|
||||
|
||||
|
||||
struct CmdSetWifiConfig
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
ProtobufCBinaryData ssid;
|
||||
ProtobufCBinaryData passphrase;
|
||||
ProtobufCBinaryData bssid;
|
||||
int32_t channel;
|
||||
};
|
||||
#define CMD_SET_WIFI_CONFIG__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&cmd_set_wifi_config__descriptor) \
|
||||
, {0,NULL}, {0,NULL}, {0,NULL}, 0 }
|
||||
|
||||
|
||||
struct CmdSetThreadConfig
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
ProtobufCBinaryData dataset;
|
||||
};
|
||||
#define CMD_SET_THREAD_CONFIG__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&cmd_set_thread_config__descriptor) \
|
||||
, {0,NULL} }
|
||||
|
||||
|
||||
struct RespSetWifiConfig
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
Status status;
|
||||
};
|
||||
#define RESP_SET_WIFI_CONFIG__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&resp_set_wifi_config__descriptor) \
|
||||
, STATUS__Success }
|
||||
|
||||
|
||||
struct RespSetThreadConfig
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
Status status;
|
||||
};
|
||||
#define RESP_SET_THREAD_CONFIG__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&resp_set_thread_config__descriptor) \
|
||||
, STATUS__Success }
|
||||
|
||||
|
||||
struct CmdApplyWifiConfig
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
};
|
||||
#define CMD_APPLY_WIFI_CONFIG__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&cmd_apply_wifi_config__descriptor) \
|
||||
}
|
||||
|
||||
|
||||
struct CmdApplyThreadConfig
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
};
|
||||
#define CMD_APPLY_THREAD_CONFIG__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&cmd_apply_thread_config__descriptor) \
|
||||
}
|
||||
|
||||
|
||||
struct RespApplyWifiConfig
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
Status status;
|
||||
};
|
||||
#define RESP_APPLY_WIFI_CONFIG__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&resp_apply_wifi_config__descriptor) \
|
||||
, STATUS__Success }
|
||||
|
||||
|
||||
struct RespApplyThreadConfig
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
Status status;
|
||||
};
|
||||
#define RESP_APPLY_THREAD_CONFIG__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&resp_apply_thread_config__descriptor) \
|
||||
, STATUS__Success }
|
||||
|
||||
|
||||
typedef enum {
|
||||
NETWORK_CONFIG_PAYLOAD__PAYLOAD__NOT_SET = 0,
|
||||
NETWORK_CONFIG_PAYLOAD__PAYLOAD_CMD_GET_WIFI_STATUS = 10,
|
||||
NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_GET_WIFI_STATUS = 11,
|
||||
NETWORK_CONFIG_PAYLOAD__PAYLOAD_CMD_SET_WIFI_CONFIG = 12,
|
||||
NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_SET_WIFI_CONFIG = 13,
|
||||
NETWORK_CONFIG_PAYLOAD__PAYLOAD_CMD_APPLY_WIFI_CONFIG = 14,
|
||||
NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_APPLY_WIFI_CONFIG = 15,
|
||||
NETWORK_CONFIG_PAYLOAD__PAYLOAD_CMD_GET_THREAD_STATUS = 16,
|
||||
NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_GET_THREAD_STATUS = 17,
|
||||
NETWORK_CONFIG_PAYLOAD__PAYLOAD_CMD_SET_THREAD_CONFIG = 18,
|
||||
NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_SET_THREAD_CONFIG = 19,
|
||||
NETWORK_CONFIG_PAYLOAD__PAYLOAD_CMD_APPLY_THREAD_CONFIG = 20,
|
||||
NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_APPLY_THREAD_CONFIG = 21
|
||||
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(NETWORK_CONFIG_PAYLOAD__PAYLOAD__CASE)
|
||||
} NetworkConfigPayload__PayloadCase;
|
||||
|
||||
struct NetworkConfigPayload
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
NetworkConfigMsgType msg;
|
||||
NetworkConfigPayload__PayloadCase payload_case;
|
||||
union {
|
||||
CmdGetWifiStatus *cmd_get_wifi_status;
|
||||
RespGetWifiStatus *resp_get_wifi_status;
|
||||
CmdSetWifiConfig *cmd_set_wifi_config;
|
||||
RespSetWifiConfig *resp_set_wifi_config;
|
||||
CmdApplyWifiConfig *cmd_apply_wifi_config;
|
||||
RespApplyWifiConfig *resp_apply_wifi_config;
|
||||
CmdGetThreadStatus *cmd_get_thread_status;
|
||||
RespGetThreadStatus *resp_get_thread_status;
|
||||
CmdSetThreadConfig *cmd_set_thread_config;
|
||||
RespSetThreadConfig *resp_set_thread_config;
|
||||
CmdApplyThreadConfig *cmd_apply_thread_config;
|
||||
RespApplyThreadConfig *resp_apply_thread_config;
|
||||
};
|
||||
};
|
||||
#define NETWORK_CONFIG_PAYLOAD__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&network_config_payload__descriptor) \
|
||||
, NETWORK_CONFIG_MSG_TYPE__TypeCmdGetWifiStatus, NETWORK_CONFIG_PAYLOAD__PAYLOAD__NOT_SET, {0} }
|
||||
|
||||
|
||||
/* CmdGetWifiStatus methods */
|
||||
void cmd_get_wifi_status__init
|
||||
(CmdGetWifiStatus *message);
|
||||
size_t cmd_get_wifi_status__get_packed_size
|
||||
(const CmdGetWifiStatus *message);
|
||||
size_t cmd_get_wifi_status__pack
|
||||
(const CmdGetWifiStatus *message,
|
||||
uint8_t *out);
|
||||
size_t cmd_get_wifi_status__pack_to_buffer
|
||||
(const CmdGetWifiStatus *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
CmdGetWifiStatus *
|
||||
cmd_get_wifi_status__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void cmd_get_wifi_status__free_unpacked
|
||||
(CmdGetWifiStatus *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* RespGetWifiStatus methods */
|
||||
void resp_get_wifi_status__init
|
||||
(RespGetWifiStatus *message);
|
||||
size_t resp_get_wifi_status__get_packed_size
|
||||
(const RespGetWifiStatus *message);
|
||||
size_t resp_get_wifi_status__pack
|
||||
(const RespGetWifiStatus *message,
|
||||
uint8_t *out);
|
||||
size_t resp_get_wifi_status__pack_to_buffer
|
||||
(const RespGetWifiStatus *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
RespGetWifiStatus *
|
||||
resp_get_wifi_status__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void resp_get_wifi_status__free_unpacked
|
||||
(RespGetWifiStatus *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* CmdGetThreadStatus methods */
|
||||
void cmd_get_thread_status__init
|
||||
(CmdGetThreadStatus *message);
|
||||
size_t cmd_get_thread_status__get_packed_size
|
||||
(const CmdGetThreadStatus *message);
|
||||
size_t cmd_get_thread_status__pack
|
||||
(const CmdGetThreadStatus *message,
|
||||
uint8_t *out);
|
||||
size_t cmd_get_thread_status__pack_to_buffer
|
||||
(const CmdGetThreadStatus *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
CmdGetThreadStatus *
|
||||
cmd_get_thread_status__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void cmd_get_thread_status__free_unpacked
|
||||
(CmdGetThreadStatus *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* RespGetThreadStatus methods */
|
||||
void resp_get_thread_status__init
|
||||
(RespGetThreadStatus *message);
|
||||
size_t resp_get_thread_status__get_packed_size
|
||||
(const RespGetThreadStatus *message);
|
||||
size_t resp_get_thread_status__pack
|
||||
(const RespGetThreadStatus *message,
|
||||
uint8_t *out);
|
||||
size_t resp_get_thread_status__pack_to_buffer
|
||||
(const RespGetThreadStatus *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
RespGetThreadStatus *
|
||||
resp_get_thread_status__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void resp_get_thread_status__free_unpacked
|
||||
(RespGetThreadStatus *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* CmdSetWifiConfig methods */
|
||||
void cmd_set_wifi_config__init
|
||||
(CmdSetWifiConfig *message);
|
||||
size_t cmd_set_wifi_config__get_packed_size
|
||||
(const CmdSetWifiConfig *message);
|
||||
size_t cmd_set_wifi_config__pack
|
||||
(const CmdSetWifiConfig *message,
|
||||
uint8_t *out);
|
||||
size_t cmd_set_wifi_config__pack_to_buffer
|
||||
(const CmdSetWifiConfig *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
CmdSetWifiConfig *
|
||||
cmd_set_wifi_config__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void cmd_set_wifi_config__free_unpacked
|
||||
(CmdSetWifiConfig *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* CmdSetThreadConfig methods */
|
||||
void cmd_set_thread_config__init
|
||||
(CmdSetThreadConfig *message);
|
||||
size_t cmd_set_thread_config__get_packed_size
|
||||
(const CmdSetThreadConfig *message);
|
||||
size_t cmd_set_thread_config__pack
|
||||
(const CmdSetThreadConfig *message,
|
||||
uint8_t *out);
|
||||
size_t cmd_set_thread_config__pack_to_buffer
|
||||
(const CmdSetThreadConfig *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
CmdSetThreadConfig *
|
||||
cmd_set_thread_config__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void cmd_set_thread_config__free_unpacked
|
||||
(CmdSetThreadConfig *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* RespSetWifiConfig methods */
|
||||
void resp_set_wifi_config__init
|
||||
(RespSetWifiConfig *message);
|
||||
size_t resp_set_wifi_config__get_packed_size
|
||||
(const RespSetWifiConfig *message);
|
||||
size_t resp_set_wifi_config__pack
|
||||
(const RespSetWifiConfig *message,
|
||||
uint8_t *out);
|
||||
size_t resp_set_wifi_config__pack_to_buffer
|
||||
(const RespSetWifiConfig *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
RespSetWifiConfig *
|
||||
resp_set_wifi_config__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void resp_set_wifi_config__free_unpacked
|
||||
(RespSetWifiConfig *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* RespSetThreadConfig methods */
|
||||
void resp_set_thread_config__init
|
||||
(RespSetThreadConfig *message);
|
||||
size_t resp_set_thread_config__get_packed_size
|
||||
(const RespSetThreadConfig *message);
|
||||
size_t resp_set_thread_config__pack
|
||||
(const RespSetThreadConfig *message,
|
||||
uint8_t *out);
|
||||
size_t resp_set_thread_config__pack_to_buffer
|
||||
(const RespSetThreadConfig *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
RespSetThreadConfig *
|
||||
resp_set_thread_config__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void resp_set_thread_config__free_unpacked
|
||||
(RespSetThreadConfig *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* CmdApplyWifiConfig methods */
|
||||
void cmd_apply_wifi_config__init
|
||||
(CmdApplyWifiConfig *message);
|
||||
size_t cmd_apply_wifi_config__get_packed_size
|
||||
(const CmdApplyWifiConfig *message);
|
||||
size_t cmd_apply_wifi_config__pack
|
||||
(const CmdApplyWifiConfig *message,
|
||||
uint8_t *out);
|
||||
size_t cmd_apply_wifi_config__pack_to_buffer
|
||||
(const CmdApplyWifiConfig *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
CmdApplyWifiConfig *
|
||||
cmd_apply_wifi_config__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void cmd_apply_wifi_config__free_unpacked
|
||||
(CmdApplyWifiConfig *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* CmdApplyThreadConfig methods */
|
||||
void cmd_apply_thread_config__init
|
||||
(CmdApplyThreadConfig *message);
|
||||
size_t cmd_apply_thread_config__get_packed_size
|
||||
(const CmdApplyThreadConfig *message);
|
||||
size_t cmd_apply_thread_config__pack
|
||||
(const CmdApplyThreadConfig *message,
|
||||
uint8_t *out);
|
||||
size_t cmd_apply_thread_config__pack_to_buffer
|
||||
(const CmdApplyThreadConfig *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
CmdApplyThreadConfig *
|
||||
cmd_apply_thread_config__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void cmd_apply_thread_config__free_unpacked
|
||||
(CmdApplyThreadConfig *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* RespApplyWifiConfig methods */
|
||||
void resp_apply_wifi_config__init
|
||||
(RespApplyWifiConfig *message);
|
||||
size_t resp_apply_wifi_config__get_packed_size
|
||||
(const RespApplyWifiConfig *message);
|
||||
size_t resp_apply_wifi_config__pack
|
||||
(const RespApplyWifiConfig *message,
|
||||
uint8_t *out);
|
||||
size_t resp_apply_wifi_config__pack_to_buffer
|
||||
(const RespApplyWifiConfig *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
RespApplyWifiConfig *
|
||||
resp_apply_wifi_config__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void resp_apply_wifi_config__free_unpacked
|
||||
(RespApplyWifiConfig *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* RespApplyThreadConfig methods */
|
||||
void resp_apply_thread_config__init
|
||||
(RespApplyThreadConfig *message);
|
||||
size_t resp_apply_thread_config__get_packed_size
|
||||
(const RespApplyThreadConfig *message);
|
||||
size_t resp_apply_thread_config__pack
|
||||
(const RespApplyThreadConfig *message,
|
||||
uint8_t *out);
|
||||
size_t resp_apply_thread_config__pack_to_buffer
|
||||
(const RespApplyThreadConfig *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
RespApplyThreadConfig *
|
||||
resp_apply_thread_config__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void resp_apply_thread_config__free_unpacked
|
||||
(RespApplyThreadConfig *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* NetworkConfigPayload methods */
|
||||
void network_config_payload__init
|
||||
(NetworkConfigPayload *message);
|
||||
size_t network_config_payload__get_packed_size
|
||||
(const NetworkConfigPayload *message);
|
||||
size_t network_config_payload__pack
|
||||
(const NetworkConfigPayload *message,
|
||||
uint8_t *out);
|
||||
size_t network_config_payload__pack_to_buffer
|
||||
(const NetworkConfigPayload *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
NetworkConfigPayload *
|
||||
network_config_payload__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void network_config_payload__free_unpacked
|
||||
(NetworkConfigPayload *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* --- per-message closures --- */
|
||||
|
||||
typedef void (*CmdGetWifiStatus_Closure)
|
||||
(const CmdGetWifiStatus *message,
|
||||
void *closure_data);
|
||||
typedef void (*RespGetWifiStatus_Closure)
|
||||
(const RespGetWifiStatus *message,
|
||||
void *closure_data);
|
||||
typedef void (*CmdGetThreadStatus_Closure)
|
||||
(const CmdGetThreadStatus *message,
|
||||
void *closure_data);
|
||||
typedef void (*RespGetThreadStatus_Closure)
|
||||
(const RespGetThreadStatus *message,
|
||||
void *closure_data);
|
||||
typedef void (*CmdSetWifiConfig_Closure)
|
||||
(const CmdSetWifiConfig *message,
|
||||
void *closure_data);
|
||||
typedef void (*CmdSetThreadConfig_Closure)
|
||||
(const CmdSetThreadConfig *message,
|
||||
void *closure_data);
|
||||
typedef void (*RespSetWifiConfig_Closure)
|
||||
(const RespSetWifiConfig *message,
|
||||
void *closure_data);
|
||||
typedef void (*RespSetThreadConfig_Closure)
|
||||
(const RespSetThreadConfig *message,
|
||||
void *closure_data);
|
||||
typedef void (*CmdApplyWifiConfig_Closure)
|
||||
(const CmdApplyWifiConfig *message,
|
||||
void *closure_data);
|
||||
typedef void (*CmdApplyThreadConfig_Closure)
|
||||
(const CmdApplyThreadConfig *message,
|
||||
void *closure_data);
|
||||
typedef void (*RespApplyWifiConfig_Closure)
|
||||
(const RespApplyWifiConfig *message,
|
||||
void *closure_data);
|
||||
typedef void (*RespApplyThreadConfig_Closure)
|
||||
(const RespApplyThreadConfig *message,
|
||||
void *closure_data);
|
||||
typedef void (*NetworkConfigPayload_Closure)
|
||||
(const NetworkConfigPayload *message,
|
||||
void *closure_data);
|
||||
|
||||
/* --- services --- */
|
||||
|
||||
|
||||
/* --- descriptors --- */
|
||||
|
||||
extern const ProtobufCEnumDescriptor network_config_msg_type__descriptor;
|
||||
extern const ProtobufCMessageDescriptor cmd_get_wifi_status__descriptor;
|
||||
extern const ProtobufCMessageDescriptor resp_get_wifi_status__descriptor;
|
||||
extern const ProtobufCMessageDescriptor cmd_get_thread_status__descriptor;
|
||||
extern const ProtobufCMessageDescriptor resp_get_thread_status__descriptor;
|
||||
extern const ProtobufCMessageDescriptor cmd_set_wifi_config__descriptor;
|
||||
extern const ProtobufCMessageDescriptor cmd_set_thread_config__descriptor;
|
||||
extern const ProtobufCMessageDescriptor resp_set_wifi_config__descriptor;
|
||||
extern const ProtobufCMessageDescriptor resp_set_thread_config__descriptor;
|
||||
extern const ProtobufCMessageDescriptor cmd_apply_wifi_config__descriptor;
|
||||
extern const ProtobufCMessageDescriptor cmd_apply_thread_config__descriptor;
|
||||
extern const ProtobufCMessageDescriptor resp_apply_wifi_config__descriptor;
|
||||
extern const ProtobufCMessageDescriptor resp_apply_thread_config__descriptor;
|
||||
extern const ProtobufCMessageDescriptor network_config_payload__descriptor;
|
||||
|
||||
PROTOBUF_C__END_DECLS
|
||||
|
||||
|
||||
#endif /* PROTOBUF_C_network_5fconfig_2eproto__INCLUDED */
|
||||
@@ -0,0 +1,509 @@
|
||||
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
|
||||
/* Generated from: network_constants.proto */
|
||||
|
||||
/* Do not generate deprecated warnings for self */
|
||||
#ifndef PROTOBUF_C__NO_DEPRECATED
|
||||
#define PROTOBUF_C__NO_DEPRECATED
|
||||
#endif
|
||||
|
||||
#include "network_constants.pb-c.h"
|
||||
void wifi_connected_state__init
|
||||
(WifiConnectedState *message)
|
||||
{
|
||||
static const WifiConnectedState init_value = WIFI_CONNECTED_STATE__INIT;
|
||||
*message = init_value;
|
||||
}
|
||||
size_t wifi_connected_state__get_packed_size
|
||||
(const WifiConnectedState *message)
|
||||
{
|
||||
assert(message->base.descriptor == &wifi_connected_state__descriptor);
|
||||
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
||||
}
|
||||
size_t wifi_connected_state__pack
|
||||
(const WifiConnectedState *message,
|
||||
uint8_t *out)
|
||||
{
|
||||
assert(message->base.descriptor == &wifi_connected_state__descriptor);
|
||||
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
||||
}
|
||||
size_t wifi_connected_state__pack_to_buffer
|
||||
(const WifiConnectedState *message,
|
||||
ProtobufCBuffer *buffer)
|
||||
{
|
||||
assert(message->base.descriptor == &wifi_connected_state__descriptor);
|
||||
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
||||
}
|
||||
WifiConnectedState *
|
||||
wifi_connected_state__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data)
|
||||
{
|
||||
return (WifiConnectedState *)
|
||||
protobuf_c_message_unpack (&wifi_connected_state__descriptor,
|
||||
allocator, len, data);
|
||||
}
|
||||
void wifi_connected_state__free_unpacked
|
||||
(WifiConnectedState *message,
|
||||
ProtobufCAllocator *allocator)
|
||||
{
|
||||
if(!message)
|
||||
return;
|
||||
assert(message->base.descriptor == &wifi_connected_state__descriptor);
|
||||
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
||||
}
|
||||
void wifi_attempt_failed__init
|
||||
(WifiAttemptFailed *message)
|
||||
{
|
||||
static const WifiAttemptFailed init_value = WIFI_ATTEMPT_FAILED__INIT;
|
||||
*message = init_value;
|
||||
}
|
||||
size_t wifi_attempt_failed__get_packed_size
|
||||
(const WifiAttemptFailed *message)
|
||||
{
|
||||
assert(message->base.descriptor == &wifi_attempt_failed__descriptor);
|
||||
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
||||
}
|
||||
size_t wifi_attempt_failed__pack
|
||||
(const WifiAttemptFailed *message,
|
||||
uint8_t *out)
|
||||
{
|
||||
assert(message->base.descriptor == &wifi_attempt_failed__descriptor);
|
||||
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
||||
}
|
||||
size_t wifi_attempt_failed__pack_to_buffer
|
||||
(const WifiAttemptFailed *message,
|
||||
ProtobufCBuffer *buffer)
|
||||
{
|
||||
assert(message->base.descriptor == &wifi_attempt_failed__descriptor);
|
||||
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
||||
}
|
||||
WifiAttemptFailed *
|
||||
wifi_attempt_failed__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data)
|
||||
{
|
||||
return (WifiAttemptFailed *)
|
||||
protobuf_c_message_unpack (&wifi_attempt_failed__descriptor,
|
||||
allocator, len, data);
|
||||
}
|
||||
void wifi_attempt_failed__free_unpacked
|
||||
(WifiAttemptFailed *message,
|
||||
ProtobufCAllocator *allocator)
|
||||
{
|
||||
if(!message)
|
||||
return;
|
||||
assert(message->base.descriptor == &wifi_attempt_failed__descriptor);
|
||||
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
||||
}
|
||||
void thread_attach_state__init
|
||||
(ThreadAttachState *message)
|
||||
{
|
||||
static const ThreadAttachState init_value = THREAD_ATTACH_STATE__INIT;
|
||||
*message = init_value;
|
||||
}
|
||||
size_t thread_attach_state__get_packed_size
|
||||
(const ThreadAttachState *message)
|
||||
{
|
||||
assert(message->base.descriptor == &thread_attach_state__descriptor);
|
||||
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
||||
}
|
||||
size_t thread_attach_state__pack
|
||||
(const ThreadAttachState *message,
|
||||
uint8_t *out)
|
||||
{
|
||||
assert(message->base.descriptor == &thread_attach_state__descriptor);
|
||||
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
||||
}
|
||||
size_t thread_attach_state__pack_to_buffer
|
||||
(const ThreadAttachState *message,
|
||||
ProtobufCBuffer *buffer)
|
||||
{
|
||||
assert(message->base.descriptor == &thread_attach_state__descriptor);
|
||||
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
||||
}
|
||||
ThreadAttachState *
|
||||
thread_attach_state__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data)
|
||||
{
|
||||
return (ThreadAttachState *)
|
||||
protobuf_c_message_unpack (&thread_attach_state__descriptor,
|
||||
allocator, len, data);
|
||||
}
|
||||
void thread_attach_state__free_unpacked
|
||||
(ThreadAttachState *message,
|
||||
ProtobufCAllocator *allocator)
|
||||
{
|
||||
if(!message)
|
||||
return;
|
||||
assert(message->base.descriptor == &thread_attach_state__descriptor);
|
||||
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
||||
}
|
||||
static const ProtobufCFieldDescriptor wifi_connected_state__field_descriptors[5] =
|
||||
{
|
||||
{
|
||||
"ip4_addr",
|
||||
1,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_STRING,
|
||||
0, /* quantifier_offset */
|
||||
offsetof(WifiConnectedState, ip4_addr),
|
||||
NULL,
|
||||
&protobuf_c_empty_string,
|
||||
0, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"auth_mode",
|
||||
2,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_ENUM,
|
||||
0, /* quantifier_offset */
|
||||
offsetof(WifiConnectedState, auth_mode),
|
||||
&wifi_auth_mode__descriptor,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"ssid",
|
||||
3,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_BYTES,
|
||||
0, /* quantifier_offset */
|
||||
offsetof(WifiConnectedState, ssid),
|
||||
NULL,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"bssid",
|
||||
4,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_BYTES,
|
||||
0, /* quantifier_offset */
|
||||
offsetof(WifiConnectedState, bssid),
|
||||
NULL,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"channel",
|
||||
5,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_INT32,
|
||||
0, /* quantifier_offset */
|
||||
offsetof(WifiConnectedState, channel),
|
||||
NULL,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
};
|
||||
static const unsigned wifi_connected_state__field_indices_by_name[] = {
|
||||
1, /* field[1] = auth_mode */
|
||||
3, /* field[3] = bssid */
|
||||
4, /* field[4] = channel */
|
||||
0, /* field[0] = ip4_addr */
|
||||
2, /* field[2] = ssid */
|
||||
};
|
||||
static const ProtobufCIntRange wifi_connected_state__number_ranges[1 + 1] =
|
||||
{
|
||||
{ 1, 0 },
|
||||
{ 0, 5 }
|
||||
};
|
||||
const ProtobufCMessageDescriptor wifi_connected_state__descriptor =
|
||||
{
|
||||
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
||||
"WifiConnectedState",
|
||||
"WifiConnectedState",
|
||||
"WifiConnectedState",
|
||||
"",
|
||||
sizeof(WifiConnectedState),
|
||||
5,
|
||||
wifi_connected_state__field_descriptors,
|
||||
wifi_connected_state__field_indices_by_name,
|
||||
1, wifi_connected_state__number_ranges,
|
||||
(ProtobufCMessageInit) wifi_connected_state__init,
|
||||
NULL,NULL,NULL /* reserved[123] */
|
||||
};
|
||||
static const ProtobufCFieldDescriptor wifi_attempt_failed__field_descriptors[1] =
|
||||
{
|
||||
{
|
||||
"attempts_remaining",
|
||||
1,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_UINT32,
|
||||
0, /* quantifier_offset */
|
||||
offsetof(WifiAttemptFailed, attempts_remaining),
|
||||
NULL,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
};
|
||||
static const unsigned wifi_attempt_failed__field_indices_by_name[] = {
|
||||
0, /* field[0] = attempts_remaining */
|
||||
};
|
||||
static const ProtobufCIntRange wifi_attempt_failed__number_ranges[1 + 1] =
|
||||
{
|
||||
{ 1, 0 },
|
||||
{ 0, 1 }
|
||||
};
|
||||
const ProtobufCMessageDescriptor wifi_attempt_failed__descriptor =
|
||||
{
|
||||
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
||||
"WifiAttemptFailed",
|
||||
"WifiAttemptFailed",
|
||||
"WifiAttemptFailed",
|
||||
"",
|
||||
sizeof(WifiAttemptFailed),
|
||||
1,
|
||||
wifi_attempt_failed__field_descriptors,
|
||||
wifi_attempt_failed__field_indices_by_name,
|
||||
1, wifi_attempt_failed__number_ranges,
|
||||
(ProtobufCMessageInit) wifi_attempt_failed__init,
|
||||
NULL,NULL,NULL /* reserved[123] */
|
||||
};
|
||||
static const ProtobufCFieldDescriptor thread_attach_state__field_descriptors[4] =
|
||||
{
|
||||
{
|
||||
"pan_id",
|
||||
1,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_UINT32,
|
||||
0, /* quantifier_offset */
|
||||
offsetof(ThreadAttachState, pan_id),
|
||||
NULL,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"ext_pan_id",
|
||||
2,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_BYTES,
|
||||
0, /* quantifier_offset */
|
||||
offsetof(ThreadAttachState, ext_pan_id),
|
||||
NULL,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"channel",
|
||||
3,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_UINT32,
|
||||
0, /* quantifier_offset */
|
||||
offsetof(ThreadAttachState, channel),
|
||||
NULL,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"name",
|
||||
4,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_STRING,
|
||||
0, /* quantifier_offset */
|
||||
offsetof(ThreadAttachState, name),
|
||||
NULL,
|
||||
&protobuf_c_empty_string,
|
||||
0, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
};
|
||||
static const unsigned thread_attach_state__field_indices_by_name[] = {
|
||||
2, /* field[2] = channel */
|
||||
1, /* field[1] = ext_pan_id */
|
||||
3, /* field[3] = name */
|
||||
0, /* field[0] = pan_id */
|
||||
};
|
||||
static const ProtobufCIntRange thread_attach_state__number_ranges[1 + 1] =
|
||||
{
|
||||
{ 1, 0 },
|
||||
{ 0, 4 }
|
||||
};
|
||||
const ProtobufCMessageDescriptor thread_attach_state__descriptor =
|
||||
{
|
||||
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
||||
"ThreadAttachState",
|
||||
"ThreadAttachState",
|
||||
"ThreadAttachState",
|
||||
"",
|
||||
sizeof(ThreadAttachState),
|
||||
4,
|
||||
thread_attach_state__field_descriptors,
|
||||
thread_attach_state__field_indices_by_name,
|
||||
1, thread_attach_state__number_ranges,
|
||||
(ProtobufCMessageInit) thread_attach_state__init,
|
||||
NULL,NULL,NULL /* reserved[123] */
|
||||
};
|
||||
static const ProtobufCEnumValue wifi_station_state__enum_values_by_number[4] =
|
||||
{
|
||||
{ "Connected", "WIFI_STATION_STATE__Connected", 0 },
|
||||
{ "Connecting", "WIFI_STATION_STATE__Connecting", 1 },
|
||||
{ "Disconnected", "WIFI_STATION_STATE__Disconnected", 2 },
|
||||
{ "ConnectionFailed", "WIFI_STATION_STATE__ConnectionFailed", 3 },
|
||||
};
|
||||
static const ProtobufCIntRange wifi_station_state__value_ranges[] = {
|
||||
{0, 0},{0, 4}
|
||||
};
|
||||
static const ProtobufCEnumValueIndex wifi_station_state__enum_values_by_name[4] =
|
||||
{
|
||||
{ "Connected", 0 },
|
||||
{ "Connecting", 1 },
|
||||
{ "ConnectionFailed", 3 },
|
||||
{ "Disconnected", 2 },
|
||||
};
|
||||
const ProtobufCEnumDescriptor wifi_station_state__descriptor =
|
||||
{
|
||||
PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,
|
||||
"WifiStationState",
|
||||
"WifiStationState",
|
||||
"WifiStationState",
|
||||
"",
|
||||
4,
|
||||
wifi_station_state__enum_values_by_number,
|
||||
4,
|
||||
wifi_station_state__enum_values_by_name,
|
||||
1,
|
||||
wifi_station_state__value_ranges,
|
||||
NULL,NULL,NULL,NULL /* reserved[1234] */
|
||||
};
|
||||
static const ProtobufCEnumValue wifi_connect_failed_reason__enum_values_by_number[2] =
|
||||
{
|
||||
{ "AuthError", "WIFI_CONNECT_FAILED_REASON__AuthError", 0 },
|
||||
{ "WifiNetworkNotFound", "WIFI_CONNECT_FAILED_REASON__WifiNetworkNotFound", 1 },
|
||||
};
|
||||
static const ProtobufCIntRange wifi_connect_failed_reason__value_ranges[] = {
|
||||
{0, 0},{0, 2}
|
||||
};
|
||||
static const ProtobufCEnumValueIndex wifi_connect_failed_reason__enum_values_by_name[2] =
|
||||
{
|
||||
{ "AuthError", 0 },
|
||||
{ "WifiNetworkNotFound", 1 },
|
||||
};
|
||||
const ProtobufCEnumDescriptor wifi_connect_failed_reason__descriptor =
|
||||
{
|
||||
PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,
|
||||
"WifiConnectFailedReason",
|
||||
"WifiConnectFailedReason",
|
||||
"WifiConnectFailedReason",
|
||||
"",
|
||||
2,
|
||||
wifi_connect_failed_reason__enum_values_by_number,
|
||||
2,
|
||||
wifi_connect_failed_reason__enum_values_by_name,
|
||||
1,
|
||||
wifi_connect_failed_reason__value_ranges,
|
||||
NULL,NULL,NULL,NULL /* reserved[1234] */
|
||||
};
|
||||
static const ProtobufCEnumValue wifi_auth_mode__enum_values_by_number[8] =
|
||||
{
|
||||
{ "Open", "WIFI_AUTH_MODE__Open", 0 },
|
||||
{ "WEP", "WIFI_AUTH_MODE__WEP", 1 },
|
||||
{ "WPA_PSK", "WIFI_AUTH_MODE__WPA_PSK", 2 },
|
||||
{ "WPA2_PSK", "WIFI_AUTH_MODE__WPA2_PSK", 3 },
|
||||
{ "WPA_WPA2_PSK", "WIFI_AUTH_MODE__WPA_WPA2_PSK", 4 },
|
||||
{ "WPA2_ENTERPRISE", "WIFI_AUTH_MODE__WPA2_ENTERPRISE", 5 },
|
||||
{ "WPA3_PSK", "WIFI_AUTH_MODE__WPA3_PSK", 6 },
|
||||
{ "WPA2_WPA3_PSK", "WIFI_AUTH_MODE__WPA2_WPA3_PSK", 7 },
|
||||
};
|
||||
static const ProtobufCIntRange wifi_auth_mode__value_ranges[] = {
|
||||
{0, 0},{0, 8}
|
||||
};
|
||||
static const ProtobufCEnumValueIndex wifi_auth_mode__enum_values_by_name[8] =
|
||||
{
|
||||
{ "Open", 0 },
|
||||
{ "WEP", 1 },
|
||||
{ "WPA2_ENTERPRISE", 5 },
|
||||
{ "WPA2_PSK", 3 },
|
||||
{ "WPA2_WPA3_PSK", 7 },
|
||||
{ "WPA3_PSK", 6 },
|
||||
{ "WPA_PSK", 2 },
|
||||
{ "WPA_WPA2_PSK", 4 },
|
||||
};
|
||||
const ProtobufCEnumDescriptor wifi_auth_mode__descriptor =
|
||||
{
|
||||
PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,
|
||||
"WifiAuthMode",
|
||||
"WifiAuthMode",
|
||||
"WifiAuthMode",
|
||||
"",
|
||||
8,
|
||||
wifi_auth_mode__enum_values_by_number,
|
||||
8,
|
||||
wifi_auth_mode__enum_values_by_name,
|
||||
1,
|
||||
wifi_auth_mode__value_ranges,
|
||||
NULL,NULL,NULL,NULL /* reserved[1234] */
|
||||
};
|
||||
static const ProtobufCEnumValue thread_network_state__enum_values_by_number[4] =
|
||||
{
|
||||
{ "Attached", "THREAD_NETWORK_STATE__Attached", 0 },
|
||||
{ "Attaching", "THREAD_NETWORK_STATE__Attaching", 1 },
|
||||
{ "Dettached", "THREAD_NETWORK_STATE__Dettached", 2 },
|
||||
{ "AttachingFailed", "THREAD_NETWORK_STATE__AttachingFailed", 3 },
|
||||
};
|
||||
static const ProtobufCIntRange thread_network_state__value_ranges[] = {
|
||||
{0, 0},{0, 4}
|
||||
};
|
||||
static const ProtobufCEnumValueIndex thread_network_state__enum_values_by_name[4] =
|
||||
{
|
||||
{ "Attached", 0 },
|
||||
{ "Attaching", 1 },
|
||||
{ "AttachingFailed", 3 },
|
||||
{ "Dettached", 2 },
|
||||
};
|
||||
const ProtobufCEnumDescriptor thread_network_state__descriptor =
|
||||
{
|
||||
PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,
|
||||
"ThreadNetworkState",
|
||||
"ThreadNetworkState",
|
||||
"ThreadNetworkState",
|
||||
"",
|
||||
4,
|
||||
thread_network_state__enum_values_by_number,
|
||||
4,
|
||||
thread_network_state__enum_values_by_name,
|
||||
1,
|
||||
thread_network_state__value_ranges,
|
||||
NULL,NULL,NULL,NULL /* reserved[1234] */
|
||||
};
|
||||
static const ProtobufCEnumValue thread_attach_failed_reason__enum_values_by_number[2] =
|
||||
{
|
||||
{ "DatasetInvalid", "THREAD_ATTACH_FAILED_REASON__DatasetInvalid", 0 },
|
||||
{ "ThreadNetworkNotFound", "THREAD_ATTACH_FAILED_REASON__ThreadNetworkNotFound", 1 },
|
||||
};
|
||||
static const ProtobufCIntRange thread_attach_failed_reason__value_ranges[] = {
|
||||
{0, 0},{0, 2}
|
||||
};
|
||||
static const ProtobufCEnumValueIndex thread_attach_failed_reason__enum_values_by_name[2] =
|
||||
{
|
||||
{ "DatasetInvalid", 0 },
|
||||
{ "ThreadNetworkNotFound", 1 },
|
||||
};
|
||||
const ProtobufCEnumDescriptor thread_attach_failed_reason__descriptor =
|
||||
{
|
||||
PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,
|
||||
"ThreadAttachFailedReason",
|
||||
"ThreadAttachFailedReason",
|
||||
"ThreadAttachFailedReason",
|
||||
"",
|
||||
2,
|
||||
thread_attach_failed_reason__enum_values_by_number,
|
||||
2,
|
||||
thread_attach_failed_reason__enum_values_by_name,
|
||||
1,
|
||||
thread_attach_failed_reason__value_ranges,
|
||||
NULL,NULL,NULL,NULL /* reserved[1234] */
|
||||
};
|
||||
@@ -0,0 +1,186 @@
|
||||
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
|
||||
/* Generated from: network_constants.proto */
|
||||
|
||||
#ifndef PROTOBUF_C_network_5fconstants_2eproto__INCLUDED
|
||||
#define PROTOBUF_C_network_5fconstants_2eproto__INCLUDED
|
||||
|
||||
#include <protobuf-c/protobuf-c.h>
|
||||
|
||||
PROTOBUF_C__BEGIN_DECLS
|
||||
|
||||
#if PROTOBUF_C_VERSION_NUMBER < 1003000
|
||||
# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
|
||||
#elif 1004000 < PROTOBUF_C_MIN_COMPILER_VERSION
|
||||
# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct WifiConnectedState WifiConnectedState;
|
||||
typedef struct WifiAttemptFailed WifiAttemptFailed;
|
||||
typedef struct ThreadAttachState ThreadAttachState;
|
||||
|
||||
|
||||
/* --- enums --- */
|
||||
|
||||
typedef enum _WifiStationState {
|
||||
WIFI_STATION_STATE__Connected = 0,
|
||||
WIFI_STATION_STATE__Connecting = 1,
|
||||
WIFI_STATION_STATE__Disconnected = 2,
|
||||
WIFI_STATION_STATE__ConnectionFailed = 3
|
||||
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(WIFI_STATION_STATE)
|
||||
} WifiStationState;
|
||||
typedef enum _WifiConnectFailedReason {
|
||||
WIFI_CONNECT_FAILED_REASON__AuthError = 0,
|
||||
WIFI_CONNECT_FAILED_REASON__WifiNetworkNotFound = 1
|
||||
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(WIFI_CONNECT_FAILED_REASON)
|
||||
} WifiConnectFailedReason;
|
||||
typedef enum _WifiAuthMode {
|
||||
WIFI_AUTH_MODE__Open = 0,
|
||||
WIFI_AUTH_MODE__WEP = 1,
|
||||
WIFI_AUTH_MODE__WPA_PSK = 2,
|
||||
WIFI_AUTH_MODE__WPA2_PSK = 3,
|
||||
WIFI_AUTH_MODE__WPA_WPA2_PSK = 4,
|
||||
WIFI_AUTH_MODE__WPA2_ENTERPRISE = 5,
|
||||
WIFI_AUTH_MODE__WPA3_PSK = 6,
|
||||
WIFI_AUTH_MODE__WPA2_WPA3_PSK = 7
|
||||
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(WIFI_AUTH_MODE)
|
||||
} WifiAuthMode;
|
||||
typedef enum _ThreadNetworkState {
|
||||
THREAD_NETWORK_STATE__Attached = 0,
|
||||
THREAD_NETWORK_STATE__Attaching = 1,
|
||||
THREAD_NETWORK_STATE__Dettached = 2,
|
||||
THREAD_NETWORK_STATE__AttachingFailed = 3
|
||||
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(THREAD_NETWORK_STATE)
|
||||
} ThreadNetworkState;
|
||||
typedef enum _ThreadAttachFailedReason {
|
||||
THREAD_ATTACH_FAILED_REASON__DatasetInvalid = 0,
|
||||
THREAD_ATTACH_FAILED_REASON__ThreadNetworkNotFound = 1
|
||||
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(THREAD_ATTACH_FAILED_REASON)
|
||||
} ThreadAttachFailedReason;
|
||||
|
||||
/* --- messages --- */
|
||||
|
||||
struct WifiConnectedState
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
char *ip4_addr;
|
||||
WifiAuthMode auth_mode;
|
||||
ProtobufCBinaryData ssid;
|
||||
ProtobufCBinaryData bssid;
|
||||
int32_t channel;
|
||||
};
|
||||
#define WIFI_CONNECTED_STATE__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&wifi_connected_state__descriptor) \
|
||||
, (char *)protobuf_c_empty_string, WIFI_AUTH_MODE__Open, {0,NULL}, {0,NULL}, 0 }
|
||||
|
||||
|
||||
struct WifiAttemptFailed
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
uint32_t attempts_remaining;
|
||||
};
|
||||
#define WIFI_ATTEMPT_FAILED__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&wifi_attempt_failed__descriptor) \
|
||||
, 0 }
|
||||
|
||||
|
||||
struct ThreadAttachState
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
uint32_t pan_id;
|
||||
ProtobufCBinaryData ext_pan_id;
|
||||
uint32_t channel;
|
||||
char *name;
|
||||
};
|
||||
#define THREAD_ATTACH_STATE__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&thread_attach_state__descriptor) \
|
||||
, 0, {0,NULL}, 0, (char *)protobuf_c_empty_string }
|
||||
|
||||
|
||||
/* WifiConnectedState methods */
|
||||
void wifi_connected_state__init
|
||||
(WifiConnectedState *message);
|
||||
size_t wifi_connected_state__get_packed_size
|
||||
(const WifiConnectedState *message);
|
||||
size_t wifi_connected_state__pack
|
||||
(const WifiConnectedState *message,
|
||||
uint8_t *out);
|
||||
size_t wifi_connected_state__pack_to_buffer
|
||||
(const WifiConnectedState *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
WifiConnectedState *
|
||||
wifi_connected_state__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void wifi_connected_state__free_unpacked
|
||||
(WifiConnectedState *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* WifiAttemptFailed methods */
|
||||
void wifi_attempt_failed__init
|
||||
(WifiAttemptFailed *message);
|
||||
size_t wifi_attempt_failed__get_packed_size
|
||||
(const WifiAttemptFailed *message);
|
||||
size_t wifi_attempt_failed__pack
|
||||
(const WifiAttemptFailed *message,
|
||||
uint8_t *out);
|
||||
size_t wifi_attempt_failed__pack_to_buffer
|
||||
(const WifiAttemptFailed *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
WifiAttemptFailed *
|
||||
wifi_attempt_failed__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void wifi_attempt_failed__free_unpacked
|
||||
(WifiAttemptFailed *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* ThreadAttachState methods */
|
||||
void thread_attach_state__init
|
||||
(ThreadAttachState *message);
|
||||
size_t thread_attach_state__get_packed_size
|
||||
(const ThreadAttachState *message);
|
||||
size_t thread_attach_state__pack
|
||||
(const ThreadAttachState *message,
|
||||
uint8_t *out);
|
||||
size_t thread_attach_state__pack_to_buffer
|
||||
(const ThreadAttachState *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
ThreadAttachState *
|
||||
thread_attach_state__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void thread_attach_state__free_unpacked
|
||||
(ThreadAttachState *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* --- per-message closures --- */
|
||||
|
||||
typedef void (*WifiConnectedState_Closure)
|
||||
(const WifiConnectedState *message,
|
||||
void *closure_data);
|
||||
typedef void (*WifiAttemptFailed_Closure)
|
||||
(const WifiAttemptFailed *message,
|
||||
void *closure_data);
|
||||
typedef void (*ThreadAttachState_Closure)
|
||||
(const ThreadAttachState *message,
|
||||
void *closure_data);
|
||||
|
||||
/* --- services --- */
|
||||
|
||||
|
||||
/* --- descriptors --- */
|
||||
|
||||
extern const ProtobufCEnumDescriptor wifi_station_state__descriptor;
|
||||
extern const ProtobufCEnumDescriptor wifi_connect_failed_reason__descriptor;
|
||||
extern const ProtobufCEnumDescriptor wifi_auth_mode__descriptor;
|
||||
extern const ProtobufCEnumDescriptor thread_network_state__descriptor;
|
||||
extern const ProtobufCEnumDescriptor thread_attach_failed_reason__descriptor;
|
||||
extern const ProtobufCMessageDescriptor wifi_connected_state__descriptor;
|
||||
extern const ProtobufCMessageDescriptor wifi_attempt_failed__descriptor;
|
||||
extern const ProtobufCMessageDescriptor thread_attach_state__descriptor;
|
||||
|
||||
PROTOBUF_C__END_DECLS
|
||||
|
||||
|
||||
#endif /* PROTOBUF_C_network_5fconstants_2eproto__INCLUDED */
|
||||
@@ -0,0 +1,756 @@
|
||||
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
|
||||
/* Generated from: network_ctrl.proto */
|
||||
|
||||
/* Do not generate deprecated warnings for self */
|
||||
#ifndef PROTOBUF_C__NO_DEPRECATED
|
||||
#define PROTOBUF_C__NO_DEPRECATED
|
||||
#endif
|
||||
|
||||
#include "network_ctrl.pb-c.h"
|
||||
void cmd_ctrl_wifi_reset__init
|
||||
(CmdCtrlWifiReset *message)
|
||||
{
|
||||
static const CmdCtrlWifiReset init_value = CMD_CTRL_WIFI_RESET__INIT;
|
||||
*message = init_value;
|
||||
}
|
||||
size_t cmd_ctrl_wifi_reset__get_packed_size
|
||||
(const CmdCtrlWifiReset *message)
|
||||
{
|
||||
assert(message->base.descriptor == &cmd_ctrl_wifi_reset__descriptor);
|
||||
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
||||
}
|
||||
size_t cmd_ctrl_wifi_reset__pack
|
||||
(const CmdCtrlWifiReset *message,
|
||||
uint8_t *out)
|
||||
{
|
||||
assert(message->base.descriptor == &cmd_ctrl_wifi_reset__descriptor);
|
||||
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
||||
}
|
||||
size_t cmd_ctrl_wifi_reset__pack_to_buffer
|
||||
(const CmdCtrlWifiReset *message,
|
||||
ProtobufCBuffer *buffer)
|
||||
{
|
||||
assert(message->base.descriptor == &cmd_ctrl_wifi_reset__descriptor);
|
||||
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
||||
}
|
||||
CmdCtrlWifiReset *
|
||||
cmd_ctrl_wifi_reset__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data)
|
||||
{
|
||||
return (CmdCtrlWifiReset *)
|
||||
protobuf_c_message_unpack (&cmd_ctrl_wifi_reset__descriptor,
|
||||
allocator, len, data);
|
||||
}
|
||||
void cmd_ctrl_wifi_reset__free_unpacked
|
||||
(CmdCtrlWifiReset *message,
|
||||
ProtobufCAllocator *allocator)
|
||||
{
|
||||
if(!message)
|
||||
return;
|
||||
assert(message->base.descriptor == &cmd_ctrl_wifi_reset__descriptor);
|
||||
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
||||
}
|
||||
void resp_ctrl_wifi_reset__init
|
||||
(RespCtrlWifiReset *message)
|
||||
{
|
||||
static const RespCtrlWifiReset init_value = RESP_CTRL_WIFI_RESET__INIT;
|
||||
*message = init_value;
|
||||
}
|
||||
size_t resp_ctrl_wifi_reset__get_packed_size
|
||||
(const RespCtrlWifiReset *message)
|
||||
{
|
||||
assert(message->base.descriptor == &resp_ctrl_wifi_reset__descriptor);
|
||||
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
||||
}
|
||||
size_t resp_ctrl_wifi_reset__pack
|
||||
(const RespCtrlWifiReset *message,
|
||||
uint8_t *out)
|
||||
{
|
||||
assert(message->base.descriptor == &resp_ctrl_wifi_reset__descriptor);
|
||||
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
||||
}
|
||||
size_t resp_ctrl_wifi_reset__pack_to_buffer
|
||||
(const RespCtrlWifiReset *message,
|
||||
ProtobufCBuffer *buffer)
|
||||
{
|
||||
assert(message->base.descriptor == &resp_ctrl_wifi_reset__descriptor);
|
||||
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
||||
}
|
||||
RespCtrlWifiReset *
|
||||
resp_ctrl_wifi_reset__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data)
|
||||
{
|
||||
return (RespCtrlWifiReset *)
|
||||
protobuf_c_message_unpack (&resp_ctrl_wifi_reset__descriptor,
|
||||
allocator, len, data);
|
||||
}
|
||||
void resp_ctrl_wifi_reset__free_unpacked
|
||||
(RespCtrlWifiReset *message,
|
||||
ProtobufCAllocator *allocator)
|
||||
{
|
||||
if(!message)
|
||||
return;
|
||||
assert(message->base.descriptor == &resp_ctrl_wifi_reset__descriptor);
|
||||
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
||||
}
|
||||
void cmd_ctrl_wifi_reprov__init
|
||||
(CmdCtrlWifiReprov *message)
|
||||
{
|
||||
static const CmdCtrlWifiReprov init_value = CMD_CTRL_WIFI_REPROV__INIT;
|
||||
*message = init_value;
|
||||
}
|
||||
size_t cmd_ctrl_wifi_reprov__get_packed_size
|
||||
(const CmdCtrlWifiReprov *message)
|
||||
{
|
||||
assert(message->base.descriptor == &cmd_ctrl_wifi_reprov__descriptor);
|
||||
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
||||
}
|
||||
size_t cmd_ctrl_wifi_reprov__pack
|
||||
(const CmdCtrlWifiReprov *message,
|
||||
uint8_t *out)
|
||||
{
|
||||
assert(message->base.descriptor == &cmd_ctrl_wifi_reprov__descriptor);
|
||||
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
||||
}
|
||||
size_t cmd_ctrl_wifi_reprov__pack_to_buffer
|
||||
(const CmdCtrlWifiReprov *message,
|
||||
ProtobufCBuffer *buffer)
|
||||
{
|
||||
assert(message->base.descriptor == &cmd_ctrl_wifi_reprov__descriptor);
|
||||
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
||||
}
|
||||
CmdCtrlWifiReprov *
|
||||
cmd_ctrl_wifi_reprov__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data)
|
||||
{
|
||||
return (CmdCtrlWifiReprov *)
|
||||
protobuf_c_message_unpack (&cmd_ctrl_wifi_reprov__descriptor,
|
||||
allocator, len, data);
|
||||
}
|
||||
void cmd_ctrl_wifi_reprov__free_unpacked
|
||||
(CmdCtrlWifiReprov *message,
|
||||
ProtobufCAllocator *allocator)
|
||||
{
|
||||
if(!message)
|
||||
return;
|
||||
assert(message->base.descriptor == &cmd_ctrl_wifi_reprov__descriptor);
|
||||
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
||||
}
|
||||
void resp_ctrl_wifi_reprov__init
|
||||
(RespCtrlWifiReprov *message)
|
||||
{
|
||||
static const RespCtrlWifiReprov init_value = RESP_CTRL_WIFI_REPROV__INIT;
|
||||
*message = init_value;
|
||||
}
|
||||
size_t resp_ctrl_wifi_reprov__get_packed_size
|
||||
(const RespCtrlWifiReprov *message)
|
||||
{
|
||||
assert(message->base.descriptor == &resp_ctrl_wifi_reprov__descriptor);
|
||||
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
||||
}
|
||||
size_t resp_ctrl_wifi_reprov__pack
|
||||
(const RespCtrlWifiReprov *message,
|
||||
uint8_t *out)
|
||||
{
|
||||
assert(message->base.descriptor == &resp_ctrl_wifi_reprov__descriptor);
|
||||
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
||||
}
|
||||
size_t resp_ctrl_wifi_reprov__pack_to_buffer
|
||||
(const RespCtrlWifiReprov *message,
|
||||
ProtobufCBuffer *buffer)
|
||||
{
|
||||
assert(message->base.descriptor == &resp_ctrl_wifi_reprov__descriptor);
|
||||
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
||||
}
|
||||
RespCtrlWifiReprov *
|
||||
resp_ctrl_wifi_reprov__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data)
|
||||
{
|
||||
return (RespCtrlWifiReprov *)
|
||||
protobuf_c_message_unpack (&resp_ctrl_wifi_reprov__descriptor,
|
||||
allocator, len, data);
|
||||
}
|
||||
void resp_ctrl_wifi_reprov__free_unpacked
|
||||
(RespCtrlWifiReprov *message,
|
||||
ProtobufCAllocator *allocator)
|
||||
{
|
||||
if(!message)
|
||||
return;
|
||||
assert(message->base.descriptor == &resp_ctrl_wifi_reprov__descriptor);
|
||||
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
||||
}
|
||||
void cmd_ctrl_thread_reset__init
|
||||
(CmdCtrlThreadReset *message)
|
||||
{
|
||||
static const CmdCtrlThreadReset init_value = CMD_CTRL_THREAD_RESET__INIT;
|
||||
*message = init_value;
|
||||
}
|
||||
size_t cmd_ctrl_thread_reset__get_packed_size
|
||||
(const CmdCtrlThreadReset *message)
|
||||
{
|
||||
assert(message->base.descriptor == &cmd_ctrl_thread_reset__descriptor);
|
||||
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
||||
}
|
||||
size_t cmd_ctrl_thread_reset__pack
|
||||
(const CmdCtrlThreadReset *message,
|
||||
uint8_t *out)
|
||||
{
|
||||
assert(message->base.descriptor == &cmd_ctrl_thread_reset__descriptor);
|
||||
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
||||
}
|
||||
size_t cmd_ctrl_thread_reset__pack_to_buffer
|
||||
(const CmdCtrlThreadReset *message,
|
||||
ProtobufCBuffer *buffer)
|
||||
{
|
||||
assert(message->base.descriptor == &cmd_ctrl_thread_reset__descriptor);
|
||||
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
||||
}
|
||||
CmdCtrlThreadReset *
|
||||
cmd_ctrl_thread_reset__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data)
|
||||
{
|
||||
return (CmdCtrlThreadReset *)
|
||||
protobuf_c_message_unpack (&cmd_ctrl_thread_reset__descriptor,
|
||||
allocator, len, data);
|
||||
}
|
||||
void cmd_ctrl_thread_reset__free_unpacked
|
||||
(CmdCtrlThreadReset *message,
|
||||
ProtobufCAllocator *allocator)
|
||||
{
|
||||
if(!message)
|
||||
return;
|
||||
assert(message->base.descriptor == &cmd_ctrl_thread_reset__descriptor);
|
||||
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
||||
}
|
||||
void resp_ctrl_thread_reset__init
|
||||
(RespCtrlThreadReset *message)
|
||||
{
|
||||
static const RespCtrlThreadReset init_value = RESP_CTRL_THREAD_RESET__INIT;
|
||||
*message = init_value;
|
||||
}
|
||||
size_t resp_ctrl_thread_reset__get_packed_size
|
||||
(const RespCtrlThreadReset *message)
|
||||
{
|
||||
assert(message->base.descriptor == &resp_ctrl_thread_reset__descriptor);
|
||||
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
||||
}
|
||||
size_t resp_ctrl_thread_reset__pack
|
||||
(const RespCtrlThreadReset *message,
|
||||
uint8_t *out)
|
||||
{
|
||||
assert(message->base.descriptor == &resp_ctrl_thread_reset__descriptor);
|
||||
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
||||
}
|
||||
size_t resp_ctrl_thread_reset__pack_to_buffer
|
||||
(const RespCtrlThreadReset *message,
|
||||
ProtobufCBuffer *buffer)
|
||||
{
|
||||
assert(message->base.descriptor == &resp_ctrl_thread_reset__descriptor);
|
||||
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
||||
}
|
||||
RespCtrlThreadReset *
|
||||
resp_ctrl_thread_reset__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data)
|
||||
{
|
||||
return (RespCtrlThreadReset *)
|
||||
protobuf_c_message_unpack (&resp_ctrl_thread_reset__descriptor,
|
||||
allocator, len, data);
|
||||
}
|
||||
void resp_ctrl_thread_reset__free_unpacked
|
||||
(RespCtrlThreadReset *message,
|
||||
ProtobufCAllocator *allocator)
|
||||
{
|
||||
if(!message)
|
||||
return;
|
||||
assert(message->base.descriptor == &resp_ctrl_thread_reset__descriptor);
|
||||
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
||||
}
|
||||
void cmd_ctrl_thread_reprov__init
|
||||
(CmdCtrlThreadReprov *message)
|
||||
{
|
||||
static const CmdCtrlThreadReprov init_value = CMD_CTRL_THREAD_REPROV__INIT;
|
||||
*message = init_value;
|
||||
}
|
||||
size_t cmd_ctrl_thread_reprov__get_packed_size
|
||||
(const CmdCtrlThreadReprov *message)
|
||||
{
|
||||
assert(message->base.descriptor == &cmd_ctrl_thread_reprov__descriptor);
|
||||
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
||||
}
|
||||
size_t cmd_ctrl_thread_reprov__pack
|
||||
(const CmdCtrlThreadReprov *message,
|
||||
uint8_t *out)
|
||||
{
|
||||
assert(message->base.descriptor == &cmd_ctrl_thread_reprov__descriptor);
|
||||
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
||||
}
|
||||
size_t cmd_ctrl_thread_reprov__pack_to_buffer
|
||||
(const CmdCtrlThreadReprov *message,
|
||||
ProtobufCBuffer *buffer)
|
||||
{
|
||||
assert(message->base.descriptor == &cmd_ctrl_thread_reprov__descriptor);
|
||||
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
||||
}
|
||||
CmdCtrlThreadReprov *
|
||||
cmd_ctrl_thread_reprov__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data)
|
||||
{
|
||||
return (CmdCtrlThreadReprov *)
|
||||
protobuf_c_message_unpack (&cmd_ctrl_thread_reprov__descriptor,
|
||||
allocator, len, data);
|
||||
}
|
||||
void cmd_ctrl_thread_reprov__free_unpacked
|
||||
(CmdCtrlThreadReprov *message,
|
||||
ProtobufCAllocator *allocator)
|
||||
{
|
||||
if(!message)
|
||||
return;
|
||||
assert(message->base.descriptor == &cmd_ctrl_thread_reprov__descriptor);
|
||||
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
||||
}
|
||||
void resp_ctrl_thread_reprov__init
|
||||
(RespCtrlThreadReprov *message)
|
||||
{
|
||||
static const RespCtrlThreadReprov init_value = RESP_CTRL_THREAD_REPROV__INIT;
|
||||
*message = init_value;
|
||||
}
|
||||
size_t resp_ctrl_thread_reprov__get_packed_size
|
||||
(const RespCtrlThreadReprov *message)
|
||||
{
|
||||
assert(message->base.descriptor == &resp_ctrl_thread_reprov__descriptor);
|
||||
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
||||
}
|
||||
size_t resp_ctrl_thread_reprov__pack
|
||||
(const RespCtrlThreadReprov *message,
|
||||
uint8_t *out)
|
||||
{
|
||||
assert(message->base.descriptor == &resp_ctrl_thread_reprov__descriptor);
|
||||
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
||||
}
|
||||
size_t resp_ctrl_thread_reprov__pack_to_buffer
|
||||
(const RespCtrlThreadReprov *message,
|
||||
ProtobufCBuffer *buffer)
|
||||
{
|
||||
assert(message->base.descriptor == &resp_ctrl_thread_reprov__descriptor);
|
||||
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
||||
}
|
||||
RespCtrlThreadReprov *
|
||||
resp_ctrl_thread_reprov__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data)
|
||||
{
|
||||
return (RespCtrlThreadReprov *)
|
||||
protobuf_c_message_unpack (&resp_ctrl_thread_reprov__descriptor,
|
||||
allocator, len, data);
|
||||
}
|
||||
void resp_ctrl_thread_reprov__free_unpacked
|
||||
(RespCtrlThreadReprov *message,
|
||||
ProtobufCAllocator *allocator)
|
||||
{
|
||||
if(!message)
|
||||
return;
|
||||
assert(message->base.descriptor == &resp_ctrl_thread_reprov__descriptor);
|
||||
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
||||
}
|
||||
void network_ctrl_payload__init
|
||||
(NetworkCtrlPayload *message)
|
||||
{
|
||||
static const NetworkCtrlPayload init_value = NETWORK_CTRL_PAYLOAD__INIT;
|
||||
*message = init_value;
|
||||
}
|
||||
size_t network_ctrl_payload__get_packed_size
|
||||
(const NetworkCtrlPayload *message)
|
||||
{
|
||||
assert(message->base.descriptor == &network_ctrl_payload__descriptor);
|
||||
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
|
||||
}
|
||||
size_t network_ctrl_payload__pack
|
||||
(const NetworkCtrlPayload *message,
|
||||
uint8_t *out)
|
||||
{
|
||||
assert(message->base.descriptor == &network_ctrl_payload__descriptor);
|
||||
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
|
||||
}
|
||||
size_t network_ctrl_payload__pack_to_buffer
|
||||
(const NetworkCtrlPayload *message,
|
||||
ProtobufCBuffer *buffer)
|
||||
{
|
||||
assert(message->base.descriptor == &network_ctrl_payload__descriptor);
|
||||
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
|
||||
}
|
||||
NetworkCtrlPayload *
|
||||
network_ctrl_payload__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data)
|
||||
{
|
||||
return (NetworkCtrlPayload *)
|
||||
protobuf_c_message_unpack (&network_ctrl_payload__descriptor,
|
||||
allocator, len, data);
|
||||
}
|
||||
void network_ctrl_payload__free_unpacked
|
||||
(NetworkCtrlPayload *message,
|
||||
ProtobufCAllocator *allocator)
|
||||
{
|
||||
if(!message)
|
||||
return;
|
||||
assert(message->base.descriptor == &network_ctrl_payload__descriptor);
|
||||
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
|
||||
}
|
||||
#define cmd_ctrl_wifi_reset__field_descriptors NULL
|
||||
#define cmd_ctrl_wifi_reset__field_indices_by_name NULL
|
||||
#define cmd_ctrl_wifi_reset__number_ranges NULL
|
||||
const ProtobufCMessageDescriptor cmd_ctrl_wifi_reset__descriptor =
|
||||
{
|
||||
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
||||
"CmdCtrlWifiReset",
|
||||
"CmdCtrlWifiReset",
|
||||
"CmdCtrlWifiReset",
|
||||
"",
|
||||
sizeof(CmdCtrlWifiReset),
|
||||
0,
|
||||
cmd_ctrl_wifi_reset__field_descriptors,
|
||||
cmd_ctrl_wifi_reset__field_indices_by_name,
|
||||
0, cmd_ctrl_wifi_reset__number_ranges,
|
||||
(ProtobufCMessageInit) cmd_ctrl_wifi_reset__init,
|
||||
NULL,NULL,NULL /* reserved[123] */
|
||||
};
|
||||
#define resp_ctrl_wifi_reset__field_descriptors NULL
|
||||
#define resp_ctrl_wifi_reset__field_indices_by_name NULL
|
||||
#define resp_ctrl_wifi_reset__number_ranges NULL
|
||||
const ProtobufCMessageDescriptor resp_ctrl_wifi_reset__descriptor =
|
||||
{
|
||||
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
||||
"RespCtrlWifiReset",
|
||||
"RespCtrlWifiReset",
|
||||
"RespCtrlWifiReset",
|
||||
"",
|
||||
sizeof(RespCtrlWifiReset),
|
||||
0,
|
||||
resp_ctrl_wifi_reset__field_descriptors,
|
||||
resp_ctrl_wifi_reset__field_indices_by_name,
|
||||
0, resp_ctrl_wifi_reset__number_ranges,
|
||||
(ProtobufCMessageInit) resp_ctrl_wifi_reset__init,
|
||||
NULL,NULL,NULL /* reserved[123] */
|
||||
};
|
||||
#define cmd_ctrl_wifi_reprov__field_descriptors NULL
|
||||
#define cmd_ctrl_wifi_reprov__field_indices_by_name NULL
|
||||
#define cmd_ctrl_wifi_reprov__number_ranges NULL
|
||||
const ProtobufCMessageDescriptor cmd_ctrl_wifi_reprov__descriptor =
|
||||
{
|
||||
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
||||
"CmdCtrlWifiReprov",
|
||||
"CmdCtrlWifiReprov",
|
||||
"CmdCtrlWifiReprov",
|
||||
"",
|
||||
sizeof(CmdCtrlWifiReprov),
|
||||
0,
|
||||
cmd_ctrl_wifi_reprov__field_descriptors,
|
||||
cmd_ctrl_wifi_reprov__field_indices_by_name,
|
||||
0, cmd_ctrl_wifi_reprov__number_ranges,
|
||||
(ProtobufCMessageInit) cmd_ctrl_wifi_reprov__init,
|
||||
NULL,NULL,NULL /* reserved[123] */
|
||||
};
|
||||
#define resp_ctrl_wifi_reprov__field_descriptors NULL
|
||||
#define resp_ctrl_wifi_reprov__field_indices_by_name NULL
|
||||
#define resp_ctrl_wifi_reprov__number_ranges NULL
|
||||
const ProtobufCMessageDescriptor resp_ctrl_wifi_reprov__descriptor =
|
||||
{
|
||||
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
||||
"RespCtrlWifiReprov",
|
||||
"RespCtrlWifiReprov",
|
||||
"RespCtrlWifiReprov",
|
||||
"",
|
||||
sizeof(RespCtrlWifiReprov),
|
||||
0,
|
||||
resp_ctrl_wifi_reprov__field_descriptors,
|
||||
resp_ctrl_wifi_reprov__field_indices_by_name,
|
||||
0, resp_ctrl_wifi_reprov__number_ranges,
|
||||
(ProtobufCMessageInit) resp_ctrl_wifi_reprov__init,
|
||||
NULL,NULL,NULL /* reserved[123] */
|
||||
};
|
||||
#define cmd_ctrl_thread_reset__field_descriptors NULL
|
||||
#define cmd_ctrl_thread_reset__field_indices_by_name NULL
|
||||
#define cmd_ctrl_thread_reset__number_ranges NULL
|
||||
const ProtobufCMessageDescriptor cmd_ctrl_thread_reset__descriptor =
|
||||
{
|
||||
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
||||
"CmdCtrlThreadReset",
|
||||
"CmdCtrlThreadReset",
|
||||
"CmdCtrlThreadReset",
|
||||
"",
|
||||
sizeof(CmdCtrlThreadReset),
|
||||
0,
|
||||
cmd_ctrl_thread_reset__field_descriptors,
|
||||
cmd_ctrl_thread_reset__field_indices_by_name,
|
||||
0, cmd_ctrl_thread_reset__number_ranges,
|
||||
(ProtobufCMessageInit) cmd_ctrl_thread_reset__init,
|
||||
NULL,NULL,NULL /* reserved[123] */
|
||||
};
|
||||
#define resp_ctrl_thread_reset__field_descriptors NULL
|
||||
#define resp_ctrl_thread_reset__field_indices_by_name NULL
|
||||
#define resp_ctrl_thread_reset__number_ranges NULL
|
||||
const ProtobufCMessageDescriptor resp_ctrl_thread_reset__descriptor =
|
||||
{
|
||||
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
||||
"RespCtrlThreadReset",
|
||||
"RespCtrlThreadReset",
|
||||
"RespCtrlThreadReset",
|
||||
"",
|
||||
sizeof(RespCtrlThreadReset),
|
||||
0,
|
||||
resp_ctrl_thread_reset__field_descriptors,
|
||||
resp_ctrl_thread_reset__field_indices_by_name,
|
||||
0, resp_ctrl_thread_reset__number_ranges,
|
||||
(ProtobufCMessageInit) resp_ctrl_thread_reset__init,
|
||||
NULL,NULL,NULL /* reserved[123] */
|
||||
};
|
||||
#define cmd_ctrl_thread_reprov__field_descriptors NULL
|
||||
#define cmd_ctrl_thread_reprov__field_indices_by_name NULL
|
||||
#define cmd_ctrl_thread_reprov__number_ranges NULL
|
||||
const ProtobufCMessageDescriptor cmd_ctrl_thread_reprov__descriptor =
|
||||
{
|
||||
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
||||
"CmdCtrlThreadReprov",
|
||||
"CmdCtrlThreadReprov",
|
||||
"CmdCtrlThreadReprov",
|
||||
"",
|
||||
sizeof(CmdCtrlThreadReprov),
|
||||
0,
|
||||
cmd_ctrl_thread_reprov__field_descriptors,
|
||||
cmd_ctrl_thread_reprov__field_indices_by_name,
|
||||
0, cmd_ctrl_thread_reprov__number_ranges,
|
||||
(ProtobufCMessageInit) cmd_ctrl_thread_reprov__init,
|
||||
NULL,NULL,NULL /* reserved[123] */
|
||||
};
|
||||
#define resp_ctrl_thread_reprov__field_descriptors NULL
|
||||
#define resp_ctrl_thread_reprov__field_indices_by_name NULL
|
||||
#define resp_ctrl_thread_reprov__number_ranges NULL
|
||||
const ProtobufCMessageDescriptor resp_ctrl_thread_reprov__descriptor =
|
||||
{
|
||||
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
||||
"RespCtrlThreadReprov",
|
||||
"RespCtrlThreadReprov",
|
||||
"RespCtrlThreadReprov",
|
||||
"",
|
||||
sizeof(RespCtrlThreadReprov),
|
||||
0,
|
||||
resp_ctrl_thread_reprov__field_descriptors,
|
||||
resp_ctrl_thread_reprov__field_indices_by_name,
|
||||
0, resp_ctrl_thread_reprov__number_ranges,
|
||||
(ProtobufCMessageInit) resp_ctrl_thread_reprov__init,
|
||||
NULL,NULL,NULL /* reserved[123] */
|
||||
};
|
||||
static const ProtobufCFieldDescriptor network_ctrl_payload__field_descriptors[10] =
|
||||
{
|
||||
{
|
||||
"msg",
|
||||
1,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_ENUM,
|
||||
0, /* quantifier_offset */
|
||||
offsetof(NetworkCtrlPayload, msg),
|
||||
&network_ctrl_msg_type__descriptor,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"status",
|
||||
2,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_ENUM,
|
||||
0, /* quantifier_offset */
|
||||
offsetof(NetworkCtrlPayload, status),
|
||||
&status__descriptor,
|
||||
NULL,
|
||||
0, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"cmd_ctrl_wifi_reset",
|
||||
11,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_MESSAGE,
|
||||
offsetof(NetworkCtrlPayload, payload_case),
|
||||
offsetof(NetworkCtrlPayload, cmd_ctrl_wifi_reset),
|
||||
&cmd_ctrl_wifi_reset__descriptor,
|
||||
NULL,
|
||||
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"resp_ctrl_wifi_reset",
|
||||
12,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_MESSAGE,
|
||||
offsetof(NetworkCtrlPayload, payload_case),
|
||||
offsetof(NetworkCtrlPayload, resp_ctrl_wifi_reset),
|
||||
&resp_ctrl_wifi_reset__descriptor,
|
||||
NULL,
|
||||
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"cmd_ctrl_wifi_reprov",
|
||||
13,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_MESSAGE,
|
||||
offsetof(NetworkCtrlPayload, payload_case),
|
||||
offsetof(NetworkCtrlPayload, cmd_ctrl_wifi_reprov),
|
||||
&cmd_ctrl_wifi_reprov__descriptor,
|
||||
NULL,
|
||||
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"resp_ctrl_wifi_reprov",
|
||||
14,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_MESSAGE,
|
||||
offsetof(NetworkCtrlPayload, payload_case),
|
||||
offsetof(NetworkCtrlPayload, resp_ctrl_wifi_reprov),
|
||||
&resp_ctrl_wifi_reprov__descriptor,
|
||||
NULL,
|
||||
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"cmd_ctrl_thread_reset",
|
||||
15,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_MESSAGE,
|
||||
offsetof(NetworkCtrlPayload, payload_case),
|
||||
offsetof(NetworkCtrlPayload, cmd_ctrl_thread_reset),
|
||||
&cmd_ctrl_thread_reset__descriptor,
|
||||
NULL,
|
||||
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"resp_ctrl_thread_reset",
|
||||
16,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_MESSAGE,
|
||||
offsetof(NetworkCtrlPayload, payload_case),
|
||||
offsetof(NetworkCtrlPayload, resp_ctrl_thread_reset),
|
||||
&resp_ctrl_thread_reset__descriptor,
|
||||
NULL,
|
||||
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"cmd_ctrl_thread_reprov",
|
||||
17,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_MESSAGE,
|
||||
offsetof(NetworkCtrlPayload, payload_case),
|
||||
offsetof(NetworkCtrlPayload, cmd_ctrl_thread_reprov),
|
||||
&cmd_ctrl_thread_reprov__descriptor,
|
||||
NULL,
|
||||
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
{
|
||||
"resp_ctrl_thread_reprov",
|
||||
18,
|
||||
PROTOBUF_C_LABEL_NONE,
|
||||
PROTOBUF_C_TYPE_MESSAGE,
|
||||
offsetof(NetworkCtrlPayload, payload_case),
|
||||
offsetof(NetworkCtrlPayload, resp_ctrl_thread_reprov),
|
||||
&resp_ctrl_thread_reprov__descriptor,
|
||||
NULL,
|
||||
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
|
||||
0,NULL,NULL /* reserved1,reserved2, etc */
|
||||
},
|
||||
};
|
||||
static const unsigned network_ctrl_payload__field_indices_by_name[] = {
|
||||
8, /* field[8] = cmd_ctrl_thread_reprov */
|
||||
6, /* field[6] = cmd_ctrl_thread_reset */
|
||||
4, /* field[4] = cmd_ctrl_wifi_reprov */
|
||||
2, /* field[2] = cmd_ctrl_wifi_reset */
|
||||
0, /* field[0] = msg */
|
||||
9, /* field[9] = resp_ctrl_thread_reprov */
|
||||
7, /* field[7] = resp_ctrl_thread_reset */
|
||||
5, /* field[5] = resp_ctrl_wifi_reprov */
|
||||
3, /* field[3] = resp_ctrl_wifi_reset */
|
||||
1, /* field[1] = status */
|
||||
};
|
||||
static const ProtobufCIntRange network_ctrl_payload__number_ranges[2 + 1] =
|
||||
{
|
||||
{ 1, 0 },
|
||||
{ 11, 2 },
|
||||
{ 0, 10 }
|
||||
};
|
||||
const ProtobufCMessageDescriptor network_ctrl_payload__descriptor =
|
||||
{
|
||||
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
|
||||
"NetworkCtrlPayload",
|
||||
"NetworkCtrlPayload",
|
||||
"NetworkCtrlPayload",
|
||||
"",
|
||||
sizeof(NetworkCtrlPayload),
|
||||
10,
|
||||
network_ctrl_payload__field_descriptors,
|
||||
network_ctrl_payload__field_indices_by_name,
|
||||
2, network_ctrl_payload__number_ranges,
|
||||
(ProtobufCMessageInit) network_ctrl_payload__init,
|
||||
NULL,NULL,NULL /* reserved[123] */
|
||||
};
|
||||
static const ProtobufCEnumValue network_ctrl_msg_type__enum_values_by_number[9] =
|
||||
{
|
||||
{ "TypeCtrlReserved", "NETWORK_CTRL_MSG_TYPE__TypeCtrlReserved", 0 },
|
||||
{ "TypeCmdCtrlWifiReset", "NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlWifiReset", 1 },
|
||||
{ "TypeRespCtrlWifiReset", "NETWORK_CTRL_MSG_TYPE__TypeRespCtrlWifiReset", 2 },
|
||||
{ "TypeCmdCtrlWifiReprov", "NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlWifiReprov", 3 },
|
||||
{ "TypeRespCtrlWifiReprov", "NETWORK_CTRL_MSG_TYPE__TypeRespCtrlWifiReprov", 4 },
|
||||
{ "TypeCmdCtrlThreadReset", "NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlThreadReset", 5 },
|
||||
{ "TypeRespCtrlThreadReset", "NETWORK_CTRL_MSG_TYPE__TypeRespCtrlThreadReset", 6 },
|
||||
{ "TypeCmdCtrlThreadReprov", "NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlThreadReprov", 7 },
|
||||
{ "TypeRespCtrlThreadReprov", "NETWORK_CTRL_MSG_TYPE__TypeRespCtrlThreadReprov", 8 },
|
||||
};
|
||||
static const ProtobufCIntRange network_ctrl_msg_type__value_ranges[] = {
|
||||
{0, 0},{0, 9}
|
||||
};
|
||||
static const ProtobufCEnumValueIndex network_ctrl_msg_type__enum_values_by_name[9] =
|
||||
{
|
||||
{ "TypeCmdCtrlThreadReprov", 7 },
|
||||
{ "TypeCmdCtrlThreadReset", 5 },
|
||||
{ "TypeCmdCtrlWifiReprov", 3 },
|
||||
{ "TypeCmdCtrlWifiReset", 1 },
|
||||
{ "TypeCtrlReserved", 0 },
|
||||
{ "TypeRespCtrlThreadReprov", 8 },
|
||||
{ "TypeRespCtrlThreadReset", 6 },
|
||||
{ "TypeRespCtrlWifiReprov", 4 },
|
||||
{ "TypeRespCtrlWifiReset", 2 },
|
||||
};
|
||||
const ProtobufCEnumDescriptor network_ctrl_msg_type__descriptor =
|
||||
{
|
||||
PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,
|
||||
"NetworkCtrlMsgType",
|
||||
"NetworkCtrlMsgType",
|
||||
"NetworkCtrlMsgType",
|
||||
"",
|
||||
9,
|
||||
network_ctrl_msg_type__enum_values_by_number,
|
||||
9,
|
||||
network_ctrl_msg_type__enum_values_by_name,
|
||||
1,
|
||||
network_ctrl_msg_type__value_ranges,
|
||||
NULL,NULL,NULL,NULL /* reserved[1234] */
|
||||
};
|
||||
@@ -0,0 +1,374 @@
|
||||
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
|
||||
/* Generated from: network_ctrl.proto */
|
||||
|
||||
#ifndef PROTOBUF_C_network_5fctrl_2eproto__INCLUDED
|
||||
#define PROTOBUF_C_network_5fctrl_2eproto__INCLUDED
|
||||
|
||||
#include <protobuf-c/protobuf-c.h>
|
||||
|
||||
PROTOBUF_C__BEGIN_DECLS
|
||||
|
||||
#if PROTOBUF_C_VERSION_NUMBER < 1003000
|
||||
# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
|
||||
#elif 1004000 < PROTOBUF_C_MIN_COMPILER_VERSION
|
||||
# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
|
||||
#endif
|
||||
|
||||
#include "constants.pb-c.h"
|
||||
|
||||
typedef struct CmdCtrlWifiReset CmdCtrlWifiReset;
|
||||
typedef struct RespCtrlWifiReset RespCtrlWifiReset;
|
||||
typedef struct CmdCtrlWifiReprov CmdCtrlWifiReprov;
|
||||
typedef struct RespCtrlWifiReprov RespCtrlWifiReprov;
|
||||
typedef struct CmdCtrlThreadReset CmdCtrlThreadReset;
|
||||
typedef struct RespCtrlThreadReset RespCtrlThreadReset;
|
||||
typedef struct CmdCtrlThreadReprov CmdCtrlThreadReprov;
|
||||
typedef struct RespCtrlThreadReprov RespCtrlThreadReprov;
|
||||
typedef struct NetworkCtrlPayload NetworkCtrlPayload;
|
||||
|
||||
|
||||
/* --- enums --- */
|
||||
|
||||
typedef enum _NetworkCtrlMsgType {
|
||||
NETWORK_CTRL_MSG_TYPE__TypeCtrlReserved = 0,
|
||||
NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlWifiReset = 1,
|
||||
NETWORK_CTRL_MSG_TYPE__TypeRespCtrlWifiReset = 2,
|
||||
NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlWifiReprov = 3,
|
||||
NETWORK_CTRL_MSG_TYPE__TypeRespCtrlWifiReprov = 4,
|
||||
NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlThreadReset = 5,
|
||||
NETWORK_CTRL_MSG_TYPE__TypeRespCtrlThreadReset = 6,
|
||||
NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlThreadReprov = 7,
|
||||
NETWORK_CTRL_MSG_TYPE__TypeRespCtrlThreadReprov = 8
|
||||
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(NETWORK_CTRL_MSG_TYPE)
|
||||
} NetworkCtrlMsgType;
|
||||
|
||||
/* --- messages --- */
|
||||
|
||||
struct CmdCtrlWifiReset
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
};
|
||||
#define CMD_CTRL_WIFI_RESET__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&cmd_ctrl_wifi_reset__descriptor) \
|
||||
}
|
||||
|
||||
|
||||
struct RespCtrlWifiReset
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
};
|
||||
#define RESP_CTRL_WIFI_RESET__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&resp_ctrl_wifi_reset__descriptor) \
|
||||
}
|
||||
|
||||
|
||||
struct CmdCtrlWifiReprov
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
};
|
||||
#define CMD_CTRL_WIFI_REPROV__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&cmd_ctrl_wifi_reprov__descriptor) \
|
||||
}
|
||||
|
||||
|
||||
struct RespCtrlWifiReprov
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
};
|
||||
#define RESP_CTRL_WIFI_REPROV__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&resp_ctrl_wifi_reprov__descriptor) \
|
||||
}
|
||||
|
||||
|
||||
struct CmdCtrlThreadReset
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
};
|
||||
#define CMD_CTRL_THREAD_RESET__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&cmd_ctrl_thread_reset__descriptor) \
|
||||
}
|
||||
|
||||
|
||||
struct RespCtrlThreadReset
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
};
|
||||
#define RESP_CTRL_THREAD_RESET__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&resp_ctrl_thread_reset__descriptor) \
|
||||
}
|
||||
|
||||
|
||||
struct CmdCtrlThreadReprov
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
};
|
||||
#define CMD_CTRL_THREAD_REPROV__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&cmd_ctrl_thread_reprov__descriptor) \
|
||||
}
|
||||
|
||||
|
||||
struct RespCtrlThreadReprov
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
};
|
||||
#define RESP_CTRL_THREAD_REPROV__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&resp_ctrl_thread_reprov__descriptor) \
|
||||
}
|
||||
|
||||
|
||||
typedef enum {
|
||||
NETWORK_CTRL_PAYLOAD__PAYLOAD__NOT_SET = 0,
|
||||
NETWORK_CTRL_PAYLOAD__PAYLOAD_CMD_CTRL_WIFI_RESET = 11,
|
||||
NETWORK_CTRL_PAYLOAD__PAYLOAD_RESP_CTRL_WIFI_RESET = 12,
|
||||
NETWORK_CTRL_PAYLOAD__PAYLOAD_CMD_CTRL_WIFI_REPROV = 13,
|
||||
NETWORK_CTRL_PAYLOAD__PAYLOAD_RESP_CTRL_WIFI_REPROV = 14,
|
||||
NETWORK_CTRL_PAYLOAD__PAYLOAD_CMD_CTRL_THREAD_RESET = 15,
|
||||
NETWORK_CTRL_PAYLOAD__PAYLOAD_RESP_CTRL_THREAD_RESET = 16,
|
||||
NETWORK_CTRL_PAYLOAD__PAYLOAD_CMD_CTRL_THREAD_REPROV = 17,
|
||||
NETWORK_CTRL_PAYLOAD__PAYLOAD_RESP_CTRL_THREAD_REPROV = 18
|
||||
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(NETWORK_CTRL_PAYLOAD__PAYLOAD__CASE)
|
||||
} NetworkCtrlPayload__PayloadCase;
|
||||
|
||||
struct NetworkCtrlPayload
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
NetworkCtrlMsgType msg;
|
||||
Status status;
|
||||
NetworkCtrlPayload__PayloadCase payload_case;
|
||||
union {
|
||||
CmdCtrlWifiReset *cmd_ctrl_wifi_reset;
|
||||
RespCtrlWifiReset *resp_ctrl_wifi_reset;
|
||||
CmdCtrlWifiReprov *cmd_ctrl_wifi_reprov;
|
||||
RespCtrlWifiReprov *resp_ctrl_wifi_reprov;
|
||||
CmdCtrlThreadReset *cmd_ctrl_thread_reset;
|
||||
RespCtrlThreadReset *resp_ctrl_thread_reset;
|
||||
CmdCtrlThreadReprov *cmd_ctrl_thread_reprov;
|
||||
RespCtrlThreadReprov *resp_ctrl_thread_reprov;
|
||||
};
|
||||
};
|
||||
#define NETWORK_CTRL_PAYLOAD__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&network_ctrl_payload__descriptor) \
|
||||
, NETWORK_CTRL_MSG_TYPE__TypeCtrlReserved, STATUS__Success, NETWORK_CTRL_PAYLOAD__PAYLOAD__NOT_SET, {0} }
|
||||
|
||||
|
||||
/* CmdCtrlWifiReset methods */
|
||||
void cmd_ctrl_wifi_reset__init
|
||||
(CmdCtrlWifiReset *message);
|
||||
size_t cmd_ctrl_wifi_reset__get_packed_size
|
||||
(const CmdCtrlWifiReset *message);
|
||||
size_t cmd_ctrl_wifi_reset__pack
|
||||
(const CmdCtrlWifiReset *message,
|
||||
uint8_t *out);
|
||||
size_t cmd_ctrl_wifi_reset__pack_to_buffer
|
||||
(const CmdCtrlWifiReset *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
CmdCtrlWifiReset *
|
||||
cmd_ctrl_wifi_reset__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void cmd_ctrl_wifi_reset__free_unpacked
|
||||
(CmdCtrlWifiReset *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* RespCtrlWifiReset methods */
|
||||
void resp_ctrl_wifi_reset__init
|
||||
(RespCtrlWifiReset *message);
|
||||
size_t resp_ctrl_wifi_reset__get_packed_size
|
||||
(const RespCtrlWifiReset *message);
|
||||
size_t resp_ctrl_wifi_reset__pack
|
||||
(const RespCtrlWifiReset *message,
|
||||
uint8_t *out);
|
||||
size_t resp_ctrl_wifi_reset__pack_to_buffer
|
||||
(const RespCtrlWifiReset *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
RespCtrlWifiReset *
|
||||
resp_ctrl_wifi_reset__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void resp_ctrl_wifi_reset__free_unpacked
|
||||
(RespCtrlWifiReset *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* CmdCtrlWifiReprov methods */
|
||||
void cmd_ctrl_wifi_reprov__init
|
||||
(CmdCtrlWifiReprov *message);
|
||||
size_t cmd_ctrl_wifi_reprov__get_packed_size
|
||||
(const CmdCtrlWifiReprov *message);
|
||||
size_t cmd_ctrl_wifi_reprov__pack
|
||||
(const CmdCtrlWifiReprov *message,
|
||||
uint8_t *out);
|
||||
size_t cmd_ctrl_wifi_reprov__pack_to_buffer
|
||||
(const CmdCtrlWifiReprov *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
CmdCtrlWifiReprov *
|
||||
cmd_ctrl_wifi_reprov__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void cmd_ctrl_wifi_reprov__free_unpacked
|
||||
(CmdCtrlWifiReprov *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* RespCtrlWifiReprov methods */
|
||||
void resp_ctrl_wifi_reprov__init
|
||||
(RespCtrlWifiReprov *message);
|
||||
size_t resp_ctrl_wifi_reprov__get_packed_size
|
||||
(const RespCtrlWifiReprov *message);
|
||||
size_t resp_ctrl_wifi_reprov__pack
|
||||
(const RespCtrlWifiReprov *message,
|
||||
uint8_t *out);
|
||||
size_t resp_ctrl_wifi_reprov__pack_to_buffer
|
||||
(const RespCtrlWifiReprov *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
RespCtrlWifiReprov *
|
||||
resp_ctrl_wifi_reprov__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void resp_ctrl_wifi_reprov__free_unpacked
|
||||
(RespCtrlWifiReprov *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* CmdCtrlThreadReset methods */
|
||||
void cmd_ctrl_thread_reset__init
|
||||
(CmdCtrlThreadReset *message);
|
||||
size_t cmd_ctrl_thread_reset__get_packed_size
|
||||
(const CmdCtrlThreadReset *message);
|
||||
size_t cmd_ctrl_thread_reset__pack
|
||||
(const CmdCtrlThreadReset *message,
|
||||
uint8_t *out);
|
||||
size_t cmd_ctrl_thread_reset__pack_to_buffer
|
||||
(const CmdCtrlThreadReset *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
CmdCtrlThreadReset *
|
||||
cmd_ctrl_thread_reset__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void cmd_ctrl_thread_reset__free_unpacked
|
||||
(CmdCtrlThreadReset *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* RespCtrlThreadReset methods */
|
||||
void resp_ctrl_thread_reset__init
|
||||
(RespCtrlThreadReset *message);
|
||||
size_t resp_ctrl_thread_reset__get_packed_size
|
||||
(const RespCtrlThreadReset *message);
|
||||
size_t resp_ctrl_thread_reset__pack
|
||||
(const RespCtrlThreadReset *message,
|
||||
uint8_t *out);
|
||||
size_t resp_ctrl_thread_reset__pack_to_buffer
|
||||
(const RespCtrlThreadReset *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
RespCtrlThreadReset *
|
||||
resp_ctrl_thread_reset__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void resp_ctrl_thread_reset__free_unpacked
|
||||
(RespCtrlThreadReset *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* CmdCtrlThreadReprov methods */
|
||||
void cmd_ctrl_thread_reprov__init
|
||||
(CmdCtrlThreadReprov *message);
|
||||
size_t cmd_ctrl_thread_reprov__get_packed_size
|
||||
(const CmdCtrlThreadReprov *message);
|
||||
size_t cmd_ctrl_thread_reprov__pack
|
||||
(const CmdCtrlThreadReprov *message,
|
||||
uint8_t *out);
|
||||
size_t cmd_ctrl_thread_reprov__pack_to_buffer
|
||||
(const CmdCtrlThreadReprov *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
CmdCtrlThreadReprov *
|
||||
cmd_ctrl_thread_reprov__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void cmd_ctrl_thread_reprov__free_unpacked
|
||||
(CmdCtrlThreadReprov *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* RespCtrlThreadReprov methods */
|
||||
void resp_ctrl_thread_reprov__init
|
||||
(RespCtrlThreadReprov *message);
|
||||
size_t resp_ctrl_thread_reprov__get_packed_size
|
||||
(const RespCtrlThreadReprov *message);
|
||||
size_t resp_ctrl_thread_reprov__pack
|
||||
(const RespCtrlThreadReprov *message,
|
||||
uint8_t *out);
|
||||
size_t resp_ctrl_thread_reprov__pack_to_buffer
|
||||
(const RespCtrlThreadReprov *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
RespCtrlThreadReprov *
|
||||
resp_ctrl_thread_reprov__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void resp_ctrl_thread_reprov__free_unpacked
|
||||
(RespCtrlThreadReprov *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* NetworkCtrlPayload methods */
|
||||
void network_ctrl_payload__init
|
||||
(NetworkCtrlPayload *message);
|
||||
size_t network_ctrl_payload__get_packed_size
|
||||
(const NetworkCtrlPayload *message);
|
||||
size_t network_ctrl_payload__pack
|
||||
(const NetworkCtrlPayload *message,
|
||||
uint8_t *out);
|
||||
size_t network_ctrl_payload__pack_to_buffer
|
||||
(const NetworkCtrlPayload *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
NetworkCtrlPayload *
|
||||
network_ctrl_payload__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void network_ctrl_payload__free_unpacked
|
||||
(NetworkCtrlPayload *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* --- per-message closures --- */
|
||||
|
||||
typedef void (*CmdCtrlWifiReset_Closure)
|
||||
(const CmdCtrlWifiReset *message,
|
||||
void *closure_data);
|
||||
typedef void (*RespCtrlWifiReset_Closure)
|
||||
(const RespCtrlWifiReset *message,
|
||||
void *closure_data);
|
||||
typedef void (*CmdCtrlWifiReprov_Closure)
|
||||
(const CmdCtrlWifiReprov *message,
|
||||
void *closure_data);
|
||||
typedef void (*RespCtrlWifiReprov_Closure)
|
||||
(const RespCtrlWifiReprov *message,
|
||||
void *closure_data);
|
||||
typedef void (*CmdCtrlThreadReset_Closure)
|
||||
(const CmdCtrlThreadReset *message,
|
||||
void *closure_data);
|
||||
typedef void (*RespCtrlThreadReset_Closure)
|
||||
(const RespCtrlThreadReset *message,
|
||||
void *closure_data);
|
||||
typedef void (*CmdCtrlThreadReprov_Closure)
|
||||
(const CmdCtrlThreadReprov *message,
|
||||
void *closure_data);
|
||||
typedef void (*RespCtrlThreadReprov_Closure)
|
||||
(const RespCtrlThreadReprov *message,
|
||||
void *closure_data);
|
||||
typedef void (*NetworkCtrlPayload_Closure)
|
||||
(const NetworkCtrlPayload *message,
|
||||
void *closure_data);
|
||||
|
||||
/* --- services --- */
|
||||
|
||||
|
||||
/* --- descriptors --- */
|
||||
|
||||
extern const ProtobufCEnumDescriptor network_ctrl_msg_type__descriptor;
|
||||
extern const ProtobufCMessageDescriptor cmd_ctrl_wifi_reset__descriptor;
|
||||
extern const ProtobufCMessageDescriptor resp_ctrl_wifi_reset__descriptor;
|
||||
extern const ProtobufCMessageDescriptor cmd_ctrl_wifi_reprov__descriptor;
|
||||
extern const ProtobufCMessageDescriptor resp_ctrl_wifi_reprov__descriptor;
|
||||
extern const ProtobufCMessageDescriptor cmd_ctrl_thread_reset__descriptor;
|
||||
extern const ProtobufCMessageDescriptor resp_ctrl_thread_reset__descriptor;
|
||||
extern const ProtobufCMessageDescriptor cmd_ctrl_thread_reprov__descriptor;
|
||||
extern const ProtobufCMessageDescriptor resp_ctrl_thread_reprov__descriptor;
|
||||
extern const ProtobufCMessageDescriptor network_ctrl_payload__descriptor;
|
||||
|
||||
PROTOBUF_C__END_DECLS
|
||||
|
||||
|
||||
#endif /* PROTOBUF_C_network_5fctrl_2eproto__INCLUDED */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,614 @@
|
||||
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
|
||||
/* Generated from: network_scan.proto */
|
||||
|
||||
#ifndef PROTOBUF_C_network_5fscan_2eproto__INCLUDED
|
||||
#define PROTOBUF_C_network_5fscan_2eproto__INCLUDED
|
||||
|
||||
#include <protobuf-c/protobuf-c.h>
|
||||
|
||||
PROTOBUF_C__BEGIN_DECLS
|
||||
|
||||
#if PROTOBUF_C_VERSION_NUMBER < 1003000
|
||||
# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
|
||||
#elif 1004000 < PROTOBUF_C_MIN_COMPILER_VERSION
|
||||
# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
|
||||
#endif
|
||||
|
||||
#include "constants.pb-c.h"
|
||||
#include "network_constants.pb-c.h"
|
||||
|
||||
typedef struct CmdScanWifiStart CmdScanWifiStart;
|
||||
typedef struct CmdScanThreadStart CmdScanThreadStart;
|
||||
typedef struct RespScanWifiStart RespScanWifiStart;
|
||||
typedef struct RespScanThreadStart RespScanThreadStart;
|
||||
typedef struct CmdScanWifiStatus CmdScanWifiStatus;
|
||||
typedef struct CmdScanThreadStatus CmdScanThreadStatus;
|
||||
typedef struct RespScanWifiStatus RespScanWifiStatus;
|
||||
typedef struct RespScanThreadStatus RespScanThreadStatus;
|
||||
typedef struct CmdScanWifiResult CmdScanWifiResult;
|
||||
typedef struct CmdScanThreadResult CmdScanThreadResult;
|
||||
typedef struct WiFiScanResult WiFiScanResult;
|
||||
typedef struct ThreadScanResult ThreadScanResult;
|
||||
typedef struct RespScanWifiResult RespScanWifiResult;
|
||||
typedef struct RespScanThreadResult RespScanThreadResult;
|
||||
typedef struct NetworkScanPayload NetworkScanPayload;
|
||||
|
||||
|
||||
/* --- enums --- */
|
||||
|
||||
typedef enum _NetworkScanMsgType {
|
||||
NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiStart = 0,
|
||||
NETWORK_SCAN_MSG_TYPE__TypeRespScanWifiStart = 1,
|
||||
NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiStatus = 2,
|
||||
NETWORK_SCAN_MSG_TYPE__TypeRespScanWifiStatus = 3,
|
||||
NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiResult = 4,
|
||||
NETWORK_SCAN_MSG_TYPE__TypeRespScanWifiResult = 5,
|
||||
NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadStart = 6,
|
||||
NETWORK_SCAN_MSG_TYPE__TypeRespScanThreadStart = 7,
|
||||
NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadStatus = 8,
|
||||
NETWORK_SCAN_MSG_TYPE__TypeRespScanThreadStatus = 9,
|
||||
NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadResult = 10,
|
||||
NETWORK_SCAN_MSG_TYPE__TypeRespScanThreadResult = 11
|
||||
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(NETWORK_SCAN_MSG_TYPE)
|
||||
} NetworkScanMsgType;
|
||||
|
||||
/* --- messages --- */
|
||||
|
||||
struct CmdScanWifiStart
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
protobuf_c_boolean blocking;
|
||||
protobuf_c_boolean passive;
|
||||
uint32_t group_channels;
|
||||
uint32_t period_ms;
|
||||
};
|
||||
#define CMD_SCAN_WIFI_START__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&cmd_scan_wifi_start__descriptor) \
|
||||
, 0, 0, 0, 0 }
|
||||
|
||||
|
||||
struct CmdScanThreadStart
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
protobuf_c_boolean blocking;
|
||||
uint32_t channel_mask;
|
||||
};
|
||||
#define CMD_SCAN_THREAD_START__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&cmd_scan_thread_start__descriptor) \
|
||||
, 0, 0 }
|
||||
|
||||
|
||||
struct RespScanWifiStart
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
};
|
||||
#define RESP_SCAN_WIFI_START__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&resp_scan_wifi_start__descriptor) \
|
||||
}
|
||||
|
||||
|
||||
struct RespScanThreadStart
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
};
|
||||
#define RESP_SCAN_THREAD_START__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&resp_scan_thread_start__descriptor) \
|
||||
}
|
||||
|
||||
|
||||
struct CmdScanWifiStatus
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
};
|
||||
#define CMD_SCAN_WIFI_STATUS__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&cmd_scan_wifi_status__descriptor) \
|
||||
}
|
||||
|
||||
|
||||
struct CmdScanThreadStatus
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
};
|
||||
#define CMD_SCAN_THREAD_STATUS__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&cmd_scan_thread_status__descriptor) \
|
||||
}
|
||||
|
||||
|
||||
struct RespScanWifiStatus
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
protobuf_c_boolean scan_finished;
|
||||
uint32_t result_count;
|
||||
};
|
||||
#define RESP_SCAN_WIFI_STATUS__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&resp_scan_wifi_status__descriptor) \
|
||||
, 0, 0 }
|
||||
|
||||
|
||||
struct RespScanThreadStatus
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
protobuf_c_boolean scan_finished;
|
||||
uint32_t result_count;
|
||||
};
|
||||
#define RESP_SCAN_THREAD_STATUS__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&resp_scan_thread_status__descriptor) \
|
||||
, 0, 0 }
|
||||
|
||||
|
||||
struct CmdScanWifiResult
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
uint32_t start_index;
|
||||
uint32_t count;
|
||||
};
|
||||
#define CMD_SCAN_WIFI_RESULT__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&cmd_scan_wifi_result__descriptor) \
|
||||
, 0, 0 }
|
||||
|
||||
|
||||
struct CmdScanThreadResult
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
uint32_t start_index;
|
||||
uint32_t count;
|
||||
};
|
||||
#define CMD_SCAN_THREAD_RESULT__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&cmd_scan_thread_result__descriptor) \
|
||||
, 0, 0 }
|
||||
|
||||
|
||||
struct WiFiScanResult
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
ProtobufCBinaryData ssid;
|
||||
uint32_t channel;
|
||||
int32_t rssi;
|
||||
ProtobufCBinaryData bssid;
|
||||
WifiAuthMode auth;
|
||||
};
|
||||
#define WI_FI_SCAN_RESULT__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&wi_fi_scan_result__descriptor) \
|
||||
, {0,NULL}, 0, 0, {0,NULL}, WIFI_AUTH_MODE__Open }
|
||||
|
||||
|
||||
struct ThreadScanResult
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
uint32_t pan_id;
|
||||
uint32_t channel;
|
||||
int32_t rssi;
|
||||
uint32_t lqi;
|
||||
ProtobufCBinaryData ext_addr;
|
||||
char *network_name;
|
||||
ProtobufCBinaryData ext_pan_id;
|
||||
};
|
||||
#define THREAD_SCAN_RESULT__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&thread_scan_result__descriptor) \
|
||||
, 0, 0, 0, 0, {0,NULL}, (char *)protobuf_c_empty_string, {0,NULL} }
|
||||
|
||||
|
||||
struct RespScanWifiResult
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
size_t n_entries;
|
||||
WiFiScanResult **entries;
|
||||
};
|
||||
#define RESP_SCAN_WIFI_RESULT__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&resp_scan_wifi_result__descriptor) \
|
||||
, 0,NULL }
|
||||
|
||||
|
||||
struct RespScanThreadResult
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
size_t n_entries;
|
||||
ThreadScanResult **entries;
|
||||
};
|
||||
#define RESP_SCAN_THREAD_RESULT__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&resp_scan_thread_result__descriptor) \
|
||||
, 0,NULL }
|
||||
|
||||
|
||||
typedef enum {
|
||||
NETWORK_SCAN_PAYLOAD__PAYLOAD__NOT_SET = 0,
|
||||
NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_WIFI_START = 10,
|
||||
NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_WIFI_START = 11,
|
||||
NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_WIFI_STATUS = 12,
|
||||
NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_WIFI_STATUS = 13,
|
||||
NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_WIFI_RESULT = 14,
|
||||
NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_WIFI_RESULT = 15,
|
||||
NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_THREAD_START = 16,
|
||||
NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_THREAD_START = 17,
|
||||
NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_THREAD_STATUS = 18,
|
||||
NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_THREAD_STATUS = 19,
|
||||
NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_THREAD_RESULT = 20,
|
||||
NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_THREAD_RESULT = 21
|
||||
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(NETWORK_SCAN_PAYLOAD__PAYLOAD__CASE)
|
||||
} NetworkScanPayload__PayloadCase;
|
||||
|
||||
struct NetworkScanPayload
|
||||
{
|
||||
ProtobufCMessage base;
|
||||
NetworkScanMsgType msg;
|
||||
Status status;
|
||||
NetworkScanPayload__PayloadCase payload_case;
|
||||
union {
|
||||
CmdScanWifiStart *cmd_scan_wifi_start;
|
||||
RespScanWifiStart *resp_scan_wifi_start;
|
||||
CmdScanWifiStatus *cmd_scan_wifi_status;
|
||||
RespScanWifiStatus *resp_scan_wifi_status;
|
||||
CmdScanWifiResult *cmd_scan_wifi_result;
|
||||
RespScanWifiResult *resp_scan_wifi_result;
|
||||
CmdScanThreadStart *cmd_scan_thread_start;
|
||||
RespScanThreadStart *resp_scan_thread_start;
|
||||
CmdScanThreadStatus *cmd_scan_thread_status;
|
||||
RespScanThreadStatus *resp_scan_thread_status;
|
||||
CmdScanThreadResult *cmd_scan_thread_result;
|
||||
RespScanThreadResult *resp_scan_thread_result;
|
||||
};
|
||||
};
|
||||
#define NETWORK_SCAN_PAYLOAD__INIT \
|
||||
{ PROTOBUF_C_MESSAGE_INIT (&network_scan_payload__descriptor) \
|
||||
, NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiStart, STATUS__Success, NETWORK_SCAN_PAYLOAD__PAYLOAD__NOT_SET, {0} }
|
||||
|
||||
|
||||
/* CmdScanWifiStart methods */
|
||||
void cmd_scan_wifi_start__init
|
||||
(CmdScanWifiStart *message);
|
||||
size_t cmd_scan_wifi_start__get_packed_size
|
||||
(const CmdScanWifiStart *message);
|
||||
size_t cmd_scan_wifi_start__pack
|
||||
(const CmdScanWifiStart *message,
|
||||
uint8_t *out);
|
||||
size_t cmd_scan_wifi_start__pack_to_buffer
|
||||
(const CmdScanWifiStart *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
CmdScanWifiStart *
|
||||
cmd_scan_wifi_start__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void cmd_scan_wifi_start__free_unpacked
|
||||
(CmdScanWifiStart *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* CmdScanThreadStart methods */
|
||||
void cmd_scan_thread_start__init
|
||||
(CmdScanThreadStart *message);
|
||||
size_t cmd_scan_thread_start__get_packed_size
|
||||
(const CmdScanThreadStart *message);
|
||||
size_t cmd_scan_thread_start__pack
|
||||
(const CmdScanThreadStart *message,
|
||||
uint8_t *out);
|
||||
size_t cmd_scan_thread_start__pack_to_buffer
|
||||
(const CmdScanThreadStart *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
CmdScanThreadStart *
|
||||
cmd_scan_thread_start__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void cmd_scan_thread_start__free_unpacked
|
||||
(CmdScanThreadStart *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* RespScanWifiStart methods */
|
||||
void resp_scan_wifi_start__init
|
||||
(RespScanWifiStart *message);
|
||||
size_t resp_scan_wifi_start__get_packed_size
|
||||
(const RespScanWifiStart *message);
|
||||
size_t resp_scan_wifi_start__pack
|
||||
(const RespScanWifiStart *message,
|
||||
uint8_t *out);
|
||||
size_t resp_scan_wifi_start__pack_to_buffer
|
||||
(const RespScanWifiStart *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
RespScanWifiStart *
|
||||
resp_scan_wifi_start__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void resp_scan_wifi_start__free_unpacked
|
||||
(RespScanWifiStart *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* RespScanThreadStart methods */
|
||||
void resp_scan_thread_start__init
|
||||
(RespScanThreadStart *message);
|
||||
size_t resp_scan_thread_start__get_packed_size
|
||||
(const RespScanThreadStart *message);
|
||||
size_t resp_scan_thread_start__pack
|
||||
(const RespScanThreadStart *message,
|
||||
uint8_t *out);
|
||||
size_t resp_scan_thread_start__pack_to_buffer
|
||||
(const RespScanThreadStart *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
RespScanThreadStart *
|
||||
resp_scan_thread_start__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void resp_scan_thread_start__free_unpacked
|
||||
(RespScanThreadStart *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* CmdScanWifiStatus methods */
|
||||
void cmd_scan_wifi_status__init
|
||||
(CmdScanWifiStatus *message);
|
||||
size_t cmd_scan_wifi_status__get_packed_size
|
||||
(const CmdScanWifiStatus *message);
|
||||
size_t cmd_scan_wifi_status__pack
|
||||
(const CmdScanWifiStatus *message,
|
||||
uint8_t *out);
|
||||
size_t cmd_scan_wifi_status__pack_to_buffer
|
||||
(const CmdScanWifiStatus *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
CmdScanWifiStatus *
|
||||
cmd_scan_wifi_status__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void cmd_scan_wifi_status__free_unpacked
|
||||
(CmdScanWifiStatus *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* CmdScanThreadStatus methods */
|
||||
void cmd_scan_thread_status__init
|
||||
(CmdScanThreadStatus *message);
|
||||
size_t cmd_scan_thread_status__get_packed_size
|
||||
(const CmdScanThreadStatus *message);
|
||||
size_t cmd_scan_thread_status__pack
|
||||
(const CmdScanThreadStatus *message,
|
||||
uint8_t *out);
|
||||
size_t cmd_scan_thread_status__pack_to_buffer
|
||||
(const CmdScanThreadStatus *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
CmdScanThreadStatus *
|
||||
cmd_scan_thread_status__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void cmd_scan_thread_status__free_unpacked
|
||||
(CmdScanThreadStatus *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* RespScanWifiStatus methods */
|
||||
void resp_scan_wifi_status__init
|
||||
(RespScanWifiStatus *message);
|
||||
size_t resp_scan_wifi_status__get_packed_size
|
||||
(const RespScanWifiStatus *message);
|
||||
size_t resp_scan_wifi_status__pack
|
||||
(const RespScanWifiStatus *message,
|
||||
uint8_t *out);
|
||||
size_t resp_scan_wifi_status__pack_to_buffer
|
||||
(const RespScanWifiStatus *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
RespScanWifiStatus *
|
||||
resp_scan_wifi_status__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void resp_scan_wifi_status__free_unpacked
|
||||
(RespScanWifiStatus *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* RespScanThreadStatus methods */
|
||||
void resp_scan_thread_status__init
|
||||
(RespScanThreadStatus *message);
|
||||
size_t resp_scan_thread_status__get_packed_size
|
||||
(const RespScanThreadStatus *message);
|
||||
size_t resp_scan_thread_status__pack
|
||||
(const RespScanThreadStatus *message,
|
||||
uint8_t *out);
|
||||
size_t resp_scan_thread_status__pack_to_buffer
|
||||
(const RespScanThreadStatus *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
RespScanThreadStatus *
|
||||
resp_scan_thread_status__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void resp_scan_thread_status__free_unpacked
|
||||
(RespScanThreadStatus *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* CmdScanWifiResult methods */
|
||||
void cmd_scan_wifi_result__init
|
||||
(CmdScanWifiResult *message);
|
||||
size_t cmd_scan_wifi_result__get_packed_size
|
||||
(const CmdScanWifiResult *message);
|
||||
size_t cmd_scan_wifi_result__pack
|
||||
(const CmdScanWifiResult *message,
|
||||
uint8_t *out);
|
||||
size_t cmd_scan_wifi_result__pack_to_buffer
|
||||
(const CmdScanWifiResult *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
CmdScanWifiResult *
|
||||
cmd_scan_wifi_result__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void cmd_scan_wifi_result__free_unpacked
|
||||
(CmdScanWifiResult *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* CmdScanThreadResult methods */
|
||||
void cmd_scan_thread_result__init
|
||||
(CmdScanThreadResult *message);
|
||||
size_t cmd_scan_thread_result__get_packed_size
|
||||
(const CmdScanThreadResult *message);
|
||||
size_t cmd_scan_thread_result__pack
|
||||
(const CmdScanThreadResult *message,
|
||||
uint8_t *out);
|
||||
size_t cmd_scan_thread_result__pack_to_buffer
|
||||
(const CmdScanThreadResult *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
CmdScanThreadResult *
|
||||
cmd_scan_thread_result__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void cmd_scan_thread_result__free_unpacked
|
||||
(CmdScanThreadResult *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* WiFiScanResult methods */
|
||||
void wi_fi_scan_result__init
|
||||
(WiFiScanResult *message);
|
||||
size_t wi_fi_scan_result__get_packed_size
|
||||
(const WiFiScanResult *message);
|
||||
size_t wi_fi_scan_result__pack
|
||||
(const WiFiScanResult *message,
|
||||
uint8_t *out);
|
||||
size_t wi_fi_scan_result__pack_to_buffer
|
||||
(const WiFiScanResult *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
WiFiScanResult *
|
||||
wi_fi_scan_result__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void wi_fi_scan_result__free_unpacked
|
||||
(WiFiScanResult *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* ThreadScanResult methods */
|
||||
void thread_scan_result__init
|
||||
(ThreadScanResult *message);
|
||||
size_t thread_scan_result__get_packed_size
|
||||
(const ThreadScanResult *message);
|
||||
size_t thread_scan_result__pack
|
||||
(const ThreadScanResult *message,
|
||||
uint8_t *out);
|
||||
size_t thread_scan_result__pack_to_buffer
|
||||
(const ThreadScanResult *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
ThreadScanResult *
|
||||
thread_scan_result__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void thread_scan_result__free_unpacked
|
||||
(ThreadScanResult *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* RespScanWifiResult methods */
|
||||
void resp_scan_wifi_result__init
|
||||
(RespScanWifiResult *message);
|
||||
size_t resp_scan_wifi_result__get_packed_size
|
||||
(const RespScanWifiResult *message);
|
||||
size_t resp_scan_wifi_result__pack
|
||||
(const RespScanWifiResult *message,
|
||||
uint8_t *out);
|
||||
size_t resp_scan_wifi_result__pack_to_buffer
|
||||
(const RespScanWifiResult *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
RespScanWifiResult *
|
||||
resp_scan_wifi_result__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void resp_scan_wifi_result__free_unpacked
|
||||
(RespScanWifiResult *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* RespScanThreadResult methods */
|
||||
void resp_scan_thread_result__init
|
||||
(RespScanThreadResult *message);
|
||||
size_t resp_scan_thread_result__get_packed_size
|
||||
(const RespScanThreadResult *message);
|
||||
size_t resp_scan_thread_result__pack
|
||||
(const RespScanThreadResult *message,
|
||||
uint8_t *out);
|
||||
size_t resp_scan_thread_result__pack_to_buffer
|
||||
(const RespScanThreadResult *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
RespScanThreadResult *
|
||||
resp_scan_thread_result__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void resp_scan_thread_result__free_unpacked
|
||||
(RespScanThreadResult *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* NetworkScanPayload methods */
|
||||
void network_scan_payload__init
|
||||
(NetworkScanPayload *message);
|
||||
size_t network_scan_payload__get_packed_size
|
||||
(const NetworkScanPayload *message);
|
||||
size_t network_scan_payload__pack
|
||||
(const NetworkScanPayload *message,
|
||||
uint8_t *out);
|
||||
size_t network_scan_payload__pack_to_buffer
|
||||
(const NetworkScanPayload *message,
|
||||
ProtobufCBuffer *buffer);
|
||||
NetworkScanPayload *
|
||||
network_scan_payload__unpack
|
||||
(ProtobufCAllocator *allocator,
|
||||
size_t len,
|
||||
const uint8_t *data);
|
||||
void network_scan_payload__free_unpacked
|
||||
(NetworkScanPayload *message,
|
||||
ProtobufCAllocator *allocator);
|
||||
/* --- per-message closures --- */
|
||||
|
||||
typedef void (*CmdScanWifiStart_Closure)
|
||||
(const CmdScanWifiStart *message,
|
||||
void *closure_data);
|
||||
typedef void (*CmdScanThreadStart_Closure)
|
||||
(const CmdScanThreadStart *message,
|
||||
void *closure_data);
|
||||
typedef void (*RespScanWifiStart_Closure)
|
||||
(const RespScanWifiStart *message,
|
||||
void *closure_data);
|
||||
typedef void (*RespScanThreadStart_Closure)
|
||||
(const RespScanThreadStart *message,
|
||||
void *closure_data);
|
||||
typedef void (*CmdScanWifiStatus_Closure)
|
||||
(const CmdScanWifiStatus *message,
|
||||
void *closure_data);
|
||||
typedef void (*CmdScanThreadStatus_Closure)
|
||||
(const CmdScanThreadStatus *message,
|
||||
void *closure_data);
|
||||
typedef void (*RespScanWifiStatus_Closure)
|
||||
(const RespScanWifiStatus *message,
|
||||
void *closure_data);
|
||||
typedef void (*RespScanThreadStatus_Closure)
|
||||
(const RespScanThreadStatus *message,
|
||||
void *closure_data);
|
||||
typedef void (*CmdScanWifiResult_Closure)
|
||||
(const CmdScanWifiResult *message,
|
||||
void *closure_data);
|
||||
typedef void (*CmdScanThreadResult_Closure)
|
||||
(const CmdScanThreadResult *message,
|
||||
void *closure_data);
|
||||
typedef void (*WiFiScanResult_Closure)
|
||||
(const WiFiScanResult *message,
|
||||
void *closure_data);
|
||||
typedef void (*ThreadScanResult_Closure)
|
||||
(const ThreadScanResult *message,
|
||||
void *closure_data);
|
||||
typedef void (*RespScanWifiResult_Closure)
|
||||
(const RespScanWifiResult *message,
|
||||
void *closure_data);
|
||||
typedef void (*RespScanThreadResult_Closure)
|
||||
(const RespScanThreadResult *message,
|
||||
void *closure_data);
|
||||
typedef void (*NetworkScanPayload_Closure)
|
||||
(const NetworkScanPayload *message,
|
||||
void *closure_data);
|
||||
|
||||
/* --- services --- */
|
||||
|
||||
|
||||
/* --- descriptors --- */
|
||||
|
||||
extern const ProtobufCEnumDescriptor network_scan_msg_type__descriptor;
|
||||
extern const ProtobufCMessageDescriptor cmd_scan_wifi_start__descriptor;
|
||||
extern const ProtobufCMessageDescriptor cmd_scan_thread_start__descriptor;
|
||||
extern const ProtobufCMessageDescriptor resp_scan_wifi_start__descriptor;
|
||||
extern const ProtobufCMessageDescriptor resp_scan_thread_start__descriptor;
|
||||
extern const ProtobufCMessageDescriptor cmd_scan_wifi_status__descriptor;
|
||||
extern const ProtobufCMessageDescriptor cmd_scan_thread_status__descriptor;
|
||||
extern const ProtobufCMessageDescriptor resp_scan_wifi_status__descriptor;
|
||||
extern const ProtobufCMessageDescriptor resp_scan_thread_status__descriptor;
|
||||
extern const ProtobufCMessageDescriptor cmd_scan_wifi_result__descriptor;
|
||||
extern const ProtobufCMessageDescriptor cmd_scan_thread_result__descriptor;
|
||||
extern const ProtobufCMessageDescriptor wi_fi_scan_result__descriptor;
|
||||
extern const ProtobufCMessageDescriptor thread_scan_result__descriptor;
|
||||
extern const ProtobufCMessageDescriptor resp_scan_wifi_result__descriptor;
|
||||
extern const ProtobufCMessageDescriptor resp_scan_thread_result__descriptor;
|
||||
extern const ProtobufCMessageDescriptor network_scan_payload__descriptor;
|
||||
|
||||
PROTOBUF_C__END_DECLS
|
||||
|
||||
|
||||
#endif /* PROTOBUF_C_network_5fscan_2eproto__INCLUDED */
|
||||
@@ -0,0 +1,29 @@
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
set(PROTO_COMPILER "protoc")
|
||||
set(PROTO_C_COMPILER "protoc-c")
|
||||
set(C_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../proto-c")
|
||||
set(PY_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../python")
|
||||
set(PROTOCOMM_INCL_PATH "${IDF_PATH}/component/protocomm/proto")
|
||||
|
||||
set(PROTO_SRCS "network_constants.proto"
|
||||
"network_config.proto"
|
||||
"network_scan.proto")
|
||||
|
||||
add_custom_target(c_proto
|
||||
COMMAND ${PROTO_C_COMPILER} --c_out=${C_OUT_PATH} -I . -I ${PROTOCOMM_INCL_PATH} ${PROTO_SRCS}
|
||||
VERBATIM
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
add_custom_target(python_proto
|
||||
COMMAND ${PROTO_COMPILER} --python_out=${PY_OUT_PATH} -I . -I ${PROTOCOMM_INCL_PATH} ${PROTO_SRCS}
|
||||
VERBATIM
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
add_custom_target(proto ALL
|
||||
DEPENDS c_proto python_proto
|
||||
VERBATIM
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
# Protobuf files for defining Network provisioning packet structures
|
||||
|
||||
`network_provisioning` uses Google Protobuf for language, transport and architecture agnostic protocol communication. These proto files define the protocomm packet structure, separated across multiple files:
|
||||
* network_contants.proto - Defines the various enums for indicating state of network (connected / disconnect / connecting), disconnect reasons, auth modes, etc.
|
||||
* network_config.proto - Defines network configuration structures and commands for setting Wi-Fi credentials (SSID, passphrase, BSSID) or Thread dataset, applying credentials and getting connection state.
|
||||
* network_scan.proto - Defines network scan commands and result structures
|
||||
* network_ctrl.proto - Defines network control commands(reset and re-provision) and result structures
|
||||
|
||||
Note : These proto files are not automatically compiled during the build process.
|
||||
|
||||
# Compilation
|
||||
|
||||
Compilation requires protoc (Protobuf Compiler) and protoc-c (Protobuf C Compiler) installed. Since the generated files are to remain the same, as long as the proto files are not modified, therefore the generated files are already available under `components/network_provisioning/proto-c` and `components/network_provisioning/python` directories, and thus running cmake / make (and installing the Protobuf compilers) is optional.
|
||||
|
||||
If using `cmake` follow the below steps. If using `make`, jump to Step 2 directly.
|
||||
|
||||
## Step 1 (Only for cmake)
|
||||
|
||||
When using cmake, first create a build directory and call cmake from inside:
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
```
|
||||
|
||||
## Step 2
|
||||
|
||||
Simply run `make` to generate the respective C and Python files. The newly created files will overwrite those under `components/network_provisioning/proto-c` and `components/network_provisioning/python`
|
||||
@@ -0,0 +1,7 @@
|
||||
all: c_proto python_proto
|
||||
|
||||
c_proto: *.proto
|
||||
@protoc-c --c_out=../proto-c/ -I . -I ${IDF_PATH}/components/protocomm/proto/ *.proto
|
||||
|
||||
python_proto: *.proto
|
||||
@protoc --python_out=../python/ -I . -I ${IDF_PATH}/components/protocomm/proto/ *.proto
|
||||
@@ -0,0 +1,96 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "constants.proto";
|
||||
import "network_constants.proto";
|
||||
|
||||
message CmdGetWifiStatus {
|
||||
}
|
||||
|
||||
message RespGetWifiStatus {
|
||||
Status status = 1;
|
||||
WifiStationState wifi_sta_state = 2;
|
||||
oneof state {
|
||||
WifiConnectFailedReason wifi_fail_reason = 10;
|
||||
WifiConnectedState wifi_connected = 11;
|
||||
WifiAttemptFailed attempt_failed = 12;
|
||||
}
|
||||
}
|
||||
|
||||
message CmdGetThreadStatus {
|
||||
}
|
||||
|
||||
message RespGetThreadStatus {
|
||||
Status status = 1;
|
||||
ThreadNetworkState thread_state = 2;
|
||||
oneof state {
|
||||
ThreadAttachFailedReason thread_fail_reason = 10;
|
||||
ThreadAttachState thread_attached = 11;
|
||||
}
|
||||
}
|
||||
|
||||
message CmdSetWifiConfig {
|
||||
bytes ssid = 1;
|
||||
bytes passphrase = 2;
|
||||
bytes bssid = 3;
|
||||
int32 channel = 4;
|
||||
}
|
||||
|
||||
message CmdSetThreadConfig {
|
||||
bytes dataset = 1;
|
||||
}
|
||||
|
||||
message RespSetWifiConfig {
|
||||
Status status = 1;
|
||||
}
|
||||
|
||||
message RespSetThreadConfig {
|
||||
Status status = 1;
|
||||
}
|
||||
|
||||
message CmdApplyWifiConfig {
|
||||
}
|
||||
|
||||
message CmdApplyThreadConfig {
|
||||
}
|
||||
|
||||
message RespApplyWifiConfig {
|
||||
Status status = 1;
|
||||
}
|
||||
|
||||
message RespApplyThreadConfig {
|
||||
Status status = 1;
|
||||
}
|
||||
|
||||
enum NetworkConfigMsgType {
|
||||
TypeCmdGetWifiStatus = 0;
|
||||
TypeRespGetWifiStatus = 1;
|
||||
TypeCmdSetWifiConfig = 2;
|
||||
TypeRespSetWifiConfig = 3;
|
||||
TypeCmdApplyWifiConfig = 4;
|
||||
TypeRespApplyWifiConfig = 5;
|
||||
TypeCmdGetThreadStatus = 6;
|
||||
TypeRespGetThreadStatus = 7;
|
||||
TypeCmdSetThreadConfig = 8;
|
||||
TypeRespSetThreadConfig = 9;
|
||||
TypeCmdApplyThreadConfig = 10;
|
||||
TypeRespApplyThreadConfig = 11;
|
||||
|
||||
}
|
||||
|
||||
message NetworkConfigPayload {
|
||||
NetworkConfigMsgType msg = 1;
|
||||
oneof payload {
|
||||
CmdGetWifiStatus cmd_get_wifi_status = 10;
|
||||
RespGetWifiStatus resp_get_wifi_status = 11;
|
||||
CmdSetWifiConfig cmd_set_wifi_config = 12;
|
||||
RespSetWifiConfig resp_set_wifi_config = 13;
|
||||
CmdApplyWifiConfig cmd_apply_wifi_config = 14;
|
||||
RespApplyWifiConfig resp_apply_wifi_config = 15;
|
||||
CmdGetThreadStatus cmd_get_thread_status = 16;
|
||||
RespGetThreadStatus resp_get_thread_status = 17;
|
||||
CmdSetThreadConfig cmd_set_thread_config = 18;
|
||||
RespSetThreadConfig resp_set_thread_config = 19;
|
||||
CmdApplyThreadConfig cmd_apply_thread_config = 20;
|
||||
RespApplyThreadConfig resp_apply_thread_config = 21;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
syntax = "proto3";
|
||||
|
||||
enum WifiStationState {
|
||||
Connected = 0;
|
||||
Connecting = 1;
|
||||
Disconnected = 2;
|
||||
ConnectionFailed = 3;
|
||||
}
|
||||
|
||||
enum WifiConnectFailedReason {
|
||||
AuthError = 0;
|
||||
WifiNetworkNotFound = 1;
|
||||
}
|
||||
|
||||
enum WifiAuthMode {
|
||||
Open = 0;
|
||||
WEP = 1;
|
||||
WPA_PSK = 2;
|
||||
WPA2_PSK = 3;
|
||||
WPA_WPA2_PSK = 4;
|
||||
WPA2_ENTERPRISE = 5;
|
||||
WPA3_PSK = 6;
|
||||
WPA2_WPA3_PSK = 7;
|
||||
}
|
||||
|
||||
message WifiConnectedState {
|
||||
string ip4_addr = 1;
|
||||
WifiAuthMode auth_mode = 2;
|
||||
bytes ssid = 3;
|
||||
bytes bssid = 4;
|
||||
int32 channel = 5;
|
||||
}
|
||||
|
||||
message WifiAttemptFailed {
|
||||
uint32 attempts_remaining = 1;
|
||||
}
|
||||
|
||||
enum ThreadNetworkState {
|
||||
Attached = 0;
|
||||
Attaching = 1;
|
||||
Dettached = 2;
|
||||
AttachingFailed = 3;
|
||||
}
|
||||
|
||||
enum ThreadAttachFailedReason {
|
||||
DatasetInvalid = 0;
|
||||
ThreadNetworkNotFound = 1;
|
||||
}
|
||||
|
||||
message ThreadAttachState {
|
||||
uint32 pan_id = 1;
|
||||
bytes ext_pan_id = 2;
|
||||
uint32 channel = 3;
|
||||
string name = 4;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "constants.proto";
|
||||
|
||||
message CmdCtrlWifiReset {
|
||||
}
|
||||
|
||||
message RespCtrlWifiReset {
|
||||
}
|
||||
|
||||
message CmdCtrlWifiReprov {
|
||||
}
|
||||
|
||||
message RespCtrlWifiReprov{
|
||||
}
|
||||
|
||||
message CmdCtrlThreadReset {
|
||||
}
|
||||
|
||||
message RespCtrlThreadReset {
|
||||
}
|
||||
|
||||
message CmdCtrlThreadReprov {
|
||||
}
|
||||
|
||||
message RespCtrlThreadReprov{
|
||||
}
|
||||
|
||||
enum NetworkCtrlMsgType {
|
||||
TypeCtrlReserved = 0;
|
||||
TypeCmdCtrlWifiReset = 1;
|
||||
TypeRespCtrlWifiReset = 2;
|
||||
TypeCmdCtrlWifiReprov = 3;
|
||||
TypeRespCtrlWifiReprov = 4;
|
||||
TypeCmdCtrlThreadReset = 5;
|
||||
TypeRespCtrlThreadReset = 6;
|
||||
TypeCmdCtrlThreadReprov = 7;
|
||||
TypeRespCtrlThreadReprov = 8;
|
||||
|
||||
}
|
||||
|
||||
message NetworkCtrlPayload {
|
||||
NetworkCtrlMsgType msg = 1;
|
||||
Status status = 2;
|
||||
oneof payload {
|
||||
CmdCtrlWifiReset cmd_ctrl_wifi_reset = 11;
|
||||
RespCtrlWifiReset resp_ctrl_wifi_reset = 12;
|
||||
CmdCtrlWifiReprov cmd_ctrl_wifi_reprov = 13;
|
||||
RespCtrlWifiReprov resp_ctrl_wifi_reprov = 14;
|
||||
CmdCtrlThreadReset cmd_ctrl_thread_reset = 15;
|
||||
RespCtrlThreadReset resp_ctrl_thread_reset = 16;
|
||||
CmdCtrlThreadReprov cmd_ctrl_thread_reprov = 17;
|
||||
RespCtrlThreadReprov resp_ctrl_thread_reprov = 18;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "constants.proto";
|
||||
import "network_constants.proto";
|
||||
|
||||
message CmdScanWifiStart {
|
||||
bool blocking = 1;
|
||||
bool passive = 2;
|
||||
uint32 group_channels = 3;
|
||||
uint32 period_ms = 4;
|
||||
}
|
||||
|
||||
message CmdScanThreadStart {
|
||||
bool blocking = 1;
|
||||
uint32 channel_mask = 2;
|
||||
}
|
||||
|
||||
message RespScanWifiStart {
|
||||
}
|
||||
|
||||
message RespScanThreadStart {
|
||||
}
|
||||
|
||||
message CmdScanWifiStatus {
|
||||
}
|
||||
|
||||
message CmdScanThreadStatus {
|
||||
}
|
||||
|
||||
message RespScanWifiStatus {
|
||||
bool scan_finished = 1;
|
||||
uint32 result_count = 2;
|
||||
}
|
||||
|
||||
message RespScanThreadStatus {
|
||||
bool scan_finished = 1;
|
||||
uint32 result_count = 2;
|
||||
}
|
||||
|
||||
message CmdScanWifiResult {
|
||||
uint32 start_index = 1;
|
||||
uint32 count = 2;
|
||||
}
|
||||
|
||||
message CmdScanThreadResult {
|
||||
uint32 start_index = 1;
|
||||
uint32 count = 2;
|
||||
}
|
||||
|
||||
message WiFiScanResult {
|
||||
bytes ssid = 1;
|
||||
uint32 channel = 2;
|
||||
int32 rssi = 3;
|
||||
bytes bssid = 4;
|
||||
WifiAuthMode auth = 5;
|
||||
}
|
||||
|
||||
message ThreadScanResult {
|
||||
uint32 pan_id = 1;
|
||||
uint32 channel = 2;
|
||||
int32 rssi = 3;
|
||||
uint32 lqi = 4;
|
||||
bytes ext_addr = 5;
|
||||
string network_name = 6;
|
||||
bytes ext_pan_id = 7;
|
||||
}
|
||||
|
||||
message RespScanWifiResult {
|
||||
repeated WiFiScanResult entries = 1;
|
||||
}
|
||||
|
||||
message RespScanThreadResult {
|
||||
repeated ThreadScanResult entries = 1;
|
||||
}
|
||||
|
||||
|
||||
enum NetworkScanMsgType {
|
||||
TypeCmdScanWifiStart = 0;
|
||||
TypeRespScanWifiStart = 1;
|
||||
TypeCmdScanWifiStatus = 2;
|
||||
TypeRespScanWifiStatus = 3;
|
||||
TypeCmdScanWifiResult = 4;
|
||||
TypeRespScanWifiResult = 5;
|
||||
TypeCmdScanThreadStart = 6;
|
||||
TypeRespScanThreadStart = 7;
|
||||
TypeCmdScanThreadStatus = 8;
|
||||
TypeRespScanThreadStatus = 9;
|
||||
TypeCmdScanThreadResult = 10;
|
||||
TypeRespScanThreadResult = 11;
|
||||
}
|
||||
|
||||
message NetworkScanPayload {
|
||||
NetworkScanMsgType msg = 1;
|
||||
Status status = 2;
|
||||
oneof payload {
|
||||
CmdScanWifiStart cmd_scan_wifi_start = 10;
|
||||
RespScanWifiStart resp_scan_wifi_start = 11;
|
||||
CmdScanWifiStatus cmd_scan_wifi_status = 12;
|
||||
RespScanWifiStatus resp_scan_wifi_status = 13;
|
||||
CmdScanWifiResult cmd_scan_wifi_result = 14;
|
||||
RespScanWifiResult resp_scan_wifi_result = 15;
|
||||
CmdScanThreadStart cmd_scan_thread_start = 16;
|
||||
RespScanThreadStart resp_scan_thread_start = 17;
|
||||
CmdScanThreadStatus cmd_scan_thread_status = 18;
|
||||
RespScanThreadStatus resp_scan_thread_status = 19;
|
||||
CmdScanThreadResult cmd_scan_thread_result = 20;
|
||||
RespScanThreadResult resp_scan_thread_result = 21;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: network_config.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf.internal import builder as _builder
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
import constants_pb2 as constants__pb2
|
||||
import network_constants_pb2 as network__constants__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14network_config.proto\x1a\x0f\x63onstants.proto\x1a\x17network_constants.proto\"\x12\n\x10\x43mdGetWifiStatus\"\xf3\x01\n\x11RespGetWifiStatus\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\x12)\n\x0ewifi_sta_state\x18\x02 \x01(\x0e\x32\x11.WifiStationState\x12\x34\n\x10wifi_fail_reason\x18\n \x01(\x0e\x32\x18.WifiConnectFailedReasonH\x00\x12-\n\x0ewifi_connected\x18\x0b \x01(\x0b\x32\x13.WifiConnectedStateH\x00\x12,\n\x0e\x61ttempt_failed\x18\x0c \x01(\x0b\x32\x12.WifiAttemptFailedH\x00\x42\x07\n\x05state\"\x14\n\x12\x43mdGetThreadStatus\"\xca\x01\n\x13RespGetThreadStatus\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\x12)\n\x0cthread_state\x18\x02 \x01(\x0e\x32\x13.ThreadNetworkState\x12\x37\n\x12thread_fail_reason\x18\n \x01(\x0e\x32\x19.ThreadAttachFailedReasonH\x00\x12-\n\x0fthread_attached\x18\x0b \x01(\x0b\x32\x12.ThreadAttachStateH\x00\x42\x07\n\x05state\"T\n\x10\x43mdSetWifiConfig\x12\x0c\n\x04ssid\x18\x01 \x01(\x0c\x12\x12\n\npassphrase\x18\x02 \x01(\x0c\x12\r\n\x05\x62ssid\x18\x03 \x01(\x0c\x12\x0f\n\x07\x63hannel\x18\x04 \x01(\x05\"%\n\x12\x43mdSetThreadConfig\x12\x0f\n\x07\x64\x61taset\x18\x01 \x01(\x0c\",\n\x11RespSetWifiConfig\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\".\n\x13RespSetThreadConfig\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\"\x14\n\x12\x43mdApplyWifiConfig\"\x16\n\x14\x43mdApplyThreadConfig\".\n\x13RespApplyWifiConfig\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\"0\n\x15RespApplyThreadConfig\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\"\xd1\x05\n\x14NetworkConfigPayload\x12\"\n\x03msg\x18\x01 \x01(\x0e\x32\x15.NetworkConfigMsgType\x12\x30\n\x13\x63md_get_wifi_status\x18\n \x01(\x0b\x32\x11.CmdGetWifiStatusH\x00\x12\x32\n\x14resp_get_wifi_status\x18\x0b \x01(\x0b\x32\x12.RespGetWifiStatusH\x00\x12\x30\n\x13\x63md_set_wifi_config\x18\x0c \x01(\x0b\x32\x11.CmdSetWifiConfigH\x00\x12\x32\n\x14resp_set_wifi_config\x18\r \x01(\x0b\x32\x12.RespSetWifiConfigH\x00\x12\x34\n\x15\x63md_apply_wifi_config\x18\x0e \x01(\x0b\x32\x13.CmdApplyWifiConfigH\x00\x12\x36\n\x16resp_apply_wifi_config\x18\x0f \x01(\x0b\x32\x14.RespApplyWifiConfigH\x00\x12\x34\n\x15\x63md_get_thread_status\x18\x10 \x01(\x0b\x32\x13.CmdGetThreadStatusH\x00\x12\x36\n\x16resp_get_thread_status\x18\x11 \x01(\x0b\x32\x14.RespGetThreadStatusH\x00\x12\x34\n\x15\x63md_set_thread_config\x18\x12 \x01(\x0b\x32\x13.CmdSetThreadConfigH\x00\x12\x36\n\x16resp_set_thread_config\x18\x13 \x01(\x0b\x32\x14.RespSetThreadConfigH\x00\x12\x38\n\x17\x63md_apply_thread_config\x18\x14 \x01(\x0b\x32\x15.CmdApplyThreadConfigH\x00\x12:\n\x18resp_apply_thread_config\x18\x15 \x01(\x0b\x32\x16.RespApplyThreadConfigH\x00\x42\t\n\x07payload*\xe8\x02\n\x14NetworkConfigMsgType\x12\x18\n\x14TypeCmdGetWifiStatus\x10\x00\x12\x19\n\x15TypeRespGetWifiStatus\x10\x01\x12\x18\n\x14TypeCmdSetWifiConfig\x10\x02\x12\x19\n\x15TypeRespSetWifiConfig\x10\x03\x12\x1a\n\x16TypeCmdApplyWifiConfig\x10\x04\x12\x1b\n\x17TypeRespApplyWifiConfig\x10\x05\x12\x1a\n\x16TypeCmdGetThreadStatus\x10\x06\x12\x1b\n\x17TypeRespGetThreadStatus\x10\x07\x12\x1a\n\x16TypeCmdSetThreadConfig\x10\x08\x12\x1b\n\x17TypeRespSetThreadConfig\x10\t\x12\x1c\n\x18TypeCmdApplyThreadConfig\x10\n\x12\x1d\n\x19TypeRespApplyThreadConfig\x10\x0b\x62\x06proto3')
|
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'network_config_pb2', globals())
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
_NETWORKCONFIGMSGTYPE._serialized_start=1647
|
||||
_NETWORKCONFIGMSGTYPE._serialized_end=2007
|
||||
_CMDGETWIFISTATUS._serialized_start=66
|
||||
_CMDGETWIFISTATUS._serialized_end=84
|
||||
_RESPGETWIFISTATUS._serialized_start=87
|
||||
_RESPGETWIFISTATUS._serialized_end=330
|
||||
_CMDGETTHREADSTATUS._serialized_start=332
|
||||
_CMDGETTHREADSTATUS._serialized_end=352
|
||||
_RESPGETTHREADSTATUS._serialized_start=355
|
||||
_RESPGETTHREADSTATUS._serialized_end=557
|
||||
_CMDSETWIFICONFIG._serialized_start=559
|
||||
_CMDSETWIFICONFIG._serialized_end=643
|
||||
_CMDSETTHREADCONFIG._serialized_start=645
|
||||
_CMDSETTHREADCONFIG._serialized_end=682
|
||||
_RESPSETWIFICONFIG._serialized_start=684
|
||||
_RESPSETWIFICONFIG._serialized_end=728
|
||||
_RESPSETTHREADCONFIG._serialized_start=730
|
||||
_RESPSETTHREADCONFIG._serialized_end=776
|
||||
_CMDAPPLYWIFICONFIG._serialized_start=778
|
||||
_CMDAPPLYWIFICONFIG._serialized_end=798
|
||||
_CMDAPPLYTHREADCONFIG._serialized_start=800
|
||||
_CMDAPPLYTHREADCONFIG._serialized_end=822
|
||||
_RESPAPPLYWIFICONFIG._serialized_start=824
|
||||
_RESPAPPLYWIFICONFIG._serialized_end=870
|
||||
_RESPAPPLYTHREADCONFIG._serialized_start=872
|
||||
_RESPAPPLYTHREADCONFIG._serialized_end=920
|
||||
_NETWORKCONFIGPAYLOAD._serialized_start=923
|
||||
_NETWORKCONFIGPAYLOAD._serialized_end=1644
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,39 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: network_constants.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf.internal import builder as _builder
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17network_constants.proto\"v\n\x12WifiConnectedState\x12\x10\n\x08ip4_addr\x18\x01 \x01(\t\x12 \n\tauth_mode\x18\x02 \x01(\x0e\x32\r.WifiAuthMode\x12\x0c\n\x04ssid\x18\x03 \x01(\x0c\x12\r\n\x05\x62ssid\x18\x04 \x01(\x0c\x12\x0f\n\x07\x63hannel\x18\x05 \x01(\x05\"/\n\x11WifiAttemptFailed\x12\x1a\n\x12\x61ttempts_remaining\x18\x01 \x01(\r\"V\n\x11ThreadAttachState\x12\x0e\n\x06pan_id\x18\x01 \x01(\r\x12\x12\n\next_pan_id\x18\x02 \x01(\x0c\x12\x0f\n\x07\x63hannel\x18\x03 \x01(\r\x12\x0c\n\x04name\x18\x04 \x01(\t*Y\n\x10WifiStationState\x12\r\n\tConnected\x10\x00\x12\x0e\n\nConnecting\x10\x01\x12\x10\n\x0c\x44isconnected\x10\x02\x12\x14\n\x10\x43onnectionFailed\x10\x03*A\n\x17WifiConnectFailedReason\x12\r\n\tAuthError\x10\x00\x12\x17\n\x13WifiNetworkNotFound\x10\x01*\x84\x01\n\x0cWifiAuthMode\x12\x08\n\x04Open\x10\x00\x12\x07\n\x03WEP\x10\x01\x12\x0b\n\x07WPA_PSK\x10\x02\x12\x0c\n\x08WPA2_PSK\x10\x03\x12\x10\n\x0cWPA_WPA2_PSK\x10\x04\x12\x13\n\x0fWPA2_ENTERPRISE\x10\x05\x12\x0c\n\x08WPA3_PSK\x10\x06\x12\x11\n\rWPA2_WPA3_PSK\x10\x07*U\n\x12ThreadNetworkState\x12\x0c\n\x08\x41ttached\x10\x00\x12\r\n\tAttaching\x10\x01\x12\r\n\tDettached\x10\x02\x12\x13\n\x0f\x41ttachingFailed\x10\x03*I\n\x18ThreadAttachFailedReason\x12\x12\n\x0e\x44\x61tasetInvalid\x10\x00\x12\x19\n\x15ThreadNetworkNotFound\x10\x01\x62\x06proto3')
|
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'network_constants_pb2', globals())
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
_WIFISTATIONSTATE._serialized_start=284
|
||||
_WIFISTATIONSTATE._serialized_end=373
|
||||
_WIFICONNECTFAILEDREASON._serialized_start=375
|
||||
_WIFICONNECTFAILEDREASON._serialized_end=440
|
||||
_WIFIAUTHMODE._serialized_start=443
|
||||
_WIFIAUTHMODE._serialized_end=575
|
||||
_THREADNETWORKSTATE._serialized_start=577
|
||||
_THREADNETWORKSTATE._serialized_end=662
|
||||
_THREADATTACHFAILEDREASON._serialized_start=664
|
||||
_THREADATTACHFAILEDREASON._serialized_end=737
|
||||
_WIFICONNECTEDSTATE._serialized_start=27
|
||||
_WIFICONNECTEDSTATE._serialized_end=145
|
||||
_WIFIATTEMPTFAILED._serialized_start=147
|
||||
_WIFIATTEMPTFAILED._serialized_end=194
|
||||
_THREADATTACHSTATE._serialized_start=196
|
||||
_THREADATTACHSTATE._serialized_end=282
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,44 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: network_ctrl.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf.internal import builder as _builder
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
import constants_pb2 as constants__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12network_ctrl.proto\x1a\x0f\x63onstants.proto\"\x12\n\x10\x43mdCtrlWifiReset\"\x13\n\x11RespCtrlWifiReset\"\x13\n\x11\x43mdCtrlWifiReprov\"\x14\n\x12RespCtrlWifiReprov\"\x14\n\x12\x43mdCtrlThreadReset\"\x15\n\x13RespCtrlThreadReset\"\x15\n\x13\x43mdCtrlThreadReprov\"\x16\n\x14RespCtrlThreadReprov\"\x8a\x04\n\x12NetworkCtrlPayload\x12 \n\x03msg\x18\x01 \x01(\x0e\x32\x13.NetworkCtrlMsgType\x12\x17\n\x06status\x18\x02 \x01(\x0e\x32\x07.Status\x12\x30\n\x13\x63md_ctrl_wifi_reset\x18\x0b \x01(\x0b\x32\x11.CmdCtrlWifiResetH\x00\x12\x32\n\x14resp_ctrl_wifi_reset\x18\x0c \x01(\x0b\x32\x12.RespCtrlWifiResetH\x00\x12\x32\n\x14\x63md_ctrl_wifi_reprov\x18\r \x01(\x0b\x32\x12.CmdCtrlWifiReprovH\x00\x12\x34\n\x15resp_ctrl_wifi_reprov\x18\x0e \x01(\x0b\x32\x13.RespCtrlWifiReprovH\x00\x12\x34\n\x15\x63md_ctrl_thread_reset\x18\x0f \x01(\x0b\x32\x13.CmdCtrlThreadResetH\x00\x12\x36\n\x16resp_ctrl_thread_reset\x18\x10 \x01(\x0b\x32\x14.RespCtrlThreadResetH\x00\x12\x36\n\x16\x63md_ctrl_thread_reprov\x18\x11 \x01(\x0b\x32\x14.CmdCtrlThreadReprovH\x00\x12\x38\n\x17resp_ctrl_thread_reprov\x18\x12 \x01(\x0b\x32\x15.RespCtrlThreadReprovH\x00\x42\t\n\x07payload*\x8a\x02\n\x12NetworkCtrlMsgType\x12\x14\n\x10TypeCtrlReserved\x10\x00\x12\x18\n\x14TypeCmdCtrlWifiReset\x10\x01\x12\x19\n\x15TypeRespCtrlWifiReset\x10\x02\x12\x19\n\x15TypeCmdCtrlWifiReprov\x10\x03\x12\x1a\n\x16TypeRespCtrlWifiReprov\x10\x04\x12\x1a\n\x16TypeCmdCtrlThreadReset\x10\x05\x12\x1b\n\x17TypeRespCtrlThreadReset\x10\x06\x12\x1b\n\x17TypeCmdCtrlThreadReprov\x10\x07\x12\x1c\n\x18TypeRespCtrlThreadReprov\x10\x08\x62\x06proto3')
|
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'network_ctrl_pb2', globals())
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
_NETWORKCTRLMSGTYPE._serialized_start=741
|
||||
_NETWORKCTRLMSGTYPE._serialized_end=1007
|
||||
_CMDCTRLWIFIRESET._serialized_start=39
|
||||
_CMDCTRLWIFIRESET._serialized_end=57
|
||||
_RESPCTRLWIFIRESET._serialized_start=59
|
||||
_RESPCTRLWIFIRESET._serialized_end=78
|
||||
_CMDCTRLWIFIREPROV._serialized_start=80
|
||||
_CMDCTRLWIFIREPROV._serialized_end=99
|
||||
_RESPCTRLWIFIREPROV._serialized_start=101
|
||||
_RESPCTRLWIFIREPROV._serialized_end=121
|
||||
_CMDCTRLTHREADRESET._serialized_start=123
|
||||
_CMDCTRLTHREADRESET._serialized_end=143
|
||||
_RESPCTRLTHREADRESET._serialized_start=145
|
||||
_RESPCTRLTHREADRESET._serialized_end=166
|
||||
_CMDCTRLTHREADREPROV._serialized_start=168
|
||||
_CMDCTRLTHREADREPROV._serialized_end=189
|
||||
_RESPCTRLTHREADREPROV._serialized_start=191
|
||||
_RESPCTRLTHREADREPROV._serialized_end=213
|
||||
_NETWORKCTRLPAYLOAD._serialized_start=216
|
||||
_NETWORKCTRLPAYLOAD._serialized_end=738
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: network_scan.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf.internal import builder as _builder
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
import constants_pb2 as constants__pb2
|
||||
import network_constants_pb2 as network__constants__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12network_scan.proto\x1a\x0f\x63onstants.proto\x1a\x17network_constants.proto\"`\n\x10\x43mdScanWifiStart\x12\x10\n\x08\x62locking\x18\x01 \x01(\x08\x12\x0f\n\x07passive\x18\x02 \x01(\x08\x12\x16\n\x0egroup_channels\x18\x03 \x01(\r\x12\x11\n\tperiod_ms\x18\x04 \x01(\r\"<\n\x12\x43mdScanThreadStart\x12\x10\n\x08\x62locking\x18\x01 \x01(\x08\x12\x14\n\x0c\x63hannel_mask\x18\x02 \x01(\r\"\x13\n\x11RespScanWifiStart\"\x15\n\x13RespScanThreadStart\"\x13\n\x11\x43mdScanWifiStatus\"\x15\n\x13\x43mdScanThreadStatus\"A\n\x12RespScanWifiStatus\x12\x15\n\rscan_finished\x18\x01 \x01(\x08\x12\x14\n\x0cresult_count\x18\x02 \x01(\r\"C\n\x14RespScanThreadStatus\x12\x15\n\rscan_finished\x18\x01 \x01(\x08\x12\x14\n\x0cresult_count\x18\x02 \x01(\r\"7\n\x11\x43mdScanWifiResult\x12\x13\n\x0bstart_index\x18\x01 \x01(\r\x12\r\n\x05\x63ount\x18\x02 \x01(\r\"9\n\x13\x43mdScanThreadResult\x12\x13\n\x0bstart_index\x18\x01 \x01(\r\x12\r\n\x05\x63ount\x18\x02 \x01(\r\"i\n\x0eWiFiScanResult\x12\x0c\n\x04ssid\x18\x01 \x01(\x0c\x12\x0f\n\x07\x63hannel\x18\x02 \x01(\r\x12\x0c\n\x04rssi\x18\x03 \x01(\x05\x12\r\n\x05\x62ssid\x18\x04 \x01(\x0c\x12\x1b\n\x04\x61uth\x18\x05 \x01(\x0e\x32\r.WifiAuthMode\"\x8a\x01\n\x10ThreadScanResult\x12\x0e\n\x06pan_id\x18\x01 \x01(\r\x12\x0f\n\x07\x63hannel\x18\x02 \x01(\r\x12\x0c\n\x04rssi\x18\x03 \x01(\x05\x12\x0b\n\x03lqi\x18\x04 \x01(\r\x12\x10\n\x08\x65xt_addr\x18\x05 \x01(\x0c\x12\x14\n\x0cnetwork_name\x18\x06 \x01(\t\x12\x12\n\next_pan_id\x18\x07 \x01(\x0c\"6\n\x12RespScanWifiResult\x12 \n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x0f.WiFiScanResult\":\n\x14RespScanThreadResult\x12\"\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x11.ThreadScanResult\"\xe6\x05\n\x12NetworkScanPayload\x12 \n\x03msg\x18\x01 \x01(\x0e\x32\x13.NetworkScanMsgType\x12\x17\n\x06status\x18\x02 \x01(\x0e\x32\x07.Status\x12\x30\n\x13\x63md_scan_wifi_start\x18\n \x01(\x0b\x32\x11.CmdScanWifiStartH\x00\x12\x32\n\x14resp_scan_wifi_start\x18\x0b \x01(\x0b\x32\x12.RespScanWifiStartH\x00\x12\x32\n\x14\x63md_scan_wifi_status\x18\x0c \x01(\x0b\x32\x12.CmdScanWifiStatusH\x00\x12\x34\n\x15resp_scan_wifi_status\x18\r \x01(\x0b\x32\x13.RespScanWifiStatusH\x00\x12\x32\n\x14\x63md_scan_wifi_result\x18\x0e \x01(\x0b\x32\x12.CmdScanWifiResultH\x00\x12\x34\n\x15resp_scan_wifi_result\x18\x0f \x01(\x0b\x32\x13.RespScanWifiResultH\x00\x12\x34\n\x15\x63md_scan_thread_start\x18\x10 \x01(\x0b\x32\x13.CmdScanThreadStartH\x00\x12\x36\n\x16resp_scan_thread_start\x18\x11 \x01(\x0b\x32\x14.RespScanThreadStartH\x00\x12\x36\n\x16\x63md_scan_thread_status\x18\x12 \x01(\x0b\x32\x14.CmdScanThreadStatusH\x00\x12\x38\n\x17resp_scan_thread_status\x18\x13 \x01(\x0b\x32\x15.RespScanThreadStatusH\x00\x12\x36\n\x16\x63md_scan_thread_result\x18\x14 \x01(\x0b\x32\x14.CmdScanThreadResultH\x00\x12\x38\n\x17resp_scan_thread_result\x18\x15 \x01(\x0b\x32\x15.RespScanThreadResultH\x00\x42\t\n\x07payload*\xe6\x02\n\x12NetworkScanMsgType\x12\x18\n\x14TypeCmdScanWifiStart\x10\x00\x12\x19\n\x15TypeRespScanWifiStart\x10\x01\x12\x19\n\x15TypeCmdScanWifiStatus\x10\x02\x12\x1a\n\x16TypeRespScanWifiStatus\x10\x03\x12\x19\n\x15TypeCmdScanWifiResult\x10\x04\x12\x1a\n\x16TypeRespScanWifiResult\x10\x05\x12\x1a\n\x16TypeCmdScanThreadStart\x10\x06\x12\x1b\n\x17TypeRespScanThreadStart\x10\x07\x12\x1b\n\x17TypeCmdScanThreadStatus\x10\x08\x12\x1c\n\x18TypeRespScanThreadStatus\x10\t\x12\x1b\n\x17TypeCmdScanThreadResult\x10\n\x12\x1c\n\x18TypeRespScanThreadResult\x10\x0b\x62\x06proto3')
|
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'network_scan_pb2', globals())
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
_NETWORKSCANMSGTYPE._serialized_start=1674
|
||||
_NETWORKSCANMSGTYPE._serialized_end=2032
|
||||
_CMDSCANWIFISTART._serialized_start=64
|
||||
_CMDSCANWIFISTART._serialized_end=160
|
||||
_CMDSCANTHREADSTART._serialized_start=162
|
||||
_CMDSCANTHREADSTART._serialized_end=222
|
||||
_RESPSCANWIFISTART._serialized_start=224
|
||||
_RESPSCANWIFISTART._serialized_end=243
|
||||
_RESPSCANTHREADSTART._serialized_start=245
|
||||
_RESPSCANTHREADSTART._serialized_end=266
|
||||
_CMDSCANWIFISTATUS._serialized_start=268
|
||||
_CMDSCANWIFISTATUS._serialized_end=287
|
||||
_CMDSCANTHREADSTATUS._serialized_start=289
|
||||
_CMDSCANTHREADSTATUS._serialized_end=310
|
||||
_RESPSCANWIFISTATUS._serialized_start=312
|
||||
_RESPSCANWIFISTATUS._serialized_end=377
|
||||
_RESPSCANTHREADSTATUS._serialized_start=379
|
||||
_RESPSCANTHREADSTATUS._serialized_end=446
|
||||
_CMDSCANWIFIRESULT._serialized_start=448
|
||||
_CMDSCANWIFIRESULT._serialized_end=503
|
||||
_CMDSCANTHREADRESULT._serialized_start=505
|
||||
_CMDSCANTHREADRESULT._serialized_end=562
|
||||
_WIFISCANRESULT._serialized_start=564
|
||||
_WIFISCANRESULT._serialized_end=669
|
||||
_THREADSCANRESULT._serialized_start=672
|
||||
_THREADSCANRESULT._serialized_end=810
|
||||
_RESPSCANWIFIRESULT._serialized_start=812
|
||||
_RESPSCANWIFIRESULT._serialized_end=866
|
||||
_RESPSCANTHREADRESULT._serialized_start=868
|
||||
_RESPSCANTHREADRESULT._serialized_end=926
|
||||
_NETWORKSCANPAYLOAD._serialized_start=929
|
||||
_NETWORKSCANPAYLOAD._serialized_end=1671
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
#include <esp_wifi.h>
|
||||
#endif
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
#include <esp_openthread.h>
|
||||
#endif
|
||||
#include <esp_netif.h>
|
||||
|
||||
#include "network_provisioning/network_config.h"
|
||||
#include "network_provisioning/network_scan.h"
|
||||
#include "network_ctrl.h"
|
||||
#include "network_provisioning/manager.h"
|
||||
#include "network_provisioning_priv.h"
|
||||
|
||||
#if defined(CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI) || defined(CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD)
|
||||
static const char *TAG = "network_prov_handlers";
|
||||
|
||||
/* Provide definition of network_prov_ctx_t */
|
||||
struct network_prov_ctx {
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
wifi_config_t wifi_cfg;
|
||||
#endif
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
otOperationalDatasetTlvs thread_dataset;
|
||||
#endif
|
||||
};
|
||||
|
||||
static void free_network_prov_ctx(network_prov_ctx_t **ctx)
|
||||
{
|
||||
free(*ctx);
|
||||
*ctx = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
static wifi_config_t *get_wifi_config(network_prov_ctx_t **ctx)
|
||||
{
|
||||
return (*ctx ? & (*ctx)->wifi_cfg : NULL);
|
||||
}
|
||||
|
||||
static wifi_config_t *new_wifi_config(network_prov_ctx_t **ctx)
|
||||
{
|
||||
free(*ctx);
|
||||
(*ctx) = (network_prov_ctx_t *) calloc(1, sizeof(network_prov_ctx_t));
|
||||
return get_wifi_config(ctx);
|
||||
}
|
||||
|
||||
static esp_err_t wifi_get_status_handler(network_prov_config_get_wifi_data_t *resp_data, network_prov_ctx_t **ctx)
|
||||
{
|
||||
/* Initialize to zero */
|
||||
memset(resp_data, 0, sizeof(network_prov_config_get_wifi_data_t));
|
||||
|
||||
if (network_prov_mgr_get_wifi_state(&resp_data->wifi_state) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Network provisioning manager for Wi-Fi not running");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (resp_data->wifi_state == NETWORK_PROV_WIFI_STA_CONNECTED) {
|
||||
ESP_LOGD(TAG, "Got state : connected");
|
||||
|
||||
/* IP Addr assigned to STA */
|
||||
esp_netif_ip_info_t ip_info;
|
||||
esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info);
|
||||
esp_ip4addr_ntoa(&ip_info.ip, resp_data->conn_info.ip_addr, sizeof(resp_data->conn_info.ip_addr));
|
||||
|
||||
|
||||
/* AP information to which STA is connected */
|
||||
wifi_ap_record_t ap_info;
|
||||
esp_wifi_sta_get_ap_info(&ap_info);
|
||||
memcpy(resp_data->conn_info.bssid, (char *)ap_info.bssid, sizeof(ap_info.bssid));
|
||||
memcpy(resp_data->conn_info.ssid, (char *)ap_info.ssid, sizeof(ap_info.ssid));
|
||||
resp_data->conn_info.channel = ap_info.primary;
|
||||
resp_data->conn_info.auth_mode = ap_info.authmode;
|
||||
|
||||
/* Tell manager to stop provisioning service */
|
||||
network_prov_mgr_done();
|
||||
} else if (resp_data->wifi_state == NETWORK_PROV_WIFI_STA_DISCONNECTED) {
|
||||
ESP_LOGD(TAG, "Got state : disconnected");
|
||||
|
||||
/* If disconnected, convey reason */
|
||||
network_prov_mgr_get_wifi_disconnect_reason(&resp_data->fail_reason);
|
||||
} else {
|
||||
if (network_prov_mgr_get_wifi_remaining_conn_attempts(&resp_data->connecting_info.attempts_remaining) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "network provisioning manager not running");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
ESP_LOGD(TAG, "Got state : connecting");
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t wifi_set_config_handler(const network_prov_config_set_wifi_data_t *req_data, network_prov_ctx_t **ctx)
|
||||
{
|
||||
wifi_config_t *wifi_cfg = get_wifi_config(ctx);
|
||||
if (wifi_cfg) {
|
||||
free_network_prov_ctx(ctx);
|
||||
}
|
||||
|
||||
wifi_cfg = new_wifi_config(ctx);
|
||||
if (!wifi_cfg) {
|
||||
ESP_LOGE(TAG, "Unable to allocate Wi-Fi config");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Wi-Fi Credentials Received");
|
||||
|
||||
/* Using memcpy allows the max SSID length to be 32 bytes (as per 802.11 standard).
|
||||
* But this doesn't guarantee that the saved SSID will be null terminated, because
|
||||
* wifi_cfg->sta.ssid is also 32 bytes long (without extra 1 byte for null character).
|
||||
* Although, this is not a matter for concern because esp_wifi library reads the SSID
|
||||
* upto 32 bytes in absence of null termination */
|
||||
const size_t ssid_len = strnlen(req_data->ssid, sizeof(wifi_cfg->sta.ssid));
|
||||
/* Ensure SSID less than 32 bytes is null terminated */
|
||||
memset(wifi_cfg->sta.ssid, 0, sizeof(wifi_cfg->sta.ssid));
|
||||
memcpy(wifi_cfg->sta.ssid, req_data->ssid, ssid_len);
|
||||
|
||||
/* Using strlcpy allows both max passphrase length (63 bytes) and ensures null termination
|
||||
* because size of wifi_cfg->sta.password is 64 bytes (1 extra byte for null character) */
|
||||
strlcpy((char *) wifi_cfg->sta.password, req_data->password, sizeof(wifi_cfg->sta.password));
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_WIFI_STA_ALL_CHANNEL_SCAN
|
||||
wifi_cfg->sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
|
||||
#else /* CONFIG_NETWORK_PROV_WIFI_STA_FAST_SCAN */
|
||||
wifi_cfg->sta.scan_method = WIFI_FAST_SCAN;
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t wifi_apply_config_handler(network_prov_ctx_t **ctx)
|
||||
{
|
||||
wifi_config_t *wifi_cfg = get_wifi_config(ctx);
|
||||
if (!wifi_cfg) {
|
||||
ESP_LOGE(TAG, "Wi-Fi config not set");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
esp_err_t ret = network_prov_mgr_configure_wifi_sta(wifi_cfg);
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGD(TAG, "Wi-Fi Credentials Applied");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to apply Wi-Fi Credentials");
|
||||
}
|
||||
|
||||
free_network_prov_ctx(ctx);
|
||||
return ret;
|
||||
}
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
static otOperationalDatasetTlvs *get_thread_dataset(network_prov_ctx_t **ctx)
|
||||
{
|
||||
return (*ctx ? & (*ctx)->thread_dataset : NULL);
|
||||
}
|
||||
|
||||
static otOperationalDatasetTlvs *new_thread_dataset(network_prov_ctx_t **ctx)
|
||||
{
|
||||
free(*ctx);
|
||||
(*ctx) = (network_prov_ctx_t *) calloc(1, sizeof(network_prov_ctx_t));
|
||||
return get_thread_dataset(ctx);
|
||||
}
|
||||
|
||||
static esp_err_t thread_get_status_handler(network_prov_config_get_thread_data_t *resp_data, network_prov_ctx_t **ctx)
|
||||
{
|
||||
/* Initialize to zero */
|
||||
memset(resp_data, 0, sizeof(network_prov_config_get_thread_data_t));
|
||||
|
||||
if (network_prov_mgr_get_thread_state(&resp_data->thread_state) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Network provisioning manager not running");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (resp_data->thread_state == NETWORK_PROV_THREAD_ATTACHED) {
|
||||
ESP_LOGD(TAG, "Got state : attached");
|
||||
otOperationalDataset dataset;
|
||||
if (otDatasetGetActive(esp_openthread_get_instance(), &dataset) != OT_ERROR_NONE) {
|
||||
ESP_LOGE(TAG, "Failed to get Thread dataset");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
resp_data->conn_info.channel = dataset.mChannel;
|
||||
memcpy(resp_data->conn_info.ext_pan_id, dataset.mExtendedPanId.m8, sizeof(dataset.mExtendedPanId.m8));
|
||||
strncpy(resp_data->conn_info.name, dataset.mNetworkName.m8,
|
||||
strnlen(dataset.mNetworkName.m8, sizeof(dataset.mNetworkName.m8)));
|
||||
resp_data->conn_info.pan_id = dataset.mPanId;
|
||||
/* Tell manager to stop provisioning service */
|
||||
network_prov_mgr_done();
|
||||
} else if (resp_data->thread_state == NETWORK_PROV_THREAD_DETACHED) {
|
||||
ESP_LOGD(TAG, "Got state : disconnected");
|
||||
|
||||
/* If disconnected, convey reason */
|
||||
network_prov_mgr_get_thread_detached_reason(&resp_data->fail_reason);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Got state : attaching");
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t thread_set_config_handler(const network_prov_config_set_thread_data_t *req_data, network_prov_ctx_t **ctx)
|
||||
{
|
||||
otOperationalDatasetTlvs *thread_dataset = get_thread_dataset(ctx);
|
||||
if (thread_dataset) {
|
||||
free_network_prov_ctx(ctx);
|
||||
}
|
||||
|
||||
thread_dataset = new_thread_dataset(ctx);
|
||||
if (!thread_dataset) {
|
||||
ESP_LOGE(TAG, "Unable to allocate Thread dataset");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Thread Dataset Received");
|
||||
|
||||
thread_dataset->mLength = req_data->length;
|
||||
memcpy(thread_dataset->mTlvs, req_data->dataset, thread_dataset->mLength);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t thread_apply_config_handler(network_prov_ctx_t **ctx)
|
||||
{
|
||||
otOperationalDatasetTlvs *thread_dataset = get_thread_dataset(ctx);
|
||||
if (!thread_dataset) {
|
||||
ESP_LOGE(TAG, "Thread Dataset not set");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
esp_err_t ret = network_prov_mgr_configure_thread_dataset(thread_dataset);
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGD(TAG, "Thread Dataset Applied");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to apply Thread Dataset");
|
||||
}
|
||||
|
||||
free_network_prov_ctx(ctx);
|
||||
return ret;
|
||||
}
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
|
||||
|
||||
esp_err_t get_network_prov_handlers(network_prov_config_handlers_t *ptr)
|
||||
{
|
||||
if (!ptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
ptr->wifi_get_status_handler = wifi_get_status_handler;
|
||||
ptr->wifi_set_config_handler = wifi_set_config_handler;
|
||||
ptr->wifi_apply_config_handler = wifi_apply_config_handler;
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
ptr->thread_get_status_handler = thread_get_status_handler;
|
||||
ptr->thread_set_config_handler = thread_set_config_handler;
|
||||
ptr->thread_apply_config_handler = thread_apply_config_handler;
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
ptr->ctx = NULL;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
static esp_err_t wifi_scan_start(bool blocking, bool passive,
|
||||
uint8_t group_channels, uint32_t period_ms,
|
||||
network_prov_scan_ctx_t **ctx)
|
||||
{
|
||||
return network_prov_mgr_wifi_scan_start(blocking, passive, group_channels, period_ms);
|
||||
}
|
||||
|
||||
static esp_err_t wifi_scan_status(bool *scan_finished,
|
||||
uint16_t *result_count,
|
||||
network_prov_scan_ctx_t **ctx)
|
||||
{
|
||||
*scan_finished = network_prov_mgr_wifi_scan_finished();
|
||||
*result_count = network_prov_mgr_wifi_scan_result_count();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t wifi_scan_result(uint16_t result_index,
|
||||
network_prov_scan_wifi_result_t *result,
|
||||
network_prov_scan_ctx_t **ctx)
|
||||
{
|
||||
const wifi_ap_record_t *record = network_prov_mgr_wifi_scan_result(result_index);
|
||||
if (!record) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Compile time check ensures memory safety in case SSID length in
|
||||
* record / result structure definition changes in future */
|
||||
_Static_assert(sizeof(result->ssid) == sizeof(record->ssid),
|
||||
"source and destination should be of same size");
|
||||
memcpy(result->ssid, record->ssid, sizeof(record->ssid));
|
||||
memcpy(result->bssid, record->bssid, sizeof(record->bssid));
|
||||
result->channel = record->primary;
|
||||
result->rssi = record->rssi;
|
||||
result->auth = record->authmode;
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
static esp_err_t thread_scan_start(bool blocking, uint32_t channel_mask, network_prov_scan_ctx_t **ctx)
|
||||
{
|
||||
return network_prov_mgr_thread_scan_start(blocking, channel_mask);
|
||||
}
|
||||
|
||||
static esp_err_t thread_scan_status(bool *scan_finished,
|
||||
uint16_t *result_count,
|
||||
network_prov_scan_ctx_t **ctx)
|
||||
{
|
||||
*scan_finished = network_prov_mgr_thread_scan_finished();
|
||||
*result_count = network_prov_mgr_thread_scan_result_count();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t thread_scan_result(uint16_t result_index,
|
||||
network_prov_scan_thread_result_t *result,
|
||||
network_prov_scan_ctx_t **ctx)
|
||||
{
|
||||
const otActiveScanResult *record = network_prov_mgr_thread_scan_result(result_index);
|
||||
if (!record) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
result->channel = record->mChannel;
|
||||
result->pan_id = record->mPanId;
|
||||
result->rssi = record->mRssi;
|
||||
result->lqi = record->mLqi;
|
||||
memcpy(result->ext_addr, record->mExtAddress.m8, sizeof(record->mExtAddress.m8));
|
||||
|
||||
if (record->mDiscover) {
|
||||
memcpy(result->ext_pan_id, record->mExtendedPanId.m8, sizeof(result->ext_pan_id));
|
||||
memcpy(result->network_name, record->mNetworkName.m8, sizeof(record->mNetworkName.m8));
|
||||
} else {
|
||||
memset(result->ext_pan_id, 0, sizeof(result->ext_pan_id));
|
||||
memset(result->network_name, 0, sizeof(result->network_name));
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
|
||||
esp_err_t get_network_scan_handlers(network_prov_scan_handlers_t *ptr)
|
||||
{
|
||||
if (!ptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
ptr->wifi_scan_start = wifi_scan_start;
|
||||
ptr->wifi_scan_status = wifi_scan_status;
|
||||
ptr->wifi_scan_result = wifi_scan_result;
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
ptr->thread_scan_start = thread_scan_start;
|
||||
ptr->thread_scan_status = thread_scan_status;
|
||||
ptr->thread_scan_result = thread_scan_result;
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
ptr->ctx = NULL;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
static esp_err_t wifi_ctrl_reset(void)
|
||||
{
|
||||
return network_prov_mgr_reset_wifi_sm_state_on_failure();
|
||||
}
|
||||
|
||||
static esp_err_t wifi_ctrl_reprov(void)
|
||||
{
|
||||
return network_prov_mgr_reset_wifi_sm_state_for_reprovision();
|
||||
}
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
static esp_err_t thread_ctrl_reset(void)
|
||||
{
|
||||
return network_prov_mgr_reset_thread_sm_state_on_failure();
|
||||
}
|
||||
|
||||
static esp_err_t thread_ctrl_reprov(void)
|
||||
{
|
||||
return network_prov_mgr_reset_thread_sm_state_for_reprovision();
|
||||
}
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
|
||||
esp_err_t get_network_ctrl_handlers(network_ctrl_handlers_t *ptr)
|
||||
{
|
||||
if (!ptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
ptr->wifi_ctrl_reset = wifi_ctrl_reset;
|
||||
ptr->wifi_ctrl_reprov = wifi_ctrl_reprov;
|
||||
#endif
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
ptr->thread_ctrl_reset = thread_ctrl_reset;
|
||||
ptr->thread_ctrl_reprov = thread_ctrl_reprov;
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,546 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
#include "network_constants.pb-c.h"
|
||||
#include "network_config.pb-c.h"
|
||||
|
||||
#include <network_provisioning/network_config.h>
|
||||
|
||||
static const char *TAG = "NetworkProvConfig";
|
||||
|
||||
typedef struct network_prov_config_cmd {
|
||||
int cmd_num;
|
||||
esp_err_t (*command_handler)(NetworkConfigPayload *req,
|
||||
NetworkConfigPayload *resp, void *priv_data);
|
||||
} network_prov_config_cmd_t;
|
||||
|
||||
static esp_err_t cmd_get_status_handler(NetworkConfigPayload *req,
|
||||
NetworkConfigPayload *resp, void *priv_data);
|
||||
|
||||
static esp_err_t cmd_set_config_handler(NetworkConfigPayload *req,
|
||||
NetworkConfigPayload *resp, void *priv_data);
|
||||
|
||||
static esp_err_t cmd_apply_config_handler(NetworkConfigPayload *req,
|
||||
NetworkConfigPayload *resp, void *priv_data);
|
||||
|
||||
static network_prov_config_cmd_t cmd_table[] = {
|
||||
{
|
||||
.cmd_num = NETWORK_CONFIG_MSG_TYPE__TypeCmdGetWifiStatus,
|
||||
.command_handler = cmd_get_status_handler
|
||||
},
|
||||
{
|
||||
.cmd_num = NETWORK_CONFIG_MSG_TYPE__TypeCmdSetWifiConfig,
|
||||
.command_handler = cmd_set_config_handler
|
||||
},
|
||||
{
|
||||
.cmd_num = NETWORK_CONFIG_MSG_TYPE__TypeCmdApplyWifiConfig,
|
||||
.command_handler = cmd_apply_config_handler
|
||||
},
|
||||
{
|
||||
.cmd_num = NETWORK_CONFIG_MSG_TYPE__TypeCmdGetThreadStatus,
|
||||
.command_handler = cmd_get_status_handler
|
||||
},
|
||||
{
|
||||
.cmd_num = NETWORK_CONFIG_MSG_TYPE__TypeCmdSetThreadConfig,
|
||||
.command_handler = cmd_set_config_handler
|
||||
},
|
||||
{
|
||||
.cmd_num = NETWORK_CONFIG_MSG_TYPE__TypeCmdApplyThreadConfig,
|
||||
.command_handler = cmd_apply_config_handler
|
||||
}
|
||||
};
|
||||
|
||||
static esp_err_t cmd_get_status_handler(NetworkConfigPayload *req,
|
||||
NetworkConfigPayload *resp, void *priv_data)
|
||||
{
|
||||
ESP_LOGD(TAG, "Enter cmd_get_status_handler");
|
||||
network_prov_config_handlers_t *h = (network_prov_config_handlers_t *) priv_data;
|
||||
if (!h) {
|
||||
ESP_LOGE(TAG, "Command invoked without handlers");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (req->msg == NETWORK_CONFIG_MSG_TYPE__TypeCmdGetWifiStatus) {
|
||||
RespGetWifiStatus *resp_payload = (RespGetWifiStatus *) malloc(sizeof(RespGetWifiStatus));
|
||||
if (!resp_payload) {
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_get_wifi_status__init(resp_payload);
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
network_prov_config_get_wifi_data_t resp_data;
|
||||
if (h->wifi_get_status_handler) {
|
||||
if (h->wifi_get_status_handler(&resp_data, &h->ctx) == ESP_OK) {
|
||||
if (resp_data.wifi_state == NETWORK_PROV_WIFI_STA_CONNECTING) {
|
||||
resp_payload->wifi_sta_state = WIFI_STATION_STATE__Connecting;
|
||||
resp_payload->state_case = RESP_GET_WIFI_STATUS__STATE_WIFI_CONNECTED;
|
||||
} else if (resp_data.wifi_state == NETWORK_PROV_WIFI_STA_CONNECTED) {
|
||||
resp_payload->wifi_sta_state = WIFI_STATION_STATE__Connected;
|
||||
resp_payload->state_case = RESP_GET_WIFI_STATUS__STATE_WIFI_CONNECTED;
|
||||
WifiConnectedState *connected = (WifiConnectedState *)(
|
||||
malloc(sizeof(WifiConnectedState)));
|
||||
if (!connected) {
|
||||
free(resp_payload);
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_payload->wifi_connected = connected;
|
||||
wifi_connected_state__init(connected);
|
||||
|
||||
connected->ip4_addr = strdup(resp_data.conn_info.ip_addr);
|
||||
if (connected->ip4_addr == NULL) {
|
||||
free(connected);
|
||||
free(resp_payload);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
connected->bssid.len = sizeof(resp_data.conn_info.bssid);
|
||||
connected->bssid.data = (uint8_t *) strndup(resp_data.conn_info.bssid,
|
||||
sizeof(resp_data.conn_info.bssid));
|
||||
if (connected->bssid.data == NULL) {
|
||||
free(connected->ip4_addr);
|
||||
free(connected);
|
||||
free(resp_payload);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
connected->ssid.len = strlen(resp_data.conn_info.ssid);
|
||||
connected->ssid.data = (uint8_t *) strdup(resp_data.conn_info.ssid);
|
||||
if (connected->ssid.data == NULL) {
|
||||
free(connected->bssid.data);
|
||||
free(connected->ip4_addr);
|
||||
free(connected);
|
||||
free(resp_payload);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
connected->channel = resp_data.conn_info.channel;
|
||||
connected->auth_mode = resp_data.conn_info.auth_mode;
|
||||
} else if (resp_data.wifi_state == NETWORK_PROV_WIFI_STA_DISCONNECTED) {
|
||||
resp_payload->wifi_sta_state = WIFI_STATION_STATE__ConnectionFailed;
|
||||
resp_payload->state_case = RESP_GET_WIFI_STATUS__STATE_WIFI_FAIL_REASON;
|
||||
|
||||
if (resp_data.fail_reason == NETWORK_PROV_WIFI_STA_AUTH_ERROR) {
|
||||
resp_payload->wifi_fail_reason = WIFI_CONNECT_FAILED_REASON__AuthError;
|
||||
} else if (resp_data.fail_reason == NETWORK_PROV_WIFI_STA_AP_NOT_FOUND) {
|
||||
resp_payload->wifi_fail_reason = WIFI_CONNECT_FAILED_REASON__WifiNetworkNotFound;
|
||||
}
|
||||
} else if (resp_data.wifi_state == NETWORK_PROV_WIFI_STA_CONN_ATTEMPT_FAILED) {
|
||||
resp_payload->wifi_sta_state = WIFI_STATION_STATE__Connecting;
|
||||
resp_payload->state_case = RESP_GET_WIFI_STATUS__STATE_ATTEMPT_FAILED;
|
||||
WifiAttemptFailed *attempt_failed = (WifiAttemptFailed *)(
|
||||
calloc(1, sizeof(WifiAttemptFailed)));
|
||||
if (!attempt_failed) {
|
||||
free(resp_payload);
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
wifi_attempt_failed__init(attempt_failed);
|
||||
attempt_failed->attempts_remaining = resp_data.connecting_info.attempts_remaining;
|
||||
resp_payload->attempt_failed = attempt_failed;
|
||||
}
|
||||
resp_payload->status = STATUS__Success;
|
||||
} else {
|
||||
resp_payload->status = STATUS__InternalError;
|
||||
}
|
||||
} else {
|
||||
resp_payload->status = STATUS__InternalError;
|
||||
}
|
||||
#else // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
resp_payload->status = STATUS__InvalidArgument;
|
||||
#endif // !CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
resp->payload_case = NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_GET_WIFI_STATUS;
|
||||
resp->resp_get_wifi_status = resp_payload;
|
||||
} else if (req->msg == NETWORK_CONFIG_MSG_TYPE__TypeCmdGetThreadStatus) {
|
||||
RespGetThreadStatus *resp_payload = (RespGetThreadStatus *) malloc(sizeof(RespGetThreadStatus));
|
||||
if (!resp_payload) {
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_get_thread_status__init(resp_payload);
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
network_prov_config_get_thread_data_t resp_data;
|
||||
if (h->thread_get_status_handler) {
|
||||
if (h->thread_get_status_handler(&resp_data, &h->ctx) == ESP_OK) {
|
||||
if (resp_data.thread_state == NETWORK_PROV_THREAD_ATTACHING) {
|
||||
resp_payload->thread_state = THREAD_NETWORK_STATE__Attaching;
|
||||
resp_payload->state_case = RESP_GET_THREAD_STATUS__STATE_THREAD_ATTACHED;
|
||||
} else if (resp_data.thread_state == NETWORK_PROV_THREAD_ATTACHED) {
|
||||
resp_payload->thread_state = THREAD_NETWORK_STATE__Attached;
|
||||
resp_payload->state_case = RESP_GET_THREAD_STATUS__STATE_THREAD_ATTACHED;
|
||||
ThreadAttachState *attached = (ThreadAttachState *)malloc(sizeof(ThreadAttachState));
|
||||
if (!attached) {
|
||||
free(resp_payload);
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_payload->thread_attached = attached;
|
||||
thread_attach_state__init(attached);
|
||||
attached->channel = resp_data.conn_info.channel;
|
||||
attached->ext_pan_id.len = sizeof(resp_data.conn_info.ext_pan_id);
|
||||
attached->ext_pan_id.data = (uint8_t *)malloc(attached->ext_pan_id.len);
|
||||
if (!attached->ext_pan_id.data) {
|
||||
free(attached);
|
||||
free(resp_payload);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
memcpy(attached->ext_pan_id.data, resp_data.conn_info.ext_pan_id, sizeof(resp_data.conn_info.ext_pan_id));
|
||||
attached->pan_id = resp_data.conn_info.pan_id;
|
||||
|
||||
attached->name = (char *)malloc(sizeof(resp_data.conn_info.name));
|
||||
if (!attached->name) {
|
||||
free(attached->ext_pan_id.data);
|
||||
free(attached);
|
||||
free(resp_payload);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
memcpy(attached->name, resp_data.conn_info.name, sizeof(resp_data.conn_info.name));
|
||||
} else if (resp_data.thread_state == NETWORK_PROV_THREAD_DETACHED) {
|
||||
resp_payload->thread_state = THREAD_NETWORK_STATE__AttachingFailed;
|
||||
resp_payload->state_case = RESP_GET_THREAD_STATUS__STATE_THREAD_FAIL_REASON;
|
||||
|
||||
if (resp_data.fail_reason == NETWORK_PROV_THREAD_DATASET_INVALID) {
|
||||
resp_payload->thread_fail_reason = THREAD_ATTACH_FAILED_REASON__DatasetInvalid;
|
||||
} else if (resp_data.fail_reason == NETWORK_PROV_THREAD_NETWORK_NOT_FOUND) {
|
||||
resp_payload->thread_fail_reason = THREAD_ATTACH_FAILED_REASON__ThreadNetworkNotFound;
|
||||
}
|
||||
}
|
||||
resp_payload->status = STATUS__Success;
|
||||
} else {
|
||||
resp_payload->status = STATUS__InternalError;
|
||||
}
|
||||
} else {
|
||||
resp_payload->status = STATUS__InternalError;
|
||||
}
|
||||
#else // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
resp_payload->status = STATUS__InvalidArgument;
|
||||
#endif // !CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
resp->payload_case = NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_GET_THREAD_STATUS;
|
||||
resp->resp_get_thread_status = resp_payload;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t cmd_set_config_handler(NetworkConfigPayload *req,
|
||||
NetworkConfigPayload *resp, void *priv_data)
|
||||
{
|
||||
ESP_LOGD(TAG, "Enter cmd_set_config_handler");
|
||||
network_prov_config_handlers_t *h = (network_prov_config_handlers_t *) priv_data;
|
||||
if (!h) {
|
||||
ESP_LOGE(TAG, "Command invoked without handlers");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (req->msg == NETWORK_CONFIG_MSG_TYPE__TypeCmdSetWifiConfig) {
|
||||
RespSetWifiConfig *resp_payload = (RespSetWifiConfig *) malloc(sizeof(RespSetWifiConfig));
|
||||
if (resp_payload == NULL) {
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_set_wifi_config__init(resp_payload);
|
||||
|
||||
if (req->payload_case != NETWORK_CONFIG_PAYLOAD__PAYLOAD_CMD_SET_WIFI_CONFIG || !req->cmd_set_wifi_config) {
|
||||
ESP_LOGE(TAG, "Invalid set WiFi config command");
|
||||
resp->resp_set_wifi_config = resp_payload;
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
network_prov_config_set_wifi_data_t req_data;
|
||||
memset(&req_data, 0, sizeof(req_data));
|
||||
|
||||
/* Check arguments provided in protobuf packet:
|
||||
* - SSID / Passphrase string length must be within the standard limits
|
||||
* - BSSID must either be NULL or have length equal to that imposed by the standard
|
||||
* If any of these conditions are not satisfied, don't invoke the handler and
|
||||
* send error status without closing connection */
|
||||
resp_payload->status = STATUS__InvalidArgument;
|
||||
if (req->cmd_set_wifi_config->bssid.len != 0 &&
|
||||
req->cmd_set_wifi_config->bssid.len != sizeof(req_data.bssid)) {
|
||||
ESP_LOGD(TAG, "Received invalid BSSID");
|
||||
} else if (req->cmd_set_wifi_config->ssid.len >= sizeof(req_data.ssid)) {
|
||||
ESP_LOGD(TAG, "Received invalid SSID");
|
||||
} else if (req->cmd_set_wifi_config->passphrase.len >= sizeof(req_data.password)) {
|
||||
ESP_LOGD(TAG, "Received invalid Passphrase");
|
||||
} else {
|
||||
/* The received SSID and Passphrase are not NULL terminated so
|
||||
* we memcpy over zeroed out arrays. Above length checks ensure
|
||||
* that there is at least 1 extra byte for null termination */
|
||||
memcpy(req_data.ssid, req->cmd_set_wifi_config->ssid.data,
|
||||
req->cmd_set_wifi_config->ssid.len);
|
||||
memcpy(req_data.password, req->cmd_set_wifi_config->passphrase.data,
|
||||
req->cmd_set_wifi_config->passphrase.len);
|
||||
memcpy(req_data.bssid, req->cmd_set_wifi_config->bssid.data,
|
||||
req->cmd_set_wifi_config->bssid.len);
|
||||
req_data.channel = req->cmd_set_wifi_config->channel;
|
||||
if (h->wifi_set_config_handler(&req_data, &h->ctx) == ESP_OK) {
|
||||
resp_payload->status = STATUS__Success;
|
||||
} else {
|
||||
resp_payload->status = STATUS__InternalError;
|
||||
}
|
||||
}
|
||||
#else // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
resp_payload->status = STATUS__InvalidArgument;
|
||||
#endif // !CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
resp->payload_case = NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_SET_WIFI_CONFIG;
|
||||
resp->resp_set_wifi_config = resp_payload;
|
||||
} else if (req->msg == NETWORK_CONFIG_MSG_TYPE__TypeCmdSetThreadConfig) {
|
||||
RespSetThreadConfig *resp_payload = (RespSetThreadConfig *) malloc(sizeof(RespSetThreadConfig));
|
||||
if (resp_payload == NULL) {
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_set_thread_config__init(resp_payload);
|
||||
|
||||
if (req->payload_case != NETWORK_CONFIG_PAYLOAD__PAYLOAD_CMD_SET_THREAD_CONFIG || !req->cmd_set_thread_config) {
|
||||
ESP_LOGE(TAG, "Invalid set Thread config command");
|
||||
resp->resp_set_thread_config = resp_payload;
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
network_prov_config_set_thread_data_t req_data;
|
||||
memset(&req_data, 0, sizeof(req_data));
|
||||
resp_payload->status = STATUS__InvalidArgument;
|
||||
if (req->cmd_set_thread_config->dataset.len > sizeof(req_data.dataset)) {
|
||||
ESP_LOGD(TAG, "Received invalid dataset");
|
||||
} else {
|
||||
memcpy(req_data.dataset, req->cmd_set_thread_config->dataset.data,
|
||||
req->cmd_set_thread_config->dataset.len);
|
||||
req_data.length = req->cmd_set_thread_config->dataset.len;
|
||||
if (h->thread_set_config_handler(&req_data, &h->ctx) == ESP_OK) {
|
||||
resp_payload->status = STATUS__Success;
|
||||
} else {
|
||||
resp_payload->status = STATUS__InternalError;
|
||||
}
|
||||
}
|
||||
#else // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
resp_payload->status = STATUS__InvalidArgument;
|
||||
#endif // !CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
resp->payload_case = NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_SET_THREAD_CONFIG;
|
||||
resp->resp_set_thread_config = resp_payload;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t cmd_apply_config_handler(NetworkConfigPayload *req,
|
||||
NetworkConfigPayload *resp, void *priv_data)
|
||||
{
|
||||
ESP_LOGD(TAG, "Enter cmd_apply_config_handler");
|
||||
network_prov_config_handlers_t *h = (network_prov_config_handlers_t *) priv_data;
|
||||
if (!h) {
|
||||
ESP_LOGE(TAG, "Command invoked without handlers");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (req->msg == NETWORK_CONFIG_MSG_TYPE__TypeCmdApplyWifiConfig) {
|
||||
RespApplyWifiConfig *resp_payload = (RespApplyWifiConfig *) malloc(sizeof(RespApplyWifiConfig));
|
||||
if (!resp_payload) {
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_apply_wifi_config__init(resp_payload);
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
if (h->wifi_apply_config_handler && h->wifi_apply_config_handler(&h->ctx) == ESP_OK) {
|
||||
resp_payload->status = STATUS__Success;
|
||||
} else {
|
||||
resp_payload->status = STATUS__InternalError;
|
||||
}
|
||||
#else // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
resp_payload->status = STATUS__InvalidArgument;
|
||||
#endif // !CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
resp->payload_case = NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_APPLY_WIFI_CONFIG;
|
||||
resp->resp_apply_wifi_config = resp_payload;
|
||||
} else if (req->msg == NETWORK_CONFIG_MSG_TYPE__TypeCmdApplyThreadConfig) {
|
||||
RespApplyThreadConfig *resp_payload = (RespApplyThreadConfig *) malloc(sizeof(RespApplyThreadConfig));
|
||||
if (!resp_payload) {
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_apply_thread_config__init(resp_payload);
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
if (h->thread_apply_config_handler && h->thread_apply_config_handler(&h->ctx) == ESP_OK) {
|
||||
resp_payload->status = STATUS__Success;
|
||||
} else {
|
||||
resp_payload->status = STATUS__InternalError;
|
||||
}
|
||||
#else // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
resp_payload->status = STATUS__InvalidArgument;
|
||||
#endif // !CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
resp->payload_case = NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_APPLY_THREAD_CONFIG;
|
||||
resp->resp_apply_thread_config = resp_payload;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static int lookup_cmd_handler(int cmd_id)
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(cmd_table) / sizeof(network_prov_config_cmd_t); i++) {
|
||||
if (cmd_table[i].cmd_num == cmd_id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
static void network_prov_config_command_cleanup(NetworkConfigPayload *resp, void *priv_data)
|
||||
{
|
||||
if (!resp) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (resp->msg) {
|
||||
case NETWORK_CONFIG_MSG_TYPE__TypeRespGetWifiStatus: {
|
||||
if (!resp->resp_get_wifi_status) {
|
||||
break;
|
||||
}
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
switch (resp->resp_get_wifi_status->wifi_sta_state) {
|
||||
case WIFI_STATION_STATE__Connecting:
|
||||
break;
|
||||
case WIFI_STATION_STATE__Connected:
|
||||
if (resp->resp_get_wifi_status->wifi_connected) {
|
||||
if (resp->resp_get_wifi_status->wifi_connected->ip4_addr) {
|
||||
free(resp->resp_get_wifi_status->wifi_connected->ip4_addr);
|
||||
}
|
||||
if (resp->resp_get_wifi_status->wifi_connected->bssid.data) {
|
||||
free(resp->resp_get_wifi_status->wifi_connected->bssid.data);
|
||||
}
|
||||
if (resp->resp_get_wifi_status->wifi_connected->ssid.data) {
|
||||
free(resp->resp_get_wifi_status->wifi_connected->ssid.data);
|
||||
}
|
||||
free(resp->resp_get_wifi_status->wifi_connected);
|
||||
}
|
||||
break;
|
||||
case WIFI_STATION_STATE__ConnectionFailed:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
free(resp->resp_get_wifi_status);
|
||||
}
|
||||
break;
|
||||
case NETWORK_CONFIG_MSG_TYPE__TypeRespGetThreadStatus: {
|
||||
if (!resp->resp_get_thread_status) {
|
||||
break;
|
||||
}
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
switch (resp->resp_get_thread_status->thread_state) {
|
||||
case THREAD_NETWORK_STATE__Attaching:
|
||||
break;
|
||||
case THREAD_NETWORK_STATE__Attached:
|
||||
if (resp->resp_get_thread_status->thread_attached) {
|
||||
if (resp->resp_get_thread_status->thread_attached->name) {
|
||||
free(resp->resp_get_thread_status->thread_attached->name);
|
||||
}
|
||||
free(resp->resp_get_thread_status->thread_attached);
|
||||
}
|
||||
break;
|
||||
case THREAD_NETWORK_STATE__AttachingFailed:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
free(resp->resp_get_thread_status);
|
||||
}
|
||||
break;
|
||||
case NETWORK_CONFIG_MSG_TYPE__TypeRespSetWifiConfig: {
|
||||
free(resp->resp_set_wifi_config);
|
||||
}
|
||||
break;
|
||||
case NETWORK_CONFIG_MSG_TYPE__TypeRespSetThreadConfig: {
|
||||
free(resp->resp_set_thread_config);
|
||||
}
|
||||
break;
|
||||
case NETWORK_CONFIG_MSG_TYPE__TypeRespApplyWifiConfig: {
|
||||
free(resp->resp_apply_wifi_config);
|
||||
}
|
||||
break;
|
||||
case NETWORK_CONFIG_MSG_TYPE__TypeRespApplyThreadConfig: {
|
||||
free(resp->resp_apply_thread_config);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unsupported response type in cleanup_handler");
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static esp_err_t network_prov_config_command_dispatcher(NetworkConfigPayload *req,
|
||||
NetworkConfigPayload *resp, void *priv_data)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_LOGD(TAG, "In network_prov_config_command_dispatcher Cmd=%d", req->msg);
|
||||
|
||||
int cmd_index = lookup_cmd_handler(req->msg);
|
||||
if (cmd_index < 0) {
|
||||
ESP_LOGE(TAG, "Invalid command handler lookup");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ret = cmd_table[cmd_index].command_handler(req, resp, priv_data);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error executing command handler");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t network_prov_config_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,
|
||||
uint8_t **outbuf, ssize_t *outlen, void *priv_data)
|
||||
{
|
||||
NetworkConfigPayload *req;
|
||||
NetworkConfigPayload resp;
|
||||
esp_err_t ret;
|
||||
|
||||
req = network_config_payload__unpack(NULL, inlen, inbuf);
|
||||
if (!req) {
|
||||
ESP_LOGE(TAG, "Unable to unpack config data");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
network_config_payload__init(&resp);
|
||||
/* Validate req->msg before arithmetic to avoid signed overflow on attacker-controlled
|
||||
* wire values. For unknown commands the dispatcher returns ESP_FAIL without calling
|
||||
* any handler, so nothing is allocated and resp.msg = 0 is safe for cleanup. */
|
||||
if (lookup_cmd_handler(req->msg) >= 0) {
|
||||
resp.msg = req->msg + 1;
|
||||
}
|
||||
ret = network_prov_config_command_dispatcher(req, &resp, priv_data);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Proto command dispatcher error %d", ret);
|
||||
ret = ESP_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*outlen = network_config_payload__get_packed_size(&resp);
|
||||
if (*outlen <= 0) {
|
||||
ESP_LOGE(TAG, "Invalid encoding for response");
|
||||
ret = ESP_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*outbuf = (uint8_t *) malloc(*outlen);
|
||||
if (!*outbuf) {
|
||||
ESP_LOGE(TAG, "System out of memory");
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto exit;
|
||||
}
|
||||
network_config_payload__pack(&resp, *outbuf);
|
||||
exit:
|
||||
network_config_payload__free_unpacked(req, NULL);
|
||||
network_prov_config_command_cleanup(&resp, priv_data);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <esp_log.h>
|
||||
#include <string.h>
|
||||
#include <esp_err.h>
|
||||
|
||||
#include "network_ctrl.pb-c.h"
|
||||
|
||||
#include "network_ctrl.h"
|
||||
|
||||
static const char *TAG = "proto_network_ctrl";
|
||||
|
||||
typedef struct network_ctrl_cmd {
|
||||
int cmd_id;
|
||||
esp_err_t (*command_handler)(NetworkCtrlPayload *req,
|
||||
NetworkCtrlPayload *resp, void *priv_data);
|
||||
} network_ctrl_cmd_t;
|
||||
|
||||
static esp_err_t cmd_ctrl_reset_handler(NetworkCtrlPayload *req,
|
||||
NetworkCtrlPayload *resp,
|
||||
void *priv_data);
|
||||
|
||||
static esp_err_t cmd_ctrl_reprov_handler(NetworkCtrlPayload *req,
|
||||
NetworkCtrlPayload *resp,
|
||||
void *priv_data);
|
||||
|
||||
static network_ctrl_cmd_t cmd_table[] = {
|
||||
{
|
||||
.cmd_id = NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlWifiReset,
|
||||
.command_handler = cmd_ctrl_reset_handler
|
||||
},
|
||||
{
|
||||
.cmd_id = NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlThreadReset,
|
||||
.command_handler = cmd_ctrl_reset_handler
|
||||
},
|
||||
{
|
||||
.cmd_id = NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlWifiReprov,
|
||||
.command_handler = cmd_ctrl_reprov_handler
|
||||
},
|
||||
{
|
||||
.cmd_id = NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlThreadReprov,
|
||||
.command_handler = cmd_ctrl_reprov_handler
|
||||
},
|
||||
};
|
||||
|
||||
static esp_err_t cmd_ctrl_reset_handler(NetworkCtrlPayload *req,
|
||||
NetworkCtrlPayload *resp, void *priv_data)
|
||||
{
|
||||
network_ctrl_handlers_t *h = (network_ctrl_handlers_t *) priv_data;
|
||||
if (!h) {
|
||||
ESP_LOGE(TAG, "Command invoked without handlers");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (req->msg == NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlWifiReset) {
|
||||
RespCtrlWifiReset *resp_payload = (RespCtrlWifiReset *) malloc(sizeof(RespCtrlWifiReset));
|
||||
if (!resp_payload) {
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_ctrl_wifi_reset__init(resp_payload);
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
if (h->wifi_ctrl_reset) {
|
||||
resp->status = (h->wifi_ctrl_reset() == ESP_OK ? STATUS__Success : STATUS__InternalError);
|
||||
} else {
|
||||
resp->status = STATUS__InternalError;
|
||||
}
|
||||
#else
|
||||
resp->status = STATUS__InvalidArgument;
|
||||
#endif
|
||||
resp->payload_case = NETWORK_CTRL_PAYLOAD__PAYLOAD_RESP_CTRL_WIFI_RESET;
|
||||
resp->resp_ctrl_wifi_reset = resp_payload;
|
||||
} else if (req->msg == NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlThreadReset) {
|
||||
RespCtrlThreadReset *resp_payload = (RespCtrlThreadReset *) malloc(sizeof(RespCtrlThreadReset));
|
||||
if (!resp_payload) {
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_ctrl_thread_reset__init(resp_payload);
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
if (h->thread_ctrl_reset) {
|
||||
resp->status = (h->thread_ctrl_reset() == ESP_OK ? STATUS__Success : STATUS__InternalError);
|
||||
} else {
|
||||
resp->status = STATUS__InternalError;
|
||||
}
|
||||
#else
|
||||
resp->status = STATUS__InvalidArgument;
|
||||
#endif
|
||||
resp->payload_case = NETWORK_CTRL_PAYLOAD__PAYLOAD_RESP_CTRL_THREAD_RESET;
|
||||
resp->resp_ctrl_thread_reset = resp_payload;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t cmd_ctrl_reprov_handler(NetworkCtrlPayload *req,
|
||||
NetworkCtrlPayload *resp, void *priv_data)
|
||||
{
|
||||
network_ctrl_handlers_t *h = (network_ctrl_handlers_t *) priv_data;
|
||||
if (!h) {
|
||||
ESP_LOGE(TAG, "Command invoked without handlers");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (req->msg == NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlWifiReprov) {
|
||||
RespCtrlWifiReprov *resp_payload = (RespCtrlWifiReprov *) malloc(sizeof(RespCtrlWifiReprov));
|
||||
if (!resp_payload) {
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_ctrl_wifi_reprov__init(resp_payload);
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
if (h->wifi_ctrl_reprov) {
|
||||
resp->status = (h->wifi_ctrl_reprov() == ESP_OK ? STATUS__Success : STATUS__InternalError);
|
||||
} else {
|
||||
resp->status = STATUS__InternalError;
|
||||
}
|
||||
#else
|
||||
resp->status = STATUS__InvalidArgument;
|
||||
#endif
|
||||
resp->payload_case = NETWORK_CTRL_PAYLOAD__PAYLOAD_RESP_CTRL_WIFI_REPROV;
|
||||
resp->resp_ctrl_wifi_reprov = resp_payload;
|
||||
} else if (req->msg == NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlThreadReprov) {
|
||||
RespCtrlThreadReprov *resp_payload = (RespCtrlThreadReprov *) malloc(sizeof(RespCtrlThreadReprov));
|
||||
if (!resp_payload) {
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_ctrl_thread_reprov__init(resp_payload);
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
if (h->thread_ctrl_reprov) {
|
||||
resp->status = (h->thread_ctrl_reprov() == ESP_OK ? STATUS__Success : STATUS__InternalError);
|
||||
} else {
|
||||
resp->status = STATUS__InternalError;
|
||||
}
|
||||
#else
|
||||
resp->status = STATUS__InvalidArgument;
|
||||
#endif
|
||||
resp->payload_case = NETWORK_CTRL_PAYLOAD__PAYLOAD_RESP_CTRL_THREAD_REPROV;
|
||||
resp->resp_ctrl_thread_reprov = resp_payload;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static int lookup_cmd_handler(int cmd_id)
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(cmd_table) / sizeof(network_ctrl_cmd_t); i++) {
|
||||
if (cmd_table[i].cmd_id == cmd_id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void network_ctrl_cmd_cleanup(NetworkCtrlPayload *resp, void *priv_data)
|
||||
{
|
||||
switch (resp->msg) {
|
||||
case NETWORK_CTRL_MSG_TYPE__TypeRespCtrlWifiReset: {
|
||||
free(resp->resp_ctrl_wifi_reset);
|
||||
}
|
||||
break;
|
||||
case NETWORK_CTRL_MSG_TYPE__TypeRespCtrlWifiReprov: {
|
||||
free(resp->resp_ctrl_wifi_reprov);
|
||||
}
|
||||
break;
|
||||
case NETWORK_CTRL_MSG_TYPE__TypeRespCtrlThreadReset: {
|
||||
free(resp->resp_ctrl_thread_reset);
|
||||
}
|
||||
break;
|
||||
case NETWORK_CTRL_MSG_TYPE__TypeRespCtrlThreadReprov: {
|
||||
free(resp->resp_ctrl_thread_reprov);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unsupported response type in cleanup_handler");
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static esp_err_t network_ctrl_cmd_dispatcher(NetworkCtrlPayload *req,
|
||||
NetworkCtrlPayload *resp, void *priv_data)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_LOGD(TAG, "In network_ctrl_cmd_dispatcher Cmd=%d", req->msg);
|
||||
|
||||
int cmd_index = lookup_cmd_handler(req->msg);
|
||||
if (cmd_index < 0) {
|
||||
ESP_LOGE(TAG, "Failed to find cmd with ID = %d in the command table", req->msg);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ret = cmd_table[cmd_index].command_handler(req, resp, priv_data);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error executing command handler");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t network_ctrl_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,
|
||||
uint8_t **outbuf, ssize_t *outlen, void *priv_data)
|
||||
{
|
||||
NetworkCtrlPayload *req;
|
||||
NetworkCtrlPayload resp;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
req = network_ctrl_payload__unpack(NULL, inlen, inbuf);
|
||||
if (!req) {
|
||||
ESP_LOGE(TAG, "Unable to unpack ctrl message");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
network_ctrl_payload__init(&resp);
|
||||
ret = network_ctrl_cmd_dispatcher(req, &resp, priv_data);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Command dispatcher error %02X", ret);
|
||||
ret = ESP_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
resp.msg = req->msg + 1; /* Response is request + 1 */
|
||||
*outlen = network_ctrl_payload__get_packed_size(&resp);
|
||||
if (*outlen <= 0) {
|
||||
ESP_LOGE(TAG, "Invalid encoding for response");
|
||||
ret = ESP_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*outbuf = (uint8_t *) malloc(*outlen);
|
||||
if (!*outbuf) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for the output buffer");
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto exit;
|
||||
}
|
||||
network_ctrl_payload__pack(&resp, *outbuf);
|
||||
ESP_LOGD(TAG, "Response packet size : %d", *outlen);
|
||||
exit:
|
||||
|
||||
network_ctrl_payload__free_unpacked(req, NULL);
|
||||
network_ctrl_cmd_cleanup(&resp, priv_data);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _PROV_NETWORK_CTRL_H_
|
||||
#define _PROV_NETWORK_CTRL_H_
|
||||
|
||||
#include <esp_err.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Internal handlers for receiving and responding to protocomm
|
||||
* requests from client
|
||||
*
|
||||
* This is to be passed as priv_data for protocomm request handler
|
||||
* (refer to `network_ctrl_handler()`) when calling `protocomm_add_endpoint()`.
|
||||
*/
|
||||
typedef struct network_ctrl_handlers {
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
/**
|
||||
* Handler functions called when ctrl reset command is received
|
||||
*/
|
||||
esp_err_t (*wifi_ctrl_reset)(void);
|
||||
|
||||
/**
|
||||
* Handler functions called when ctrl reprov command is received
|
||||
*/
|
||||
esp_err_t (*wifi_ctrl_reprov)(void);
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
esp_err_t (*thread_ctrl_reset)(void);
|
||||
esp_err_t (*thread_ctrl_reprov)(void);
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
} network_ctrl_handlers_t;
|
||||
|
||||
/**
|
||||
* @brief Handler for sending on demand network ctrl results
|
||||
*
|
||||
* This is to be registered as the `prov-ctrl` endpoint handler
|
||||
* (protocomm `protocomm_req_handler_t`) using `protocomm_add_endpoint()`
|
||||
*/
|
||||
esp_err_t network_ctrl_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,
|
||||
uint8_t **outbuf, ssize_t *outlen, void *priv_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_security.h>
|
||||
|
||||
#include "network_provisioning/manager.h"
|
||||
#include "network_provisioning/network_config.h"
|
||||
#include "network_provisioning/network_scan.h"
|
||||
#include "network_ctrl.h"
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
#include "openthread/link.h"
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
|
||||
/**
|
||||
* @brief Notify manager that provisioning is done
|
||||
*
|
||||
* Stops the provisioning. This is called by the get_status_handler()
|
||||
* when the status is connected. This has no effect if main application
|
||||
* has disabled auto stop on completion by calling
|
||||
* network_prov_mgr_disable_auto_stop()
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Provisioning will be stopped
|
||||
* - ESP_FAIL : Failed to stop provisioning
|
||||
*/
|
||||
esp_err_t network_prov_mgr_done(void);
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
/**
|
||||
* @brief Start Wi-Fi AP Scan
|
||||
*
|
||||
* @param[in] blocking Set true to return only after scanning is complete
|
||||
* @param[in] passive Set true to perform passive scan instead of default active scan
|
||||
* @param[in] group_channels Number of channels to scan in one go
|
||||
* (set to 0 for scanning all channels in one go)
|
||||
* @param[in] period_ms Scan time (in milli-seconds) on each channel
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Successfully started Wi-Fi scanning
|
||||
* - ESP_FAIL : Provisioning app not running
|
||||
*/
|
||||
esp_err_t network_prov_mgr_wifi_scan_start(bool blocking, bool passive,
|
||||
uint8_t group_channels,
|
||||
uint32_t period_ms);
|
||||
|
||||
/**
|
||||
* @brief Use to query the state of Wi-Fi scan
|
||||
*
|
||||
* @return
|
||||
* - true : Scan finished
|
||||
* - false : Scan running
|
||||
*/
|
||||
bool network_prov_mgr_wifi_scan_finished(void);
|
||||
|
||||
/**
|
||||
* @brief Get the count of results in the scan list
|
||||
*
|
||||
* @return
|
||||
* - count : Number of Wi-Fi Access Points detected while scanning
|
||||
*/
|
||||
uint16_t network_prov_mgr_wifi_scan_result_count(void);
|
||||
|
||||
/**
|
||||
* @brief Get AP record for a particular index in the scan list result
|
||||
*
|
||||
* @param[out] index Index of the result to fetch
|
||||
*
|
||||
* @return
|
||||
* - result : Pointer to Access Point record
|
||||
*/
|
||||
const wifi_ap_record_t *network_prov_mgr_wifi_scan_result(uint16_t index);
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
/**
|
||||
* @brief Start Thread network Scan
|
||||
*
|
||||
* @param[in] blocking Set true to return only after scanning is complete
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Successfully started Thread scanning
|
||||
* - ESP_FAIL : Provisioning app not running
|
||||
*/
|
||||
esp_err_t network_prov_mgr_thread_scan_start(bool blocking, uint32_t channel_mask);
|
||||
|
||||
/**
|
||||
* @brief Use to query the state of Thread scan
|
||||
*
|
||||
* @return
|
||||
* - true : Scan finished
|
||||
* - false : Scan running
|
||||
*/
|
||||
bool network_prov_mgr_thread_scan_finished(void);
|
||||
|
||||
/**
|
||||
* @brief Get the count of results in the scan list
|
||||
*
|
||||
* @return
|
||||
* - count : Number of Thread networks detected while scanning
|
||||
*/
|
||||
uint16_t network_prov_mgr_thread_scan_result_count(void);
|
||||
|
||||
/**
|
||||
* @brief Get Thread network record for a particular index in the scan list result
|
||||
*
|
||||
* @param[out] index Index of the result to fetch
|
||||
*
|
||||
* @return
|
||||
* - result : Pointer to Thread network record
|
||||
*/
|
||||
const otActiveScanResult *network_prov_mgr_thread_scan_result(uint16_t index);
|
||||
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
|
||||
/**
|
||||
* @brief Get protocomm handlers for network_config provisioning endpoint
|
||||
*
|
||||
* @param[out] ptr pointer to structure to be set
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : success
|
||||
* - ESP_ERR_INVALID_ARG : null argument
|
||||
*/
|
||||
esp_err_t get_network_prov_handlers(network_prov_config_handlers_t *ptr);
|
||||
|
||||
/**
|
||||
* @brief Get protocomm handlers for network_scan provisioning endpoint
|
||||
*
|
||||
* @param[out] ptr pointer to structure to be set
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : success
|
||||
* - ESP_ERR_INVALID_ARG : null argument
|
||||
*/
|
||||
esp_err_t get_network_scan_handlers(network_prov_scan_handlers_t *ptr);
|
||||
|
||||
/**
|
||||
* @brief Get protocomm handlers for network_ctrl provisioning endpoint
|
||||
*
|
||||
* @param[in] ptr pointer to structure to be set
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : success
|
||||
* - ESP_ERR_INVALID_ARG : null argument
|
||||
*/
|
||||
esp_err_t get_network_ctrl_handlers(network_ctrl_handlers_t *ptr);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the remaining number of Wi-Fi connection attempts
|
||||
*
|
||||
* This function provides the number of Wi-Fi connection attempts left for
|
||||
* the network provisioning manager before reaching the maximum retry limit.
|
||||
*
|
||||
* @param[out] attempts_remaining Pointer to store the remaining connection attempts
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - ESP_ERR_INVALID_ARG: Null pointer provided for attempts_remaining
|
||||
* - ESP_FAIL: Failed to retrieve the remaining attempts
|
||||
*/
|
||||
esp_err_t network_prov_mgr_get_wifi_remaining_conn_attempts(uint32_t *attempts_remaining);
|
||||
@@ -0,0 +1,675 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <esp_log.h>
|
||||
#include <string.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_wifi.h>
|
||||
|
||||
#include "network_scan.pb-c.h"
|
||||
|
||||
#include <network_provisioning/network_scan.h>
|
||||
|
||||
static const char *TAG = "proto_network_scan";
|
||||
|
||||
typedef struct network_prov_scan_cmd {
|
||||
int cmd_num;
|
||||
esp_err_t (*command_handler)(NetworkScanPayload *req,
|
||||
NetworkScanPayload *resp, void *priv_data);
|
||||
} network_prov_scan_cmd_t;
|
||||
|
||||
static esp_err_t cmd_scan_start_handler(NetworkScanPayload *req,
|
||||
NetworkScanPayload *resp,
|
||||
void *priv_data);
|
||||
|
||||
static esp_err_t cmd_scan_status_handler(NetworkScanPayload *req,
|
||||
NetworkScanPayload *resp,
|
||||
void *priv_data);
|
||||
|
||||
static esp_err_t cmd_scan_result_handler(NetworkScanPayload *req,
|
||||
NetworkScanPayload *resp,
|
||||
void *priv_data);
|
||||
|
||||
static network_prov_scan_cmd_t cmd_table[] = {
|
||||
{
|
||||
.cmd_num = NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiStart,
|
||||
.command_handler = cmd_scan_start_handler
|
||||
},
|
||||
{
|
||||
.cmd_num = NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiStatus,
|
||||
.command_handler = cmd_scan_status_handler
|
||||
},
|
||||
{
|
||||
.cmd_num = NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiResult,
|
||||
.command_handler = cmd_scan_result_handler
|
||||
},
|
||||
{
|
||||
.cmd_num = NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadStart,
|
||||
.command_handler = cmd_scan_start_handler
|
||||
},
|
||||
{
|
||||
.cmd_num = NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadStatus,
|
||||
.command_handler = cmd_scan_status_handler
|
||||
},
|
||||
{
|
||||
.cmd_num = NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadResult,
|
||||
.command_handler = cmd_scan_result_handler
|
||||
}
|
||||
};
|
||||
|
||||
static size_t sanitize_ssid_for_client(const char *src, char *dst, size_t dst_len)
|
||||
{
|
||||
if (!src || !dst || dst_len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t src_len = strnlen(src, 32);
|
||||
size_t out = 0;
|
||||
for (size_t i = 0; i < src_len && out < (dst_len - 1); i++) {
|
||||
unsigned char c = (unsigned char)src[i];
|
||||
/* Keep returned SSID bytes ASCII-safe to avoid client UTF-8 decode failures. */
|
||||
if (c >= 0x20 && c <= 0x7E) {
|
||||
dst[out++] = (char)c;
|
||||
} else {
|
||||
dst[out++] = '?';
|
||||
}
|
||||
}
|
||||
|
||||
dst[out] = '\0';
|
||||
return out;
|
||||
}
|
||||
|
||||
static uint32_t map_auth_for_client(uint8_t authmode)
|
||||
{
|
||||
switch (authmode) {
|
||||
case WIFI_AUTH_OPEN:
|
||||
return WIFI_AUTH_MODE__Open;
|
||||
case WIFI_AUTH_WEP:
|
||||
return WIFI_AUTH_MODE__WEP;
|
||||
case WIFI_AUTH_WPA_PSK:
|
||||
return WIFI_AUTH_MODE__WPA_PSK;
|
||||
case WIFI_AUTH_WPA2_PSK:
|
||||
return WIFI_AUTH_MODE__WPA2_PSK;
|
||||
case WIFI_AUTH_WPA_WPA2_PSK:
|
||||
return WIFI_AUTH_MODE__WPA_WPA2_PSK;
|
||||
case WIFI_AUTH_WPA2_ENTERPRISE:
|
||||
return WIFI_AUTH_MODE__WPA2_ENTERPRISE;
|
||||
#ifdef WIFI_AUTH_WPA3_PSK
|
||||
case WIFI_AUTH_WPA3_PSK:
|
||||
return WIFI_AUTH_MODE__WPA3_PSK;
|
||||
#endif
|
||||
#ifdef WIFI_AUTH_WPA2_WPA3_PSK
|
||||
case WIFI_AUTH_WPA2_WPA3_PSK:
|
||||
return WIFI_AUTH_MODE__WPA2_WPA3_PSK;
|
||||
#endif
|
||||
default:
|
||||
/* Keep a known enum value for older clients when AP auth mode is newer/unknown. */
|
||||
return WIFI_AUTH_MODE__WPA2_PSK;
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t cmd_scan_start_handler(NetworkScanPayload *req,
|
||||
NetworkScanPayload *resp, void *priv_data)
|
||||
{
|
||||
network_prov_scan_handlers_t *h = (network_prov_scan_handlers_t *) priv_data;
|
||||
if (!h) {
|
||||
ESP_LOGE(TAG, "Command invoked without handlers");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (req->msg == NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiStart) {
|
||||
RespScanWifiStart *resp_payload = (RespScanWifiStart *) malloc(sizeof(RespScanWifiStart));
|
||||
if (!resp_payload) {
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_scan_wifi_start__init(resp_payload);
|
||||
|
||||
bool blocking = false;
|
||||
bool passive = false;
|
||||
uint8_t group_channels = 4;
|
||||
uint32_t period_ms = 120;
|
||||
|
||||
if (req->payload_case != NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_WIFI_START || !req->cmd_scan_wifi_start) {
|
||||
ESP_LOGW(TAG, "Invalid WiFi scan start command payload; using safe defaults");
|
||||
} else {
|
||||
blocking = req->cmd_scan_wifi_start->blocking;
|
||||
passive = req->cmd_scan_wifi_start->passive;
|
||||
group_channels = req->cmd_scan_wifi_start->group_channels;
|
||||
period_ms = req->cmd_scan_wifi_start->period_ms;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
if (h->wifi_scan_start) {
|
||||
resp->status = (h->wifi_scan_start(blocking,
|
||||
passive,
|
||||
group_channels,
|
||||
period_ms,
|
||||
&h->ctx) == ESP_OK ? STATUS__Success : STATUS__InternalError);
|
||||
} else {
|
||||
resp->status = STATUS__InternalError;
|
||||
}
|
||||
#else
|
||||
resp->status = STATUS__InvalidArgument;
|
||||
#endif
|
||||
resp->payload_case = NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_WIFI_START;
|
||||
resp->resp_scan_wifi_start = resp_payload;
|
||||
} else if (req->msg == NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadStart) {
|
||||
RespScanThreadStart *resp_payload = (RespScanThreadStart *) malloc(sizeof(RespScanThreadStart));
|
||||
if (!resp_payload) {
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_scan_thread_start__init(resp_payload);
|
||||
|
||||
if (req->payload_case != NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_THREAD_START || !req->cmd_scan_thread_start) {
|
||||
ESP_LOGE(TAG, "Invalid Thread scan start command");
|
||||
resp->resp_scan_thread_start = resp_payload;
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
if (h->thread_scan_start) {
|
||||
resp->status = (h->thread_scan_start(req->cmd_scan_thread_start->blocking,
|
||||
req->cmd_scan_thread_start->channel_mask,
|
||||
&h->ctx) == ESP_OK ? STATUS__Success : STATUS__InternalError);
|
||||
} else {
|
||||
resp->status = STATUS__InternalError;
|
||||
}
|
||||
#else
|
||||
resp->status = STATUS__InvalidArgument;
|
||||
#endif
|
||||
resp->payload_case = NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_THREAD_START;
|
||||
resp->resp_scan_thread_start = resp_payload;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t cmd_scan_status_handler(NetworkScanPayload *req,
|
||||
NetworkScanPayload *resp, void *priv_data)
|
||||
{
|
||||
bool scan_finished = false;
|
||||
uint16_t result_count = 0;
|
||||
|
||||
network_prov_scan_handlers_t *h = (network_prov_scan_handlers_t *) priv_data;
|
||||
if (!h) {
|
||||
ESP_LOGE(TAG, "Command invoked without handlers");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (req->msg == NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiStatus) {
|
||||
RespScanWifiStatus *resp_payload = (RespScanWifiStatus *) malloc(sizeof(RespScanWifiStatus));
|
||||
if (!resp_payload) {
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_scan_wifi_status__init(resp_payload);
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
if (h->wifi_scan_status) {
|
||||
resp->status = (h->wifi_scan_status(&scan_finished, &result_count, &h->ctx) == ESP_OK ?
|
||||
STATUS__Success : STATUS__InternalError);
|
||||
} else {
|
||||
resp->status = STATUS__InternalError;
|
||||
}
|
||||
#else
|
||||
resp->status = STATUS__InvalidArgument;
|
||||
#endif
|
||||
resp_payload->scan_finished = scan_finished;
|
||||
resp_payload->result_count = result_count;
|
||||
resp->payload_case = NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_WIFI_STATUS;
|
||||
resp->resp_scan_wifi_status = resp_payload;
|
||||
} else if (req->msg == NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadStatus) {
|
||||
RespScanThreadStatus *resp_payload = (RespScanThreadStatus *) malloc(sizeof(RespScanThreadStatus));
|
||||
if (!resp_payload) {
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_scan_thread_status__init(resp_payload);
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
if (h->thread_scan_status) {
|
||||
resp->status = (h->thread_scan_status(&scan_finished, &result_count, &h->ctx) == ESP_OK ?
|
||||
STATUS__Success : STATUS__InternalError);
|
||||
} else {
|
||||
resp->status = STATUS__InternalError;
|
||||
}
|
||||
#else
|
||||
resp->status = STATUS__InvalidArgument;
|
||||
#endif
|
||||
resp_payload->scan_finished = scan_finished;
|
||||
resp_payload->result_count = result_count;
|
||||
resp->payload_case = NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_THREAD_STATUS;
|
||||
resp->resp_scan_thread_status = resp_payload;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t cmd_scan_result_handler(NetworkScanPayload *req,
|
||||
NetworkScanPayload *resp, void *priv_data)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
network_prov_scan_handlers_t *h = (network_prov_scan_handlers_t *) priv_data;
|
||||
if (!h) {
|
||||
ESP_LOGE(TAG, "Command invoked without handlers");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (req->msg == NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiResult) {
|
||||
RespScanWifiResult *resp_payload = (RespScanWifiResult *) malloc(sizeof(RespScanWifiResult));
|
||||
if (!resp_payload) {
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_scan_wifi_result__init(resp_payload);
|
||||
|
||||
uint16_t start_index = 0;
|
||||
uint16_t req_wifi_count = 4;
|
||||
|
||||
if (req->payload_case != NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_WIFI_RESULT || !req->cmd_scan_wifi_result) {
|
||||
ESP_LOGW(TAG, "Invalid WiFi scan result command payload; using defaults start=0 count=4");
|
||||
} else {
|
||||
start_index = req->cmd_scan_wifi_result->start_index;
|
||||
req_wifi_count = req->cmd_scan_wifi_result->count;
|
||||
}
|
||||
|
||||
if (start_index >= CONFIG_NETWORK_PROV_SCAN_MAX_ENTRIES) {
|
||||
ESP_LOGE(TAG, "WiFi scan result count/start_index out of bounds");
|
||||
resp->resp_scan_wifi_result = resp_payload;
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
uint16_t max_wifi_count = CONFIG_NETWORK_PROV_SCAN_MAX_ENTRIES - start_index;
|
||||
uint16_t effective_wifi_count = MIN(req_wifi_count, max_wifi_count);
|
||||
ESP_LOGI(TAG, "WiFi scan result requested: start=%u count=%u (effective=%u)",
|
||||
start_index,
|
||||
req_wifi_count,
|
||||
effective_wifi_count);
|
||||
if (req_wifi_count != effective_wifi_count) {
|
||||
ESP_LOGW(TAG, "Clamping WiFi scan result count from %u to %u (start_index=%u)",
|
||||
req_wifi_count, effective_wifi_count, start_index);
|
||||
}
|
||||
|
||||
resp->status = STATUS__Success;
|
||||
resp->payload_case = NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_WIFI_RESULT;
|
||||
resp->resp_scan_wifi_result = resp_payload;
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
network_prov_scan_wifi_result_t scan_result = {{0}, {0}, 0, 0, 0};
|
||||
WiFiScanResult **results = NULL;
|
||||
|
||||
/* Allocate memory only if there are non-zero scan results */
|
||||
if (effective_wifi_count) {
|
||||
results = (WiFiScanResult **) calloc(effective_wifi_count,
|
||||
sizeof(WiFiScanResult *));
|
||||
if (!results) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for results array");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
}
|
||||
resp_payload->entries = results;
|
||||
resp_payload->n_entries = effective_wifi_count;
|
||||
|
||||
/* If req->cmd_scan_wifi_result->count is 0, the below loop will
|
||||
* be skipped.
|
||||
*/
|
||||
for (uint32_t i = 0; i < effective_wifi_count; i++) {
|
||||
if (!h->wifi_scan_result) {
|
||||
resp_payload->n_entries = i;
|
||||
resp->status = STATUS__InternalError;
|
||||
break;
|
||||
}
|
||||
/* start_index and count are validated above to sum to at most
|
||||
* CONFIG_NETWORK_PROV_SCAN_MAX_ENTRIES (max 255), so this cast is safe. */
|
||||
uint16_t result_index = (uint16_t)(i + start_index);
|
||||
err = h->wifi_scan_result(result_index, &scan_result, &h->ctx);
|
||||
if (err != ESP_OK) {
|
||||
resp_payload->n_entries = i;
|
||||
resp->status = STATUS__InternalError;
|
||||
break;
|
||||
}
|
||||
|
||||
results[i] = (WiFiScanResult *) malloc(sizeof(WiFiScanResult));
|
||||
if (!results[i]) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for result entry");
|
||||
resp_payload->n_entries = i;
|
||||
resp->status = STATUS__InternalError;
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
wi_fi_scan_result__init(results[i]);
|
||||
|
||||
char ssid_sanitized[33] = {0};
|
||||
size_t ssid_len = sanitize_ssid_for_client(scan_result.ssid, ssid_sanitized, sizeof(ssid_sanitized));
|
||||
results[i]->ssid.len = ssid_len;
|
||||
results[i]->ssid.data = (uint8_t *) strdup(ssid_sanitized);
|
||||
if (!results[i]->ssid.data) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for scan result entry SSID");
|
||||
results[i]->ssid.len = 0;
|
||||
resp_payload->n_entries = i + 1;
|
||||
resp->status = STATUS__InternalError;
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
results[i]->channel = scan_result.channel;
|
||||
results[i]->rssi = scan_result.rssi;
|
||||
results[i]->auth = map_auth_for_client(scan_result.auth);
|
||||
|
||||
results[i]->bssid.len = sizeof(scan_result.bssid);
|
||||
results[i]->bssid.data = malloc(results[i]->bssid.len);
|
||||
if (!results[i]->bssid.data) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for scan result entry BSSID");
|
||||
results[i]->bssid.len = 0;
|
||||
resp_payload->n_entries = i + 1;
|
||||
resp->status = STATUS__InternalError;
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
memcpy(results[i]->bssid.data, scan_result.bssid, results[i]->bssid.len);
|
||||
|
||||
ESP_LOGI(TAG,
|
||||
"WiFi scan entry[%u]: ssid='%s' ch=%u rssi=%d auth_raw=%u auth_sent=%u",
|
||||
(unsigned int)i,
|
||||
ssid_sanitized,
|
||||
(unsigned int)results[i]->channel,
|
||||
(int)results[i]->rssi,
|
||||
(unsigned int)scan_result.auth,
|
||||
(unsigned int)results[i]->auth);
|
||||
}
|
||||
ESP_LOGI(TAG, "WiFi scan result responded: entries=%u status=%d",
|
||||
(unsigned int)resp_payload->n_entries,
|
||||
(int)resp->status);
|
||||
#else // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
resp->status = STATUS__InvalidArgument;
|
||||
#endif // !CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
} else if (req->msg == NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadResult) {
|
||||
RespScanThreadResult *resp_payload = (RespScanThreadResult *) malloc(sizeof(RespScanThreadResult));
|
||||
if (!resp_payload) {
|
||||
ESP_LOGE(TAG, "Error allocating memory");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
resp_scan_thread_result__init(resp_payload);
|
||||
|
||||
if (req->payload_case != NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_THREAD_RESULT || !req->cmd_scan_thread_result) {
|
||||
ESP_LOGE(TAG, "Invalid Thread scan result command");
|
||||
resp->resp_scan_thread_result = resp_payload;
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (req->cmd_scan_thread_result->start_index >= CONFIG_NETWORK_PROV_SCAN_MAX_ENTRIES) {
|
||||
ESP_LOGE(TAG, "Thread scan result count/start_index out of bounds");
|
||||
resp->resp_scan_thread_result = resp_payload;
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
uint16_t req_thread_count = req->cmd_scan_thread_result->count;
|
||||
uint16_t max_thread_count = CONFIG_NETWORK_PROV_SCAN_MAX_ENTRIES - req->cmd_scan_thread_result->start_index;
|
||||
uint16_t effective_thread_count = MIN(req_thread_count, max_thread_count);
|
||||
if (req_thread_count != effective_thread_count) {
|
||||
ESP_LOGW(TAG, "Clamping Thread scan result count from %u to %u (start_index=%u)",
|
||||
req_thread_count, effective_thread_count, req->cmd_scan_thread_result->start_index);
|
||||
}
|
||||
|
||||
resp->status = STATUS__Success;
|
||||
resp->payload_case = NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_THREAD_RESULT;
|
||||
resp->resp_scan_thread_result = resp_payload;
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
network_prov_scan_thread_result_t scan_result;
|
||||
memset(&scan_result, 0, sizeof(scan_result));
|
||||
ThreadScanResult **results = NULL;
|
||||
|
||||
/* Allocate memory only if there are non-zero scan results */
|
||||
if (effective_thread_count) {
|
||||
results = (ThreadScanResult **) calloc(effective_thread_count,
|
||||
sizeof(ThreadScanResult *));
|
||||
if (!results) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for results array");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
}
|
||||
resp_payload->entries = results;
|
||||
resp_payload->n_entries = effective_thread_count;
|
||||
|
||||
/* If req->cmd_scan_result->count is 0, the below loop will
|
||||
* be skipped.
|
||||
*/
|
||||
for (uint32_t i = 0; i < effective_thread_count; i++) {
|
||||
if (!h->thread_scan_result) {
|
||||
resp_payload->n_entries = i;
|
||||
resp->status = STATUS__InternalError;
|
||||
break;
|
||||
}
|
||||
/* start_index and count are validated above to sum to at most
|
||||
* CONFIG_NETWORK_PROV_SCAN_MAX_ENTRIES (max 255), so this cast is safe. */
|
||||
uint16_t result_index = (uint16_t)(i + req->cmd_scan_thread_result->start_index);
|
||||
err = h->thread_scan_result(result_index, &scan_result, &h->ctx);
|
||||
if (err != ESP_OK) {
|
||||
resp_payload->n_entries = i;
|
||||
resp->status = STATUS__InternalError;
|
||||
break;
|
||||
}
|
||||
|
||||
results[i] = (ThreadScanResult *) malloc(sizeof(ThreadScanResult));
|
||||
if (!results[i]) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for result entry");
|
||||
resp_payload->n_entries = i;
|
||||
resp->status = STATUS__InternalError;
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
thread_scan_result__init(results[i]);
|
||||
results[i]->pan_id = scan_result.pan_id;
|
||||
results[i]->channel = scan_result.channel;
|
||||
results[i]->rssi = scan_result.rssi;
|
||||
results[i]->lqi = scan_result.lqi;
|
||||
|
||||
results[i]->ext_addr.len = sizeof(scan_result.ext_addr);
|
||||
results[i]->ext_addr.data = (uint8_t *)malloc(results[i]->ext_addr.len);
|
||||
if (!results[i]->ext_addr.data) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for scan result entry extended address");
|
||||
results[i]->ext_addr.len = 0;
|
||||
resp_payload->n_entries = i + 1;
|
||||
resp->status = STATUS__InternalError;
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
memcpy(results[i]->ext_addr.data, scan_result.ext_addr, results[i]->ext_addr.len);
|
||||
|
||||
results[i]->ext_pan_id.len = sizeof(scan_result.ext_pan_id);
|
||||
results[i]->ext_pan_id.data = (uint8_t *)malloc(results[i]->ext_pan_id.len);
|
||||
if (!results[i]->ext_pan_id.data) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for scan result entry extended PAN ID");
|
||||
results[i]->ext_pan_id.len = 0;
|
||||
resp_payload->n_entries = i + 1;
|
||||
resp->status = STATUS__InternalError;
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
memcpy(results[i]->ext_pan_id.data, scan_result.ext_pan_id, results[i]->ext_pan_id.len);
|
||||
|
||||
results[i]->network_name = (char *)malloc(sizeof(scan_result.network_name));
|
||||
if (!results[i]->network_name) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for scan result entry network name");
|
||||
resp_payload->n_entries = i + 1;
|
||||
resp->status = STATUS__InternalError;
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
memcpy(results[i]->network_name, scan_result.network_name, sizeof(scan_result.network_name));
|
||||
}
|
||||
#else // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
resp->status = STATUS__InvalidArgument;
|
||||
err = ESP_ERR_INVALID_ARG;
|
||||
#endif // !CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int lookup_cmd_handler(int cmd_id)
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(cmd_table) / sizeof(network_prov_scan_cmd_t); i++) {
|
||||
if (cmd_table[i].cmd_num == cmd_id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void network_prov_scan_cmd_cleanup(NetworkScanPayload *resp, void *priv_data)
|
||||
{
|
||||
switch (resp->msg) {
|
||||
case NETWORK_SCAN_MSG_TYPE__TypeRespScanWifiStart: {
|
||||
free(resp->resp_scan_wifi_start);
|
||||
}
|
||||
break;
|
||||
case NETWORK_SCAN_MSG_TYPE__TypeRespScanThreadStart: {
|
||||
free(resp->resp_scan_thread_start);
|
||||
}
|
||||
break;
|
||||
case NETWORK_SCAN_MSG_TYPE__TypeRespScanWifiStatus: {
|
||||
free(resp->resp_scan_wifi_status);
|
||||
}
|
||||
break;
|
||||
case NETWORK_SCAN_MSG_TYPE__TypeRespScanThreadStatus: {
|
||||
free(resp->resp_scan_thread_status);
|
||||
}
|
||||
break;
|
||||
|
||||
case NETWORK_SCAN_MSG_TYPE__TypeRespScanWifiResult: {
|
||||
if (!resp->resp_scan_wifi_result) {
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
if (resp->resp_scan_wifi_result->entries) {
|
||||
for (uint32_t i = 0; i < resp->resp_scan_wifi_result->n_entries; i++) {
|
||||
if (!resp->resp_scan_wifi_result->entries[i]) {
|
||||
continue;
|
||||
}
|
||||
free(resp->resp_scan_wifi_result->entries[i]->ssid.data);
|
||||
free(resp->resp_scan_wifi_result->entries[i]->bssid.data);
|
||||
free(resp->resp_scan_wifi_result->entries[i]);
|
||||
}
|
||||
free(resp->resp_scan_wifi_result->entries);
|
||||
}
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
free(resp->resp_scan_wifi_result);
|
||||
}
|
||||
break;
|
||||
case NETWORK_SCAN_MSG_TYPE__TypeRespScanThreadResult: {
|
||||
if (!resp->resp_scan_thread_result) {
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
if (resp->resp_scan_thread_result->entries) {
|
||||
for (size_t i = 0; i < resp->resp_scan_thread_result->n_entries; i++) {
|
||||
if (!resp->resp_scan_thread_result->entries[i]) {
|
||||
continue;
|
||||
}
|
||||
free(resp->resp_scan_thread_result->entries[i]->ext_addr.data);
|
||||
free(resp->resp_scan_thread_result->entries[i]->ext_pan_id.data);
|
||||
if (resp->resp_scan_thread_result->entries[i]->network_name != protobuf_c_empty_string) {
|
||||
free(resp->resp_scan_thread_result->entries[i]->network_name);
|
||||
}
|
||||
free(resp->resp_scan_thread_result->entries[i]);
|
||||
}
|
||||
free(resp->resp_scan_thread_result->entries);
|
||||
}
|
||||
#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD
|
||||
free(resp->resp_scan_thread_result);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unsupported response type in cleanup_handler");
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static esp_err_t network_prov_scan_cmd_dispatcher(NetworkScanPayload *req,
|
||||
NetworkScanPayload *resp, void *priv_data)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_LOGD(TAG, "In network_prov_scan_cmd_dispatcher Cmd=%d", req->msg);
|
||||
|
||||
int cmd_index = lookup_cmd_handler(req->msg);
|
||||
if (cmd_index < 0) {
|
||||
ESP_LOGE(TAG, "Invalid command handler lookup");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ret = cmd_table[cmd_index].command_handler(req, resp, priv_data);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error executing command handler");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t network_prov_scan_pack_response(NetworkScanPayload *resp,
|
||||
uint8_t **outbuf, ssize_t *outlen)
|
||||
{
|
||||
if (!resp || !outbuf || !outlen) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*outlen = network_scan_payload__get_packed_size(resp);
|
||||
if (*outlen <= 0) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
*outbuf = (uint8_t *) malloc(*outlen);
|
||||
if (!*outbuf) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
network_scan_payload__pack(resp, *outbuf);
|
||||
ESP_LOGD(TAG, "Response packet size : %d", *outlen);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t network_prov_scan_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,
|
||||
uint8_t **outbuf, ssize_t *outlen, void *priv_data)
|
||||
{
|
||||
NetworkScanPayload *req;
|
||||
NetworkScanPayload resp;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
req = network_scan_payload__unpack(NULL, inlen, inbuf);
|
||||
if (!req) {
|
||||
NetworkScanPayload decode_err_resp;
|
||||
network_scan_payload__init(&decode_err_resp);
|
||||
|
||||
/* Ensure encrypted transport always has a non-empty protobuf payload. */
|
||||
decode_err_resp.msg = NETWORK_SCAN_MSG_TYPE__TypeRespScanWifiStatus;
|
||||
decode_err_resp.status = STATUS__InvalidArgument;
|
||||
|
||||
ESP_LOGW(TAG, "Unable to unpack scan message (len=%d), returning error response", (int)inlen);
|
||||
return network_prov_scan_pack_response(&decode_err_resp, outbuf, outlen);
|
||||
}
|
||||
|
||||
network_scan_payload__init(&resp);
|
||||
/* Validate req->msg before arithmetic to avoid signed overflow on attacker-controlled
|
||||
* wire values. For unknown commands the dispatcher returns ESP_FAIL without calling
|
||||
* any handler, so nothing is allocated and resp.msg = 0 is safe for cleanup. */
|
||||
if (lookup_cmd_handler(req->msg) >= 0) {
|
||||
resp.msg = req->msg + 1;
|
||||
}
|
||||
ret = network_prov_scan_cmd_dispatcher(req, &resp, priv_data);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Command dispatcher error %d", ret);
|
||||
/* Keep session stable: serialize an explicit error response. */
|
||||
resp.status = STATUS__InternalError;
|
||||
if (resp.msg == 0) {
|
||||
resp.msg = NETWORK_SCAN_MSG_TYPE__TypeRespScanWifiStatus;
|
||||
}
|
||||
ret = network_prov_scan_pack_response(&resp, outbuf, outlen);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = network_prov_scan_pack_response(&resp, outbuf, outlen);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Invalid encoding for response");
|
||||
goto exit;
|
||||
}
|
||||
exit:
|
||||
|
||||
network_scan_payload__free_unpacked(req, NULL);
|
||||
network_prov_scan_cmd_cleanup(&resp, priv_data);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
#ifdef CONFIG_BT_CONTROLLER_ENABLED
|
||||
#include "esp_bt.h"
|
||||
#endif
|
||||
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_ble.h>
|
||||
|
||||
#include "network_provisioning/scheme_ble.h"
|
||||
#include "network_provisioning_priv.h"
|
||||
|
||||
static const char *TAG = "network_prov_scheme_ble";
|
||||
|
||||
extern const network_prov_scheme_t network_prov_scheme_ble;
|
||||
|
||||
static uint8_t *custom_service_uuid;
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
|
||||
static uint8_t *custom_ble_addr;
|
||||
static uint8_t custom_keep_ble_on;
|
||||
#endif
|
||||
|
||||
static uint8_t *custom_manufacturer_data;
|
||||
static size_t custom_manufacturer_data_len;
|
||||
|
||||
static esp_err_t prov_start(protocomm_t *pc, void *config)
|
||||
{
|
||||
if (!pc) {
|
||||
ESP_LOGE(TAG, "Protocomm handle cannot be null");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!config) {
|
||||
ESP_LOGE(TAG, "Cannot start with null configuration");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
protocomm_ble_config_t *ble_config = (protocomm_ble_config_t *) config;
|
||||
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
|
||||
ble_config->keep_ble_on = custom_keep_ble_on;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NETWORK_PROV_BLE_BONDING)
|
||||
ble_config->ble_bonding = 1;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NETWORK_PROV_BLE_SEC_CONN) || defined(CONFIG_BT_BLUEDROID_ENABLED)
|
||||
ble_config->ble_sm_sc = 1;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NETWORK_PROV_BLE_FORCE_ENCRYPTION)
|
||||
ble_config->ble_link_encryption = 1;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NETWORK_PROV_BLE_NOTIFY)
|
||||
ble_config->ble_notify = 1;
|
||||
#endif
|
||||
/* Start protocomm as BLE service */
|
||||
if (protocomm_ble_start(pc, ble_config) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to start protocomm BLE service");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
|
||||
esp_err_t network_prov_scheme_ble_set_random_addr(const uint8_t *addr)
|
||||
{
|
||||
if (!addr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
custom_ble_addr = (uint8_t *) malloc(BLE_ADDR_LEN);
|
||||
if (custom_ble_addr == NULL) {
|
||||
ESP_LOGE(TAG, "Error allocating memory for random address");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
memcpy(custom_ble_addr, addr, BLE_ADDR_LEN);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t network_prov_mgr_keep_ble_on(uint8_t is_on_after_ble_stop)
|
||||
{
|
||||
if (!is_on_after_ble_stop) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
custom_keep_ble_on = is_on_after_ble_stop;
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
|
||||
|
||||
|
||||
esp_err_t network_prov_scheme_ble_set_service_uuid(uint8_t *uuid128)
|
||||
{
|
||||
if (!uuid128) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
custom_service_uuid = uuid128;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t network_prov_scheme_ble_set_mfg_data(uint8_t *mfg_data, ssize_t mfg_data_len)
|
||||
{
|
||||
if (!mfg_data || !mfg_data_len) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
custom_manufacturer_data = (uint8_t *) malloc(mfg_data_len);
|
||||
if (custom_manufacturer_data == NULL) {
|
||||
ESP_LOGE(TAG, "Error allocating memory for mfg_data");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
custom_manufacturer_data_len = mfg_data_len;
|
||||
memcpy(custom_manufacturer_data, mfg_data, mfg_data_len);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void *new_config(void)
|
||||
{
|
||||
protocomm_ble_config_t *ble_config = calloc(1, sizeof(protocomm_ble_config_t));
|
||||
if (!ble_config) {
|
||||
ESP_LOGE(TAG, "Error allocating memory for new configuration");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The default provisioning service UUID */
|
||||
const uint8_t service_uuid[16] = {
|
||||
/* LSB <---------------------------------------
|
||||
* ---------------------------------------> MSB */
|
||||
0x07, 0xed, 0x9b, 0x2d, 0x0f, 0x06, 0x7c, 0x87,
|
||||
0x9b, 0x43, 0x43, 0x6b, 0x4d, 0x24, 0x75, 0x17,
|
||||
};
|
||||
|
||||
memcpy(ble_config->service_uuid, service_uuid, sizeof(ble_config->service_uuid));
|
||||
return ble_config;
|
||||
}
|
||||
|
||||
static void delete_config(void *config)
|
||||
{
|
||||
if (!config) {
|
||||
ESP_LOGE(TAG, "Cannot delete null configuration");
|
||||
return;
|
||||
}
|
||||
|
||||
protocomm_ble_config_t *ble_config = (protocomm_ble_config_t *) config;
|
||||
for (unsigned int i = 0; i < ble_config->nu_lookup_count; i++) {
|
||||
free((void *)ble_config->nu_lookup[i].name);
|
||||
}
|
||||
free(ble_config->nu_lookup);
|
||||
free(ble_config);
|
||||
}
|
||||
|
||||
static esp_err_t set_config_service(void *config, const char *service_name, const char *service_key)
|
||||
{
|
||||
if (!config) {
|
||||
ESP_LOGE(TAG, "Cannot set null configuration");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!service_name) {
|
||||
ESP_LOGE(TAG, "Service name cannot be NULL");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
protocomm_ble_config_t *ble_config = (protocomm_ble_config_t *) config;
|
||||
strlcpy(ble_config->device_name, service_name, sizeof(ble_config->device_name));
|
||||
|
||||
/* If a custom service UUID has been provided, override the default one */
|
||||
if (custom_service_uuid) {
|
||||
memcpy(ble_config->service_uuid, custom_service_uuid, sizeof(ble_config->service_uuid));
|
||||
}
|
||||
/* Set manufacturer data if it is provided by app */
|
||||
if (custom_manufacturer_data) {
|
||||
size_t mfg_data_len = custom_manufacturer_data_len;
|
||||
size_t dev_name_len = strnlen(ble_config->device_name, MAX_BLE_DEVNAME_LEN);
|
||||
|
||||
if ((dev_name_len + 2) >= MAX_BLE_MANUFACTURER_DATA_LEN) {
|
||||
/* No space left for manufacturer data */
|
||||
ESP_LOGE(TAG, "No space left for Manufacturer data ");
|
||||
ble_config->manufacturer_data = NULL;
|
||||
ble_config->manufacturer_data_len = 0;
|
||||
} else {
|
||||
if ((mfg_data_len + (dev_name_len ? (dev_name_len + 2) : 0)) > MAX_BLE_MANUFACTURER_DATA_LEN) {
|
||||
ESP_LOGE(TAG, "Manufacturer data length is more than the max allowed size; expect truncated mfg_data ");
|
||||
/* Truncate the mfg_data to fit in the available length */
|
||||
mfg_data_len = MAX_BLE_MANUFACTURER_DATA_LEN - (dev_name_len ? (dev_name_len + 2) : 0);
|
||||
}
|
||||
|
||||
ble_config->manufacturer_data = custom_manufacturer_data;
|
||||
ble_config->manufacturer_data_len = mfg_data_len;
|
||||
}
|
||||
} else {
|
||||
ble_config->manufacturer_data = NULL;
|
||||
ble_config->manufacturer_data_len = 0;
|
||||
}
|
||||
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
|
||||
if (custom_ble_addr) {
|
||||
ble_config->ble_addr = custom_ble_addr;
|
||||
} else {
|
||||
ble_config->ble_addr = NULL;
|
||||
}
|
||||
#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t set_config_endpoint(void *config, const char *endpoint_name, uint16_t uuid)
|
||||
{
|
||||
if (!config) {
|
||||
ESP_LOGE(TAG, "Cannot set null configuration");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!endpoint_name) {
|
||||
ESP_LOGE(TAG, "EP name cannot be null");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
protocomm_ble_config_t *ble_config = (protocomm_ble_config_t *) config;
|
||||
|
||||
char *copy_ep_name = strdup(endpoint_name);
|
||||
if (!copy_ep_name) {
|
||||
ESP_LOGE(TAG, "Error allocating memory for EP name");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
protocomm_ble_name_uuid_t *lookup_table = (
|
||||
realloc(ble_config->nu_lookup, (ble_config->nu_lookup_count + 1) * sizeof(protocomm_ble_name_uuid_t)));
|
||||
if (!lookup_table) {
|
||||
ESP_LOGE(TAG, "Error allocating memory for EP-UUID lookup table");
|
||||
free(copy_ep_name);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
lookup_table[ble_config->nu_lookup_count].name = copy_ep_name;
|
||||
lookup_table[ble_config->nu_lookup_count].uuid = uuid;
|
||||
ble_config->nu_lookup = lookup_table;
|
||||
ble_config->nu_lookup_count += 1;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* Used when both BT and BLE are not needed by application */
|
||||
void network_prov_scheme_ble_event_cb_free_btdm(void *user_data, network_prov_cb_event_t event, void *event_data)
|
||||
{
|
||||
#ifdef CONFIG_BT_CONTROLLER_ENABLED
|
||||
esp_err_t err;
|
||||
switch (event) {
|
||||
case NETWORK_PROV_INIT:
|
||||
/* Release BT memory, as we need only BLE */
|
||||
err = esp_bt_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "bt_mem_release of classic BT failed %d", err);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "BT memory released");
|
||||
}
|
||||
break;
|
||||
|
||||
case NETWORK_PROV_DEINIT:
|
||||
#ifndef CONFIG_NETWORK_PROV_KEEP_BLE_ON_AFTER_PROV
|
||||
/* Release memory used by BLE and Bluedroid host stack */
|
||||
err = esp_bt_mem_release(ESP_BT_MODE_BTDM);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "bt_mem_release of BTDM failed %d", err);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "BTDM memory released");
|
||||
}
|
||||
#endif /* !CONFIG_NETWORK_PROV_KEEP_BLE_ON_AFTER_PROV */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif /* CONFIG_BT_CONTROLLER_ENABLED */
|
||||
}
|
||||
|
||||
/* Used when BT is not needed by application */
|
||||
void network_prov_scheme_ble_event_cb_free_bt(void *user_data, network_prov_cb_event_t event, void *event_data)
|
||||
{
|
||||
#ifdef CONFIG_BT_CONTROLLER_ENABLED
|
||||
esp_err_t err;
|
||||
switch (event) {
|
||||
case NETWORK_PROV_INIT:
|
||||
/* Release BT memory, as we need only BLE */
|
||||
err = esp_bt_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "bt_mem_release of classic BT failed %d", err);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "BT memory released");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif /* CONFIG_BT_CONTROLLER_ENABLED */
|
||||
}
|
||||
|
||||
/* Used when BLE is not needed by application */
|
||||
void network_prov_scheme_ble_event_cb_free_ble(void *user_data, network_prov_cb_event_t event, void *event_data)
|
||||
{
|
||||
#ifdef CONFIG_BT_CONTROLLER_ENABLED
|
||||
esp_err_t err;
|
||||
switch (event) {
|
||||
case NETWORK_PROV_DEINIT:
|
||||
#ifndef CONFIG_NETWORK_PROV_KEEP_BLE_ON_AFTER_PROV
|
||||
/* Release memory used by BLE stack */
|
||||
err = esp_bt_mem_release(ESP_BT_MODE_BLE);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "bt_mem_release of BLE failed %d", err);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "BLE memory released");
|
||||
}
|
||||
#endif /* !CONFIG_NETWORK_PROV_KEEP_BLE_ON_AFTER_PROV */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif /* CONFIG_BT_CONTROLLER_ENABLED */
|
||||
}
|
||||
|
||||
const network_prov_scheme_t network_prov_scheme_ble = {
|
||||
.prov_start = prov_start,
|
||||
.prov_stop = protocomm_ble_stop,
|
||||
.new_config = new_config,
|
||||
.delete_config = delete_config,
|
||||
.set_config_service = set_config_service,
|
||||
.set_config_endpoint = set_config_endpoint,
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
.wifi_mode = WIFI_MODE_STA
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_wifi.h>
|
||||
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_console.h>
|
||||
|
||||
#include "network_provisioning/scheme_console.h"
|
||||
#include "network_provisioning_priv.h"
|
||||
|
||||
static const char *TAG = "network_prov_scheme_console";
|
||||
|
||||
extern const network_prov_scheme_t network_prov_scheme_console;
|
||||
|
||||
static esp_err_t prov_start(protocomm_t *pc, void *config)
|
||||
{
|
||||
if (!pc) {
|
||||
ESP_LOGE(TAG, "Protocomm handle cannot be null");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!config) {
|
||||
ESP_LOGE(TAG, "Cannot start with null configuration");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
protocomm_console_config_t *console_config = (protocomm_console_config_t *) config;
|
||||
|
||||
/* Start protocomm console */
|
||||
esp_err_t err = protocomm_console_start(pc, console_config);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to start protocomm HTTP server");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void *new_config(void)
|
||||
{
|
||||
protocomm_console_config_t *console_config = malloc(sizeof(protocomm_console_config_t));
|
||||
if (!console_config) {
|
||||
ESP_LOGE(TAG, "Error allocating memory for new configuration");
|
||||
return NULL;
|
||||
}
|
||||
protocomm_console_config_t default_config = PROTOCOMM_CONSOLE_DEFAULT_CONFIG();
|
||||
memcpy(console_config, &default_config, sizeof(default_config));
|
||||
return console_config;
|
||||
}
|
||||
|
||||
static void delete_config(void *config)
|
||||
{
|
||||
if (!config) {
|
||||
ESP_LOGE(TAG, "Cannot delete null configuration");
|
||||
return;
|
||||
}
|
||||
free(config);
|
||||
}
|
||||
|
||||
static esp_err_t set_config_service(void *config, const char *service_name, const char *service_key)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t set_config_endpoint(void *config, const char *endpoint_name, uint16_t uuid)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
const network_prov_scheme_t network_prov_scheme_console = {
|
||||
.prov_start = prov_start,
|
||||
.prov_stop = protocomm_console_stop,
|
||||
.new_config = new_config,
|
||||
.delete_config = delete_config,
|
||||
.set_config_service = set_config_service,
|
||||
.set_config_endpoint = set_config_endpoint,
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
.wifi_mode = WIFI_MODE_STA
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_wifi.h>
|
||||
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_httpd.h>
|
||||
|
||||
#include "network_provisioning/scheme_softap.h"
|
||||
#include "network_provisioning_priv.h"
|
||||
|
||||
typedef struct softap_config {
|
||||
protocomm_httpd_config_t httpd_config;
|
||||
char ssid[33];
|
||||
char password[65];
|
||||
} network_prov_softap_config_t;
|
||||
|
||||
static const char *TAG = "network_prov_scheme_softap";
|
||||
|
||||
extern const network_prov_scheme_t network_prov_scheme_softap;
|
||||
static void *scheme_softap_prov_httpd_handle;
|
||||
static esp_err_t start_wifi_ap(const char *ssid, const char *pass)
|
||||
{
|
||||
/* Build Wi-Fi configuration for AP mode */
|
||||
wifi_config_t wifi_config = {
|
||||
.ap = {
|
||||
.max_connection = 5,
|
||||
},
|
||||
};
|
||||
|
||||
/* SSID can be a non NULL terminated string if `ap.ssid_len` is specified
|
||||
* Hence, memcpy is used to support 32 bytes long SSID per 802.11 standard */
|
||||
const size_t ssid_len = strnlen(ssid, sizeof(wifi_config.ap.ssid));
|
||||
memcpy(wifi_config.ap.ssid, ssid, ssid_len);
|
||||
wifi_config.ap.ssid_len = ssid_len;
|
||||
|
||||
if (strlen(pass) == 0) {
|
||||
memset(wifi_config.ap.password, 0, sizeof(wifi_config.ap.password));
|
||||
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
|
||||
} else {
|
||||
strlcpy((char *) wifi_config.ap.password, pass, sizeof(wifi_config.ap.password));
|
||||
wifi_config.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK;
|
||||
}
|
||||
|
||||
/* Run Wi-Fi in AP + STA mode with configuration built above */
|
||||
esp_err_t err = esp_wifi_set_mode(WIFI_MODE_APSTA);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set Wi-Fi mode : %d", err);
|
||||
return err;
|
||||
}
|
||||
err = esp_wifi_set_config(WIFI_IF_AP, &wifi_config);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set Wi-Fi config : %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t prov_start(protocomm_t *pc, void *config)
|
||||
{
|
||||
if (!pc) {
|
||||
ESP_LOGE(TAG, "Protocomm handle cannot be null");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!config) {
|
||||
ESP_LOGE(TAG, "Cannot start with null configuration");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
network_prov_softap_config_t *softap_config = (network_prov_softap_config_t *) config;
|
||||
|
||||
protocomm_httpd_config_t *httpd_config = &softap_config->httpd_config;
|
||||
|
||||
if (scheme_softap_prov_httpd_handle) {
|
||||
httpd_config->ext_handle_provided = true;
|
||||
httpd_config->data.handle = scheme_softap_prov_httpd_handle;
|
||||
}
|
||||
|
||||
/* Start protocomm server on top of HTTP */
|
||||
esp_err_t err = protocomm_httpd_start(pc, httpd_config);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to start protocomm HTTP server");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Start Wi-Fi softAP with specified ssid and password */
|
||||
err = start_wifi_ap(softap_config->ssid, softap_config->password);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to start Wi-Fi AP");
|
||||
protocomm_httpd_stop(pc);
|
||||
return err;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t prov_stop(protocomm_t *pc)
|
||||
{
|
||||
esp_err_t err = protocomm_httpd_stop(pc);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Error occurred while stopping protocomm_httpd");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void *new_config(void)
|
||||
{
|
||||
network_prov_softap_config_t *softap_config = calloc(1, sizeof(network_prov_softap_config_t));
|
||||
if (!softap_config) {
|
||||
ESP_LOGE(TAG, "Error allocating memory for new configuration");
|
||||
return NULL;
|
||||
}
|
||||
protocomm_httpd_config_t default_config = {
|
||||
.data = {
|
||||
.config = PROTOCOMM_HTTPD_DEFAULT_CONFIG()
|
||||
}
|
||||
};
|
||||
softap_config->httpd_config = default_config;
|
||||
return softap_config;
|
||||
}
|
||||
|
||||
static void delete_config(void *config)
|
||||
{
|
||||
if (!config) {
|
||||
ESP_LOGE(TAG, "Cannot delete null configuration");
|
||||
return;
|
||||
}
|
||||
|
||||
network_prov_softap_config_t *softap_config = (network_prov_softap_config_t *) config;
|
||||
free(softap_config);
|
||||
}
|
||||
|
||||
static esp_err_t set_config_service(void *config, const char *service_name, const char *service_key)
|
||||
{
|
||||
if (!config) {
|
||||
ESP_LOGE(TAG, "Cannot set null configuration");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!service_name) {
|
||||
ESP_LOGE(TAG, "Service name cannot be NULL");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
network_prov_softap_config_t *softap_config = (network_prov_softap_config_t *) config;
|
||||
if (service_key) {
|
||||
const int service_key_len = strlen(service_key);
|
||||
if (service_key_len < 8 || service_key_len >= sizeof(softap_config->password)) {
|
||||
ESP_LOGE(TAG, "Incorrect passphrase length for softAP: %d (Expected: Min - 8, Max - 64)", service_key_len);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
strlcpy(softap_config->password, service_key, sizeof(softap_config->password));
|
||||
}
|
||||
strlcpy(softap_config->ssid, service_name, sizeof(softap_config->ssid));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t set_config_endpoint(void *config, const char *endpoint_name, uint16_t uuid)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void network_prov_scheme_softap_set_httpd_handle(void *handle)
|
||||
{
|
||||
scheme_softap_prov_httpd_handle = handle;
|
||||
}
|
||||
|
||||
const network_prov_scheme_t network_prov_scheme_softap = {
|
||||
.prov_start = prov_start,
|
||||
.prov_stop = prov_stop,
|
||||
.new_config = new_config,
|
||||
.delete_config = delete_config,
|
||||
.set_config_service = set_config_service,
|
||||
.set_config_endpoint = set_config_endpoint,
|
||||
#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI
|
||||
.wifi_mode = WIFI_MODE_APSTA
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,132 @@
|
||||
# ESP Provisioning Tool
|
||||
|
||||
## Description
|
||||
|
||||
`esp_prov` - A python-based utility for testing the provisioning examples over a host machine.
|
||||
|
||||
Usage of `esp-prov` assumes that the provisioning app has specific protocomm endpoints active. These endpoints are active in the provisioning examples and accept specific protobuf data structure:
|
||||
|
||||
| Endpoint Name | URI (HTTP server on ip:port) | Description |
|
||||
|---------------|------------------------------|------------------------------------------------------------------------------------------|
|
||||
| prov-session | http://ip:port/prov-session | Security endpoint used for session establishment |
|
||||
| prov-config | http://ip:port/prov-config | Endpoint used for configuring Wi-Fi credentials or Thread dataset on device |
|
||||
| proto-ver | http://ip:port/proto-ver | Version endpoint for checking protocol compatibility |
|
||||
| prov-scan | http://ip:port/prov-scan | Endpoint used for scanning Wi-Fi APs or Thread network |
|
||||
| prov-ctrl | http://ip:port/prov-ctrl | Endpoint used for controlling Wi-Fi / Thread provisioning state |
|
||||
| custom-data | http://ip:port/custom-data | Optional endpoint for sending custom data (refer `wifi_prov` or `thread_prov` example) |
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
python esp_prov.py --transport < mode of provisioning : softap \ ble \ console > [ Optional parameters... ]
|
||||
```
|
||||
### Parameters
|
||||
|
||||
* `--help`
|
||||
Print the list of options along with brief descriptions
|
||||
|
||||
* `--verbose`, `-v`
|
||||
Sets the verbosity level of output log
|
||||
|
||||
* `--transport <mode>`
|
||||
- Three options are available:
|
||||
* `softap` - for SoftAP + HTTPD based provisioning
|
||||
* Requires the device to be running in Wi-Fi SoftAP mode and hosting an HTTP server supporting specific endpoint URIs
|
||||
* The client needs to be connected to the device softAP network before running the `esp_prov` tool.
|
||||
* `ble` - for Bluetooth LE based provisioning
|
||||
* Supports Linux, Windows and macOS; redirected to console if dependencies are not met
|
||||
* Assumes that the provisioning endpoints are active on the device with specific Bluetooth LE service UUIDs
|
||||
* `console` - for debugging via console-based provisioning
|
||||
* The client->device commands are printed to STDOUT and device->client messages are accepted via STDIN.
|
||||
* This is to be used when the device is accepting provisioning commands on UART console.
|
||||
* `httpd` - the script works the same as for `softap`. This could be used on any other network interface than WiFi soft AP, e.g. Ethernet or USB.
|
||||
|
||||
* `--service_name <name>` (Optional)
|
||||
- When transport mode is `ble`, this specifies the Bluetooth LE device name to which connection is to be established for provisioned. If not provided, Bluetooth LE scanning is initiated and a list of nearby devices, as seen by the host, is displayed, of which the target device can be chosen.
|
||||
- When transport mode is `softap` or `httpd`, this specifies the HTTP server hostname / IP which is running the provisioning service, on the SoftAP network (or any other interface for `httpd` mode) of the device which is to be provisioned. This defaults to `192.168.4.1:80` if not specified
|
||||
|
||||
* `--ssid <AP SSID>` (Optional)
|
||||
- For specifying the SSID of the Wi-Fi AP to which the device is to connect after provisioning.
|
||||
- If not provided, scanning is initiated and scan results, as seen by the device, are displayed, of which an SSID can be picked and the corresponding password specified.
|
||||
|
||||
* `--passphrase <AP Password>` (Optional)
|
||||
- For specifying the password of the Wi-Fi AP to which the device is to connect after provisioning.
|
||||
- Only used when corresponding SSID is provided using the `--ssid` option
|
||||
|
||||
* `--dataset_tlvs <Thread Dataset Tlvs>` (Optional)
|
||||
- For specifying the Dataset Tlvs of the Thread network to which the device is to connect after provisioning.
|
||||
|
||||
* `--sec_ver <Security version number>`
|
||||
- For specifying the version of protocomm endpoint security to use. Following 3 versions are supported:
|
||||
* `0` for `protocomm_security0` - No security
|
||||
* `1` for `protocomm_security1` - X25519 key exchange + Authentication using Proof of Possession (PoP) + AES-CTR encryption
|
||||
* `2` for `protocomm_security2` - Secure Remote Password protocol (SRP6a) + AES-GCM encryption
|
||||
|
||||
* `--pop <Proof of possession string>` (Optional)
|
||||
- For specifying optional Proof of Possession string to use for protocomm endpoint security version 1
|
||||
- Ignored when other security versions are used
|
||||
|
||||
* `--sec2_username <SRP6a Username>` (Optional)
|
||||
- For specifying optional username to use for protocomm endpoint security version 2
|
||||
- Ignored when other security versions are used
|
||||
|
||||
* `--sec2_pwd <SRP6a Password>` (Optional)
|
||||
- For specifying optional password to use for protocomm endpoint security version 2
|
||||
- Ignored when other security versions are used
|
||||
|
||||
* `--sec2_gen_cred` (Optional)
|
||||
- For generating the `SRP6a` credentials (salt and verifier) from the provided username and password for protocomm endpoint security version 2
|
||||
- Ignored when other security versions are used
|
||||
|
||||
* `--sec2_salt_len <SRP6a Salt Length>` (Optional)
|
||||
- For specifying the optional `SRP6a` salt length to be used for generating protocomm endpoint security version 2 credentials
|
||||
- Ignored when other security versions are used and the `--sec2_gen_cred` option is not set
|
||||
|
||||
* `--reset` (Optional)
|
||||
- Resets internal state machine of the device and clears provisioned credentials; to be used only in case of provisioning failures
|
||||
|
||||
* `--reprov` (Optional)
|
||||
- Resets internal state machine of the device and clears provisioned credentials; to be used only in case the device is to be provisioned again for new credentials after a previous successful provisioning
|
||||
|
||||
* `--ble_adapter <HCI adapter>` (Optional)
|
||||
- For specifying the HCI adapter to use for Bluetooth LE transport (default: `hci0`).
|
||||
- Useful when working with `vhci_bridge` for emulated devices, e.g. `--ble_adapter hci1`.
|
||||
- Only relevant when transport mode is `ble`
|
||||
|
||||
* `--custom_data <some string>` (Optional)
|
||||
An information string can be sent to the `custom-data` endpoint during provisioning using this argument.
|
||||
(Assumes the provisioning app has an endpoint called `custom-data` - see [wifi_prov](../../examples/wifi_prov/) example for implementation details).
|
||||
|
||||
|
||||
### Example Usage
|
||||
|
||||
Please refer to the `README.md` file with the `wifi_prov` or `thread_prov` example present under `{path-to-network_provisioning-component}/examples`.
|
||||
|
||||
This example uses specific options of the `esp_prov` tool and gives an overview of simple as well as advanced usage scenarios.
|
||||
|
||||
## Dependencies
|
||||
|
||||
This requires the following python libraries to run:
|
||||
* `bleak`
|
||||
* `protobuf`
|
||||
* `cryptography`
|
||||
|
||||
To install the dependency packages needed, please run the following command in `$IDF_PATH` directory:
|
||||
|
||||
For ESP-IDF v5.1:
|
||||
```shell
|
||||
bash install.sh --enable-ttfw
|
||||
```
|
||||
|
||||
For ESP-IDF v5.2 to v5.5:
|
||||
```shell
|
||||
bash install.sh --enable-pytest
|
||||
```
|
||||
|
||||
For ESP-IDF v6.0 or later:
|
||||
```shell
|
||||
bash install.sh --enable-ci
|
||||
```
|
||||
|
||||
**Note:** For troubleshooting errors with Bluetooth LE transport, please refer this [link](https://bleak.readthedocs.io/en/latest/troubleshooting.html).
|
||||
@@ -0,0 +1,5 @@
|
||||
# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
from .esp_prov import * # noqa: export esp_prov module to users
|
||||
@@ -0,0 +1,763 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import textwrap
|
||||
import time
|
||||
from getpass import getpass
|
||||
|
||||
from utils import int_to_hex_str
|
||||
|
||||
try:
|
||||
import prov
|
||||
import security
|
||||
import transport
|
||||
|
||||
except ImportError:
|
||||
idf_path = os.environ['IDF_PATH']
|
||||
sys.path.insert(0, idf_path + '/components/protocomm/python')
|
||||
sys.path.insert(1, idf_path + '/tools/esp_prov')
|
||||
|
||||
import prov
|
||||
import security
|
||||
import transport
|
||||
|
||||
# Set this to true to allow exceptions to be thrown
|
||||
config_throw_except = False
|
||||
|
||||
|
||||
def on_except(err):
|
||||
if config_throw_except:
|
||||
raise RuntimeError(err)
|
||||
else:
|
||||
print(err)
|
||||
|
||||
|
||||
def get_security(secver, sec_patch_ver, username, password, pop='', verbose=False):
|
||||
if secver == 2:
|
||||
return security.Security2(sec_patch_ver, username, password, verbose)
|
||||
elif secver == 1:
|
||||
return security.Security1(pop, verbose)
|
||||
elif secver == 0:
|
||||
return security.Security0(verbose)
|
||||
return None
|
||||
|
||||
|
||||
def get_thread_dataset_tlvs(network_info, network_key):
|
||||
# Get the simple dataset tlvs from the PAN ID, Channel, Extended PAN ID, and Network Key
|
||||
pan_id = network_info['pan_id']
|
||||
channel = network_info['channel']
|
||||
ext_pan_id = network_info['ext_pan_id']
|
||||
dataset_tlvs = '00030000' + int_to_hex_str(channel) + '0208' + ext_pan_id + '0510' + network_key + '0102' + int_to_hex_str(pan_id)
|
||||
return dataset_tlvs
|
||||
|
||||
|
||||
async def get_transport(sel_transport, service_name, ble_adapter=transport.DEFAULT_BLE_ADAPTER):
|
||||
try:
|
||||
tp = None
|
||||
if (sel_transport in ['softap', 'httpd']):
|
||||
if service_name is None:
|
||||
service_name = '192.168.4.1:80'
|
||||
tp = transport.Transport_HTTP(service_name)
|
||||
elif (sel_transport == 'ble'):
|
||||
# BLE client is now capable of automatically figuring out
|
||||
# the primary service from the advertisement data and the
|
||||
# characteristics corresponding to each endpoint.
|
||||
# Below, the service_uuid field and 16bit UUIDs in the nu_lookup
|
||||
# table are provided only to support devices running older firmware,
|
||||
# in which case, the automated discovery will fail and the client
|
||||
# will fallback to using the provided UUIDs instead
|
||||
nu_lookup = {'prov-session': 'ff51', 'prov-config': 'ff52', 'proto-ver': 'ff53'}
|
||||
tp = transport.Transport_BLE(service_uuid='021a9004-0382-4aea-bff4-6b3f1c5adfb4',
|
||||
nu_lookup=nu_lookup, ble_adapter=ble_adapter)
|
||||
await tp.connect(devname=service_name)
|
||||
elif (sel_transport == 'console'):
|
||||
tp = transport.Transport_Console()
|
||||
return tp
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
return None
|
||||
|
||||
|
||||
async def version_match(tp, protover, verbose=False):
|
||||
try:
|
||||
response = await tp.send_data('proto-ver', protover)
|
||||
|
||||
if verbose:
|
||||
print('proto-ver response : ', response)
|
||||
|
||||
# First assume this to be a simple version string
|
||||
if response.lower() == protover.lower():
|
||||
return True
|
||||
|
||||
try:
|
||||
# Else interpret this as JSON structure containing
|
||||
# information with versions and capabilities of both
|
||||
# provisioning service and application
|
||||
info = json.loads(response)
|
||||
if info['prov']['ver'].lower() == protover.lower():
|
||||
return True
|
||||
|
||||
except ValueError:
|
||||
# If decoding as JSON fails, it means that capabilities
|
||||
# are not supported
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
on_except(e)
|
||||
return None
|
||||
|
||||
|
||||
async def has_capability(tp, capability='none', verbose=False):
|
||||
# Note : default value of `capability` argument cannot be empty string
|
||||
# because protocomm_httpd expects non zero content lengths
|
||||
try:
|
||||
response = await tp.send_data('proto-ver', capability)
|
||||
|
||||
if verbose:
|
||||
print('proto-ver response : ', response)
|
||||
|
||||
try:
|
||||
# Interpret this as JSON structure containing
|
||||
# information with versions and capabilities of both
|
||||
# provisioning service and application
|
||||
info = json.loads(response)
|
||||
supported_capabilities = info['prov']['cap']
|
||||
if capability.lower() == 'none':
|
||||
# No specific capability to check, but capabilities
|
||||
# feature is present so return True
|
||||
return True
|
||||
elif capability in supported_capabilities:
|
||||
return True
|
||||
return False
|
||||
|
||||
except ValueError:
|
||||
# If decoding as JSON fails, it means that capabilities
|
||||
# are not supported
|
||||
return False
|
||||
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
async def get_version(tp):
|
||||
response = None
|
||||
try:
|
||||
response = await tp.send_data('proto-ver', '---')
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
response = ''
|
||||
return response
|
||||
|
||||
|
||||
async def get_sec_patch_ver(tp, verbose=False):
|
||||
response = await get_version(tp)
|
||||
|
||||
if verbose:
|
||||
print('proto-ver response : ', response)
|
||||
|
||||
try:
|
||||
# Interpret this as JSON structure containing
|
||||
# information with security version information
|
||||
info = json.loads(response)
|
||||
try:
|
||||
sec_patch_ver = info['prov']['sec_patch_ver']
|
||||
except KeyError:
|
||||
sec_patch_ver = 0
|
||||
return sec_patch_ver
|
||||
|
||||
except ValueError:
|
||||
# If decoding as JSON fails, we assume default patch level
|
||||
return 0
|
||||
|
||||
|
||||
async def establish_session(tp, sec):
|
||||
try:
|
||||
response = None
|
||||
while True:
|
||||
request = sec.security_session(response)
|
||||
if request is None:
|
||||
break
|
||||
response = await tp.send_data('prov-session', request)
|
||||
if (response is None):
|
||||
return False
|
||||
return True
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
return None
|
||||
|
||||
|
||||
async def custom_config(tp, sec, custom_info, custom_ver):
|
||||
try:
|
||||
message = prov.custom_config_request(sec, custom_info, custom_ver)
|
||||
response = await tp.send_data('custom-config', message)
|
||||
return (prov.custom_config_response(sec, response) == 0)
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
return None
|
||||
|
||||
|
||||
async def custom_data(tp, sec, custom_data):
|
||||
try:
|
||||
message = prov.custom_data_request(sec, custom_data)
|
||||
response = await tp.send_data('custom-data', message)
|
||||
return (prov.custom_data_response(sec, response) == 0)
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
return None
|
||||
|
||||
|
||||
async def scan_wifi_APs(sel_transport, tp, sec):
|
||||
APs = []
|
||||
group_channels = 0
|
||||
readlen = 100
|
||||
if sel_transport in ['softap', 'httpd']:
|
||||
# In case of softAP/httpd we must perform the scan on individual channels, one by one,
|
||||
# so that the Wi-Fi controller gets ample time to send out beacons (necessary to
|
||||
# maintain connectivity with authenticated stations. As scanning one channel at a
|
||||
# time will be slow, we can group more than one channels to be scanned in quick
|
||||
# succession, hence speeding up the scan process. Though if too many channels are
|
||||
# present in a group, the controller may again miss out on sending beacons. Hence,
|
||||
# the application must should use an optimum value. The following value usually
|
||||
# works out in most cases
|
||||
group_channels = 5
|
||||
elif sel_transport == 'ble':
|
||||
# Read at most 4 entries at a time. This is because if we are using BLE transport
|
||||
# then the response packet size should not exceed the present limit of 256 bytes of
|
||||
# characteristic value imposed by protocomm_ble. This limit may be removed in the
|
||||
# future
|
||||
readlen = 4
|
||||
try:
|
||||
message = prov.scan_start_request('wifi', sec, blocking=True, group_channels=group_channels)
|
||||
start_time = time.time()
|
||||
response = await tp.send_data('prov-scan', message)
|
||||
stop_time = time.time()
|
||||
print('++++ Scan process executed in ' + str(stop_time - start_time) + ' sec')
|
||||
prov.scan_start_response(sec, response)
|
||||
|
||||
message = prov.scan_status_request('wifi', sec)
|
||||
response = await tp.send_data('prov-scan', message)
|
||||
result = prov.scan_status_response(sec, response)
|
||||
print('++++ Scan results : ' + str(result['count']))
|
||||
if result['count'] != 0:
|
||||
index = 0
|
||||
remaining = result['count']
|
||||
while remaining:
|
||||
count = [remaining, readlen][remaining > readlen]
|
||||
message = prov.scan_result_request('wifi', sec, index, count)
|
||||
response = await tp.send_data('prov-scan', message)
|
||||
APs += prov.scan_result_response(sec, response)
|
||||
remaining -= count
|
||||
index += count
|
||||
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
return None
|
||||
|
||||
return APs
|
||||
|
||||
|
||||
async def send_wifi_config(tp, sec, ssid, passphrase):
|
||||
try:
|
||||
message = prov.config_set_config_request('wifi', sec, ssid, passphrase)
|
||||
response = await tp.send_data('prov-config', message)
|
||||
return (prov.config_set_config_response(sec, response) == 0)
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
return None
|
||||
|
||||
|
||||
async def apply_wifi_config(tp, sec):
|
||||
try:
|
||||
message = prov.config_apply_config_request('wifi', sec)
|
||||
response = await tp.send_data('prov-config', message)
|
||||
return (prov.config_apply_config_response(sec, response) == 0)
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
return None
|
||||
|
||||
|
||||
async def get_wifi_config(tp, sec):
|
||||
try:
|
||||
message = prov.config_get_status_request('wifi', sec)
|
||||
response = await tp.send_data('prov-config', message)
|
||||
return prov.config_get_status_response(sec, response)
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
return None
|
||||
|
||||
|
||||
async def wait_wifi_connected(tp, sec):
|
||||
"""
|
||||
Wait for provisioning to report Wi-Fi is connected
|
||||
|
||||
Returns True if Wi-Fi connection succeeded, False if connection consistently failed
|
||||
"""
|
||||
TIME_PER_POLL = 5
|
||||
retry = 3
|
||||
|
||||
while True:
|
||||
time.sleep(TIME_PER_POLL)
|
||||
print('\n==== Wi-Fi connection state ====')
|
||||
ret = await get_wifi_config(tp, sec)
|
||||
if ret == 'connecting':
|
||||
continue
|
||||
elif ret == 'connected':
|
||||
print('==== Provisioning was successful ====')
|
||||
return True
|
||||
elif retry > 0:
|
||||
retry -= 1
|
||||
print('Waiting to poll status again (status %s, %d tries left)...' % (ret, retry))
|
||||
else:
|
||||
print('---- Provisioning failed! ----')
|
||||
return False
|
||||
|
||||
|
||||
async def reset_wifi(tp, sec):
|
||||
try:
|
||||
message = prov.ctrl_reset_request('wifi', sec)
|
||||
response = await tp.send_data('prov-ctrl', message)
|
||||
prov.ctrl_reset_response(sec, response)
|
||||
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
return None
|
||||
|
||||
|
||||
async def reprov_wifi(tp, sec):
|
||||
try:
|
||||
message = prov.ctrl_reprov_request('wifi', sec)
|
||||
response = await tp.send_data('prov-ctrl', message)
|
||||
prov.ctrl_reprov_response(sec, response)
|
||||
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
return None
|
||||
|
||||
|
||||
async def scan_thread_networks(sel_transport, tp, sec):
|
||||
Networks = []
|
||||
# Read at most 4 entries at a time. This is because if we are using BLE transport
|
||||
# then the response packet size should not exceed the present limit of 256 bytes of
|
||||
# characteristic value imposed by protocomm_ble. This limit may be removed in the
|
||||
# future
|
||||
readlen = 4
|
||||
try:
|
||||
message = prov.scan_start_request('thread', sec, blocking=True, group_channels=0)
|
||||
start_time = time.time()
|
||||
response = await tp.send_data('prov-scan', message)
|
||||
stop_time = time.time()
|
||||
print('++++ Scan process executed in ' + str(stop_time - start_time) + ' sec')
|
||||
prov.scan_start_response(sec, response)
|
||||
|
||||
message = prov.scan_status_request('thread', sec)
|
||||
response = await tp.send_data('prov-scan', message)
|
||||
result = prov.scan_status_response(sec, response)
|
||||
print('++++ Scan results : ' + str(result['count']))
|
||||
if result['count'] != 0:
|
||||
index = 0
|
||||
remaining = result['count']
|
||||
while remaining:
|
||||
count = [remaining, readlen][remaining > readlen]
|
||||
message = prov.scan_result_request('thread', sec, index, count)
|
||||
response = await tp.send_data('prov-scan', message)
|
||||
Networks += prov.scan_result_response(sec, response)
|
||||
remaining -= count
|
||||
index += count
|
||||
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
return None
|
||||
|
||||
return Networks
|
||||
|
||||
|
||||
async def send_thread_config(tp, sec, dataset_tlvs):
|
||||
try:
|
||||
message = prov.config_set_config_request('thread', sec, dataset_tlvs)
|
||||
response = await tp.send_data('prov-config', message)
|
||||
return (prov.config_set_config_response(sec, response) == 0)
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
return None
|
||||
|
||||
|
||||
async def apply_thread_config(tp, sec):
|
||||
try:
|
||||
message = prov.config_apply_config_request('thread', sec)
|
||||
response = await tp.send_data('prov-config', message)
|
||||
return (prov.config_apply_config_response(sec, response) == 0)
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
return None
|
||||
|
||||
|
||||
async def get_thread_config(tp, sec):
|
||||
try:
|
||||
message = prov.config_get_status_request('thread', sec)
|
||||
response = await tp.send_data('prov-config', message)
|
||||
return prov.config_get_status_response(sec, response)
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
return None
|
||||
|
||||
|
||||
async def wait_thread_connected(tp, sec):
|
||||
"""
|
||||
Wait for provisioning to report Thread is attached
|
||||
|
||||
Returns True if Thread connection succeeded, False if connection consistently failed
|
||||
"""
|
||||
TIME_PER_POLL = 5
|
||||
retry = 3
|
||||
|
||||
while True:
|
||||
time.sleep(TIME_PER_POLL)
|
||||
print('\n==== Thread connection state ====')
|
||||
ret = await get_thread_config(tp, sec)
|
||||
if ret == 'attaching':
|
||||
continue
|
||||
elif ret == 'attached':
|
||||
print('==== Provisioning was successful ====')
|
||||
return True
|
||||
elif retry > 0:
|
||||
retry -= 1
|
||||
print('Waiting to poll status again (status %s, %d tries left)...' % (ret, retry))
|
||||
else:
|
||||
print('---- Provisioning failed! ----')
|
||||
return False
|
||||
|
||||
|
||||
async def reset_thread(tp, sec):
|
||||
try:
|
||||
message = prov.ctrl_reset_request('thread', sec)
|
||||
response = await tp.send_data('prov-ctrl', message)
|
||||
prov.ctrl_reset_response(sec, response)
|
||||
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
return None
|
||||
|
||||
|
||||
async def reprov_thread(tp, sec):
|
||||
try:
|
||||
message = prov.ctrl_reprov_request('thread', sec)
|
||||
response = await tp.send_data('prov-ctrl', message)
|
||||
prov.ctrl_reprov_response(sec, response)
|
||||
|
||||
except RuntimeError as e:
|
||||
on_except(e)
|
||||
return None
|
||||
|
||||
|
||||
def desc_format(*args):
|
||||
desc = ''
|
||||
for arg in args:
|
||||
desc += textwrap.fill(replace_whitespace=False, text=arg) + '\n'
|
||||
return desc
|
||||
|
||||
|
||||
async def main():
|
||||
parser = argparse.ArgumentParser(description=desc_format(
|
||||
'ESP Provisioning tool for configuring devices '
|
||||
'running protocomm based provisioning service.',
|
||||
'See esp-idf/examples/provisioning for sample applications'),
|
||||
formatter_class=argparse.RawTextHelpFormatter)
|
||||
|
||||
parser.add_argument('--transport', required=True, dest='mode', type=str,
|
||||
help=desc_format(
|
||||
'Mode of transport over which provisioning is to be performed.',
|
||||
'This should be one of "softap", "ble", "console" (or "httpd" which is an alias of softap)'))
|
||||
|
||||
parser.add_argument('--service_name', dest='name', type=str,
|
||||
help=desc_format(
|
||||
'This specifies the name of the provisioning service to connect to, '
|
||||
'depending upon the mode of transport :',
|
||||
'\t- transport "ble" : The BLE Device Name',
|
||||
'\t- transport "softap/httpd" : HTTP Server hostname or IP',
|
||||
'\t (default "192.168.4.1:80")'))
|
||||
|
||||
parser.add_argument('--proto_ver', dest='version', type=str, default='',
|
||||
help=desc_format(
|
||||
'This checks the protocol version of the provisioning service running '
|
||||
'on the device before initiating Wi-Fi configuration'))
|
||||
|
||||
parser.add_argument('--sec_ver', dest='secver', type=int, default=None,
|
||||
help=desc_format(
|
||||
'Protocomm security scheme used by the provisioning service for secure '
|
||||
'session establishment. Accepted values are :',
|
||||
'\t- 0 : No security',
|
||||
'\t- 1 : X25519 key exchange + AES-CTR encryption',
|
||||
'\t + Authentication using Proof of Possession (PoP)',
|
||||
'\t- 2 : SRP6a + AES-GCM encryption',
|
||||
'In case device side application uses IDF\'s provisioning manager, '
|
||||
'the compatible security version is automatically determined from '
|
||||
'capabilities retrieved via the version endpoint'))
|
||||
|
||||
parser.add_argument('--pop', dest='sec1_pop', type=str, default='',
|
||||
help=desc_format(
|
||||
'This specifies the Proof of possession (PoP) when security scheme 1 '
|
||||
'is used'))
|
||||
|
||||
parser.add_argument('--sec2_username', dest='sec2_usr', type=str, default='',
|
||||
help=desc_format(
|
||||
'Username for security scheme 2 (SRP6a)'))
|
||||
|
||||
parser.add_argument('--sec2_pwd', dest='sec2_pwd', type=str, default='',
|
||||
help=desc_format(
|
||||
'Password for security scheme 2 (SRP6a)'))
|
||||
|
||||
parser.add_argument('--sec2_gen_cred', help='Generate salt and verifier for security scheme 2 (SRP6a)', action='store_true')
|
||||
|
||||
parser.add_argument('--sec2_salt_len', dest='sec2_salt_len', type=int, default=16,
|
||||
help=desc_format(
|
||||
'Salt length for security scheme 2 (SRP6a)'))
|
||||
|
||||
parser.add_argument('--ssid', dest='ssid', type=str, default='',
|
||||
help=desc_format(
|
||||
'This configures the device to use SSID of the Wi-Fi network to which '
|
||||
'we would like it to connect to permanently, once provisioning is complete. '
|
||||
'If Wi-Fi scanning is supported by the provisioning service, this need not '
|
||||
'be specified'))
|
||||
|
||||
parser.add_argument('--passphrase', dest='passphrase', type=str,
|
||||
help=desc_format(
|
||||
'This configures the device to use Passphrase for the Wi-Fi network to which '
|
||||
'we would like it to connect to permanently, once provisioning is complete. '
|
||||
'If Wi-Fi scanning is supported by the provisioning service, this need not '
|
||||
'be specified'))
|
||||
|
||||
parser.add_argument('--dataset_tlvs', dest='dataset_tlvs', type=str,
|
||||
help=desc_format(
|
||||
'This configures the device to use Dataset Tlvs of the Thread network to '
|
||||
'which we would like it to attach to permanently, once provisioning is '
|
||||
'complete. If Thread scanning is supported by the provisioning service, this '
|
||||
'need not be specified'))
|
||||
|
||||
parser.add_argument('--custom_data', dest='custom_data', type=str, default='',
|
||||
help=desc_format(
|
||||
'This is an optional parameter, only intended for use with '
|
||||
'"examples/wifi_prov"'))
|
||||
|
||||
parser.add_argument('--reset', help='Reset WiFi', action='store_true')
|
||||
|
||||
parser.add_argument('--reprov', help='Reprovision WiFi', action='store_true')
|
||||
|
||||
parser.add_argument('-v','--verbose', help='Increase output verbosity', action='store_true')
|
||||
|
||||
parser.add_argument('--ble_adapter', dest='ble_adapter', type=str, default=transport.DEFAULT_BLE_ADAPTER,
|
||||
help=desc_format(
|
||||
f'HCI adapter to use for BLE (default: {transport.DEFAULT_BLE_ADAPTER}).',
|
||||
'Use with vhci_bridge for emulated devices, e.g. --ble_adapter hci1'))
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.secver == 2 and args.sec2_gen_cred:
|
||||
if not args.sec2_usr or not args.sec2_pwd:
|
||||
raise ValueError('Username/password cannot be empty for security scheme 2 (SRP6a)')
|
||||
|
||||
print('==== Salt-verifier for security scheme 2 (SRP6a) ====')
|
||||
security.sec2_gen_salt_verifier(args.sec2_usr, args.sec2_pwd, args.sec2_salt_len)
|
||||
sys.exit()
|
||||
|
||||
obj_transport = await get_transport(args.mode.lower(), args.name, args.ble_adapter)
|
||||
if obj_transport is None:
|
||||
raise RuntimeError('Failed to establish connection')
|
||||
|
||||
try:
|
||||
sec_patch_ver = 0
|
||||
# If security version not specified check in capabilities
|
||||
if args.secver is None:
|
||||
# First check if capabilities are supported or not
|
||||
if not await has_capability(obj_transport):
|
||||
print('Security capabilities could not be determined, please specify "--sec_ver" explicitly')
|
||||
raise ValueError('Invalid Security Version')
|
||||
|
||||
# When no_sec is present, use security 0, else security 1
|
||||
args.secver = int(not await has_capability(obj_transport, 'no_sec'))
|
||||
print(f'==== Security Scheme: {args.secver} ====')
|
||||
|
||||
if (args.secver == 1):
|
||||
if not await has_capability(obj_transport, 'no_pop'):
|
||||
if len(args.sec1_pop) == 0:
|
||||
prompt_str = 'Proof of Possession required: '
|
||||
args.sec1_pop = getpass(prompt_str)
|
||||
elif len(args.sec1_pop) != 0:
|
||||
print('Proof of Possession will be ignored')
|
||||
args.sec1_pop = ''
|
||||
|
||||
if (args.secver == 2):
|
||||
sec_patch_ver = await get_sec_patch_ver(obj_transport, args.verbose)
|
||||
if len(args.sec2_usr) == 0:
|
||||
args.sec2_usr = input('Security Scheme 2 - SRP6a Username required: ')
|
||||
if len(args.sec2_pwd) == 0:
|
||||
prompt_str = 'Security Scheme 2 - SRP6a Password required: '
|
||||
args.sec2_pwd = getpass(prompt_str)
|
||||
|
||||
obj_security = get_security(args.secver, sec_patch_ver, args.sec2_usr, args.sec2_pwd, args.sec1_pop, args.verbose)
|
||||
if obj_security is None:
|
||||
raise ValueError('Invalid Security Version')
|
||||
|
||||
if args.version != '':
|
||||
print('\n==== Verifying protocol version ====')
|
||||
if not await version_match(obj_transport, args.version, args.verbose):
|
||||
raise RuntimeError('Error in protocol version matching')
|
||||
print('==== Verified protocol version successfully ====')
|
||||
|
||||
print('\n==== Starting Session ====')
|
||||
if not await establish_session(obj_transport, obj_security):
|
||||
print('Failed to establish session. Ensure that security scheme and proof of possession are correct')
|
||||
raise RuntimeError('Error in establishing session')
|
||||
print('==== Session Established ====')
|
||||
|
||||
if await has_capability(obj_transport, 'thread_prov'):
|
||||
if args.reset:
|
||||
print('==== Resetting Thread====')
|
||||
await reset_thread(obj_transport, obj_security)
|
||||
sys.exit()
|
||||
|
||||
if args.reprov:
|
||||
print('==== Reprovisioning Thread====')
|
||||
await reprov_thread(obj_transport, obj_security)
|
||||
sys.exit()
|
||||
|
||||
if args.dataset_tlvs is None:
|
||||
if not await has_capability(obj_transport, 'thread_scan'):
|
||||
prompt_str = 'Enter Thread dataset tlvs string : '
|
||||
args.dataset_tlvs = input(prompt_str)
|
||||
else:
|
||||
while True:
|
||||
print('\n==== Scanning Thread Networks ====')
|
||||
start_time = time.time()
|
||||
Networks = await scan_thread_networks(args.mode.lower(), obj_transport, obj_security)
|
||||
end_time = time.time()
|
||||
print('\n++++ Scan finished in ' + str(end_time - start_time) + ' sec')
|
||||
if Networks is None:
|
||||
raise RuntimeError('Error in scanning Thread Networks')
|
||||
|
||||
if len(Networks) == 0:
|
||||
print('No Thread Networks found!')
|
||||
sys.exit()
|
||||
|
||||
print('==== Thread Scan results ====')
|
||||
print('{0: >4} {1: <8} {2: <18} {3: <18} {4: <18} {5: <4} {6: <4} {7: <16}'.format(
|
||||
'S.N.', 'PAN ID', 'EXT PAN ID', 'NAME', 'EXT ADDR', 'CHN', 'RSSI', 'LQI'))
|
||||
for i in range(len(Networks)):
|
||||
print('[{0: >2}] {1: <8} {2: <18} {3: <18} {4: <18} {5: <4} {6: <4} {7: <16}'.format(
|
||||
i + 1, Networks[i]['pan_id'], Networks[i]['ext_pan_id'], Networks[i]['network_name'],
|
||||
Networks[i]['ext_addr'], Networks[i]['channel'], Networks[i]['rssi'], Networks[i]['lqi']))
|
||||
|
||||
while True:
|
||||
try:
|
||||
select = int(input('Select Network by number (0 to rescan) : '))
|
||||
if select < 0 or select > len(Networks):
|
||||
raise ValueError
|
||||
break
|
||||
except ValueError:
|
||||
print('Invalid input! Retry')
|
||||
|
||||
if select != 0:
|
||||
network_key = getpass('Enter Thread network key string : ')
|
||||
args.dataset_tlvs = get_thread_dataset_tlvs(Networks[select], network_key)
|
||||
break
|
||||
|
||||
print('\n==== Sending Thread Dataset to Target ====')
|
||||
if not await send_thread_config(obj_transport, obj_security, args.dataset_tlvs):
|
||||
raise RuntimeError('Error in send Thread config')
|
||||
print('==== Thread Dataset sent successfully ====')
|
||||
|
||||
print('\n==== Applying Thread Config to Target ====')
|
||||
if not await apply_thread_config(obj_transport, obj_security):
|
||||
raise RuntimeError('Error in apply Thread config')
|
||||
print('==== Apply config sent successfully ====')
|
||||
|
||||
await wait_thread_connected(obj_transport, obj_security)
|
||||
else:
|
||||
if not await has_capability(obj_transport, 'wifi_prov'):
|
||||
print('Use wifi_provisioning for device without "wifi_prov" capabilities')
|
||||
print('The device might be using previous wifi_provisioning in ESP-IDF')
|
||||
|
||||
if args.reset:
|
||||
print('==== Resetting WiFi====')
|
||||
await reset_wifi(obj_transport, obj_security)
|
||||
sys.exit()
|
||||
|
||||
if args.reprov:
|
||||
print('==== Reprovisioning WiFi====')
|
||||
await reprov_wifi(obj_transport, obj_security)
|
||||
sys.exit()
|
||||
|
||||
if args.custom_data != '':
|
||||
print('\n==== Sending Custom data to Target ====')
|
||||
if not await custom_data(obj_transport, obj_security, args.custom_data):
|
||||
raise RuntimeError('Error in custom data')
|
||||
print('==== Custom data sent successfully ====')
|
||||
|
||||
if args.ssid == '':
|
||||
if not await has_capability(obj_transport, 'wifi_scan'):
|
||||
raise RuntimeError('Wi-Fi Scan List is not supported by provisioning service')
|
||||
|
||||
while True:
|
||||
print('\n==== Scanning Wi-Fi APs ====')
|
||||
start_time = time.time()
|
||||
APs = await scan_wifi_APs(args.mode.lower(), obj_transport, obj_security)
|
||||
end_time = time.time()
|
||||
print('\n++++ Scan finished in ' + str(end_time - start_time) + ' sec')
|
||||
if APs is None:
|
||||
raise RuntimeError('Error in scanning Wi-Fi APs')
|
||||
|
||||
if len(APs) == 0:
|
||||
print('No APs found!')
|
||||
sys.exit()
|
||||
|
||||
print('==== Wi-Fi Scan results ====')
|
||||
print('{0: >4} {1: <33} {2: <12} {3: >4} {4: <4} {5: <16}'.format(
|
||||
'S.N.', 'SSID', 'BSSID', 'CHN', 'RSSI', 'AUTH'))
|
||||
for i in range(len(APs)):
|
||||
print('[{0: >2}] {1: <33} {2: <12} {3: >4} {4: <4} {5: <16}'.format(
|
||||
i + 1, APs[i]['ssid'], APs[i]['bssid'], APs[i]['channel'], APs[i]['rssi'], APs[i]['auth']))
|
||||
|
||||
while True:
|
||||
try:
|
||||
select = int(input('Select AP by number (0 to rescan) : '))
|
||||
if select < 0 or select > len(APs):
|
||||
raise ValueError
|
||||
break
|
||||
except ValueError:
|
||||
print('Invalid input! Retry')
|
||||
|
||||
if select != 0:
|
||||
break
|
||||
|
||||
args.ssid = APs[select - 1]['ssid']
|
||||
|
||||
if args.passphrase is None:
|
||||
prompt_str = 'Enter passphrase for {0} : '.format(args.ssid)
|
||||
args.passphrase = getpass(prompt_str)
|
||||
|
||||
print('\n==== Sending Wi-Fi Credentials to Target ====')
|
||||
if not await send_wifi_config(obj_transport, obj_security, args.ssid, args.passphrase):
|
||||
raise RuntimeError('Error in send Wi-Fi config')
|
||||
print('==== Wi-Fi Credentials sent successfully ====')
|
||||
|
||||
print('\n==== Applying Wi-Fi Config to Target ====')
|
||||
if not await apply_wifi_config(obj_transport, obj_security):
|
||||
raise RuntimeError('Error in apply Wi-Fi config')
|
||||
print('==== Apply config sent successfully ====')
|
||||
|
||||
await wait_wifi_connected(obj_transport, obj_security)
|
||||
|
||||
finally:
|
||||
await obj_transport.disconnect()
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,38 @@
|
||||
# SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
import sys
|
||||
from importlib.abc import Loader
|
||||
from typing import Any
|
||||
|
||||
|
||||
def _load_source(name: str, path: str) -> Any:
|
||||
spec = importlib.util.spec_from_file_location(name, path)
|
||||
if not spec:
|
||||
return None
|
||||
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[spec.name] = module
|
||||
assert isinstance(spec.loader, Loader)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
idf_path = os.environ['IDF_PATH']
|
||||
esp_prov_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
# protocomm component related python files generated from .proto files
|
||||
constants_pb2 = _load_source('constants_pb2', idf_path + '/components/protocomm/python/constants_pb2.py')
|
||||
sec0_pb2 = _load_source('sec0_pb2', idf_path + '/components/protocomm/python/sec0_pb2.py')
|
||||
sec1_pb2 = _load_source('sec1_pb2', idf_path + '/components/protocomm/python/sec1_pb2.py')
|
||||
sec2_pb2 = _load_source('sec2_pb2', idf_path + '/components/protocomm/python/sec2_pb2.py')
|
||||
session_pb2 = _load_source('session_pb2', idf_path + '/components/protocomm/python/session_pb2.py')
|
||||
|
||||
# network_provisioning component related python files generated from .proto files
|
||||
network_constants_pb2 = _load_source('network_constants_pb2', esp_prov_path + '/../../python/network_constants_pb2.py')
|
||||
network_config_pb2 = _load_source('network_config_pb2', esp_prov_path + '/../../python/network_config_pb2.py')
|
||||
network_scan_pb2 = _load_source('network_scan_pb2', esp_prov_path + '/../../python/network_scan_pb2.py')
|
||||
network_ctrl_pb2 = _load_source('network_ctrl_pb2', esp_prov_path + '/../../python/network_ctrl_pb2.py')
|
||||
@@ -0,0 +1,8 @@
|
||||
# SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
from .custom_prov import * # noqa F403
|
||||
from .network_ctrl import * # noqa F403
|
||||
from .network_prov import * # noqa F403
|
||||
from .network_scan import * # noqa F403
|
||||
@@ -0,0 +1,26 @@
|
||||
# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# APIs for interpreting and creating protobuf packets for `custom-config` protocomm endpoint
|
||||
|
||||
from utils import str_to_bytes
|
||||
|
||||
|
||||
def print_verbose(security_ctx, data):
|
||||
if (security_ctx.verbose):
|
||||
print(f'\x1b[32;20m++++ {data} ++++\x1b[0m')
|
||||
|
||||
|
||||
def custom_data_request(security_ctx, data):
|
||||
# Encrypt the custom data
|
||||
enc_cmd = security_ctx.encrypt_data(str_to_bytes(data))
|
||||
print_verbose(security_ctx, f'Client -> Device (CustomData cmd): 0x{enc_cmd.hex()}')
|
||||
return enc_cmd.decode('latin-1')
|
||||
|
||||
|
||||
def custom_data_response(security_ctx, response_data):
|
||||
# Decrypt response packet
|
||||
decrypt = security_ctx.decrypt_data(str_to_bytes(response_data))
|
||||
print(f'++++ CustomData response: {str(decrypt)}++++')
|
||||
return 0
|
||||
@@ -0,0 +1,61 @@
|
||||
# SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# APIs for interpreting and creating protobuf packets for Wi-Fi State Controlling
|
||||
|
||||
import proto
|
||||
from utils import str_to_bytes
|
||||
|
||||
|
||||
def print_verbose(security_ctx, data):
|
||||
if (security_ctx.verbose):
|
||||
print(f'\x1b[32;20m++++ {data} ++++\x1b[0m')
|
||||
|
||||
|
||||
def ctrl_reset_request(network_type, security_ctx):
|
||||
# Form protobuf request packet for CtrlReset command
|
||||
cmd = proto.network_ctrl_pb2.NetworkCtrlPayload()
|
||||
if network_type == 'wifi':
|
||||
cmd.msg = proto.network_ctrl_pb2.TypeCmdCtrlWifiReset
|
||||
elif network_type == 'thread':
|
||||
cmd.msg = proto.network_ctrl_pb2.TypeCmdCtrlThreadReset
|
||||
else:
|
||||
raise RuntimeError
|
||||
enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString())
|
||||
print_verbose(security_ctx, f'Client -> Device (Encrypted CmdCtrlReset): 0x{enc_cmd.hex()}')
|
||||
return enc_cmd.decode('latin-1')
|
||||
|
||||
|
||||
def ctrl_reset_response(security_ctx, response_data):
|
||||
# Interpret protobuf response packet from CtrlReset command
|
||||
dec_resp = security_ctx.decrypt_data(str_to_bytes(response_data))
|
||||
resp = proto.network_ctrl_pb2.NetworkCtrlPayload()
|
||||
resp.ParseFromString(dec_resp)
|
||||
print_verbose(security_ctx, f'CtrlReset status: 0x{str(resp.status)}')
|
||||
if resp.status != 0:
|
||||
raise RuntimeError
|
||||
|
||||
|
||||
def ctrl_reprov_request(network_type, security_ctx):
|
||||
# Form protobuf request packet for CtrlReprov command
|
||||
cmd = proto.network_ctrl_pb2.NetworkCtrlPayload()
|
||||
if network_type == 'wifi':
|
||||
cmd.msg = proto.network_ctrl_pb2.TypeCmdCtrlWifiReprov
|
||||
elif network_type == 'thread':
|
||||
cmd.msg = proto.network_ctrl_pb2.TypeCmdCtrlThreadReprov
|
||||
else:
|
||||
raise RuntimeError
|
||||
enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString())
|
||||
print_verbose(security_ctx, f'Client -> Device (Encrypted CmdCtrlReset): 0x{enc_cmd.hex()}')
|
||||
return enc_cmd.decode('latin-1')
|
||||
|
||||
|
||||
def ctrl_reprov_response(security_ctx, response_data):
|
||||
# Interpret protobuf response packet from CtrlReprov command
|
||||
dec_resp = security_ctx.decrypt_data(str_to_bytes(response_data))
|
||||
resp = proto.network_ctrl_pb2.NetworkCtrlPayload()
|
||||
resp.ParseFromString(dec_resp)
|
||||
print_verbose(security_ctx, f'CtrlReset status: 0x{str(resp.status)}')
|
||||
if resp.status != 0:
|
||||
raise RuntimeError
|
||||
@@ -0,0 +1,140 @@
|
||||
# SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# APIs for interpreting and creating protobuf packets for Wi-Fi provisioning
|
||||
|
||||
import proto
|
||||
from utils import hex_str_to_bytes, str_to_bytes
|
||||
|
||||
|
||||
def print_verbose(security_ctx, data):
|
||||
if (security_ctx.verbose):
|
||||
print(f'++++ {data} ++++')
|
||||
|
||||
|
||||
def config_get_status_request(network_type, security_ctx):
|
||||
# Form protobuf request packet for GetStatus command
|
||||
cfg1 = proto.network_config_pb2.NetworkConfigPayload()
|
||||
if network_type == 'wifi':
|
||||
cfg1.msg = proto.network_config_pb2.TypeCmdGetWifiStatus
|
||||
cmd_get_wifi_status = proto.network_config_pb2.CmdGetWifiStatus()
|
||||
cfg1.cmd_get_wifi_status.MergeFrom(cmd_get_wifi_status)
|
||||
elif network_type == 'thread':
|
||||
cfg1.msg = proto.network_config_pb2.TypeCmdGetThreadStatus
|
||||
cmd_get_thread_status = proto.network_config_pb2.CmdGetThreadStatus()
|
||||
cfg1.cmd_get_thread_status.MergeFrom(cmd_get_thread_status)
|
||||
else:
|
||||
raise RuntimeError
|
||||
encrypted_cfg = security_ctx.encrypt_data(cfg1.SerializeToString())
|
||||
print_verbose(security_ctx, f'Client -> Device (Encrypted CmdGetStatus): 0x{encrypted_cfg.hex()}')
|
||||
return encrypted_cfg.decode('latin-1')
|
||||
|
||||
|
||||
def config_get_status_response(security_ctx, response_data):
|
||||
# Interpret protobuf response packet from GetStatus command
|
||||
decrypted_message = security_ctx.decrypt_data(str_to_bytes(response_data))
|
||||
cmd_resp1 = proto.network_config_pb2.NetworkConfigPayload()
|
||||
cmd_resp1.ParseFromString(decrypted_message)
|
||||
print_verbose(security_ctx, f'CmdGetStatus type: {str(cmd_resp1.msg)}')
|
||||
|
||||
if cmd_resp1.msg == proto.network_config_pb2.TypeRespGetWifiStatus:
|
||||
print_verbose(security_ctx, f'CmdGetStatus status: {str(cmd_resp1.resp_get_wifi_status.status)}')
|
||||
if cmd_resp1.resp_get_wifi_status.wifi_sta_state == 0:
|
||||
print('==== WiFi state: Connected ====')
|
||||
return 'connected'
|
||||
elif cmd_resp1.resp_get_wifi_status.wifi_sta_state == 1:
|
||||
print('++++ WiFi state: Connecting... ++++')
|
||||
if cmd_resp1.resp_get_wifi_status.HasField('attempt_failed'):
|
||||
if cmd_resp1.resp_get_wifi_status.attempt_failed.attempts_remaining:
|
||||
print(cmd_resp1.resp_get_wifi_status)
|
||||
else:
|
||||
print('attempt_failed {\n attempts_remaining: 0\n}')
|
||||
return 'connecting'
|
||||
elif cmd_resp1.resp_get_wifi_status.wifi_sta_state == 2:
|
||||
print('---- WiFi state: Disconnected ----')
|
||||
return 'disconnected'
|
||||
elif cmd_resp1.resp_get_wifi_status.wifi_sta_state == 3:
|
||||
print('---- WiFi state: Connection Failed ----')
|
||||
if cmd_resp1.resp_get_wifi_status.wifi_fail_reason == 0:
|
||||
print('---- Failure reason: Incorrect Password ----')
|
||||
elif cmd_resp1.resp_get_wifi_status.wifi_fail_reason == 1:
|
||||
print('---- Failure reason: Incorrect SSID ----')
|
||||
return 'failed'
|
||||
elif cmd_resp1.msg == proto.network_config_pb2.TypeRespGetThreadStatus:
|
||||
print_verbose(security_ctx, f'CmdGetStatus status: {str(cmd_resp1.resp_get_thread_status.status)}')
|
||||
if cmd_resp1.resp_get_thread_status.thread_state == 0:
|
||||
print('==== Thread state: Attached ====')
|
||||
return 'attached'
|
||||
elif cmd_resp1.resp_get_thread_status.thread_state == 1:
|
||||
print('==== Thread state: Attaching ====')
|
||||
return 'attaching'
|
||||
elif cmd_resp1.resp_get_thread_status.thread_state == 2:
|
||||
print('==== Thread state: Detached ====')
|
||||
return 'detached'
|
||||
elif cmd_resp1.resp_get_thread_status.thread_state == 3:
|
||||
print('==== Thread state: Attaching Failed ====')
|
||||
if cmd_resp1.resp_get_thread_status.thread_fail_reason == 0:
|
||||
print('---- Failure reason: Invalid Dataset ----')
|
||||
elif cmd_resp1.resp_get_thread_status.thread_fail_reason == 1:
|
||||
print('---- Failure reason: Network Not Found ----')
|
||||
return 'failed'
|
||||
|
||||
return 'unknown'
|
||||
|
||||
|
||||
def config_set_config_request(network_type, security_ctx, ssid_or_dataset_tlvs, passphrase=''):
|
||||
# Form protobuf request packet for SetConfig command
|
||||
cmd = proto.network_config_pb2.NetworkConfigPayload()
|
||||
if network_type == 'wifi':
|
||||
cmd.msg = proto.network_config_pb2.TypeCmdSetWifiConfig
|
||||
cmd.cmd_set_wifi_config.ssid = str_to_bytes(ssid_or_dataset_tlvs)
|
||||
cmd.cmd_set_wifi_config.passphrase = str_to_bytes(passphrase)
|
||||
elif network_type == 'thread':
|
||||
cmd.msg = proto.network_config_pb2.TypeCmdSetThreadConfig
|
||||
cmd.cmd_set_thread_config.dataset = hex_str_to_bytes(ssid_or_dataset_tlvs)
|
||||
else:
|
||||
raise RuntimeError
|
||||
enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString())
|
||||
print_verbose(security_ctx, f'Client -> Device (SetConfig cmd): 0x{enc_cmd.hex()}')
|
||||
return enc_cmd.decode('latin-1')
|
||||
|
||||
|
||||
def config_set_config_response(security_ctx, response_data):
|
||||
# Interpret protobuf response packet from SetConfig command
|
||||
decrypt = security_ctx.decrypt_data(str_to_bytes(response_data))
|
||||
cmd_resp4 = proto.network_config_pb2.NetworkConfigPayload()
|
||||
cmd_resp4.ParseFromString(decrypt)
|
||||
if cmd_resp4.msg == proto.network_config_pb2.TypeRespSetWifiConfig:
|
||||
print_verbose(security_ctx, f'SetConfig status: 0x{str(cmd_resp4.resp_set_wifi_config.status)}')
|
||||
return cmd_resp4.resp_set_wifi_config.status
|
||||
elif cmd_resp4.msg == proto.network_config_pb2.TypeRespSetThreadConfig:
|
||||
print_verbose(security_ctx, f'SetConfig status: 0x{str(cmd_resp4.resp_set_thread_config.status)}')
|
||||
return cmd_resp4.resp_set_thread_config.status
|
||||
|
||||
|
||||
def config_apply_config_request(network_type, security_ctx):
|
||||
# Form protobuf request packet for ApplyConfig command
|
||||
cmd = proto.network_config_pb2.NetworkConfigPayload()
|
||||
if network_type == 'wifi':
|
||||
cmd.msg = proto.network_config_pb2.TypeCmdApplyWifiConfig
|
||||
elif network_type == 'thread':
|
||||
cmd.msg = proto.network_config_pb2.TypeCmdApplyThreadConfig
|
||||
else:
|
||||
raise RuntimeError
|
||||
enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString())
|
||||
print_verbose(security_ctx, f'Client -> Device (ApplyConfig cmd): 0x{enc_cmd.hex()}')
|
||||
return enc_cmd.decode('latin-1')
|
||||
|
||||
|
||||
def config_apply_config_response(security_ctx, response_data):
|
||||
# Interpret protobuf response packet from ApplyConfig command
|
||||
decrypt = security_ctx.decrypt_data(str_to_bytes(response_data))
|
||||
cmd_resp5 = proto.network_config_pb2.NetworkConfigPayload()
|
||||
cmd_resp5.ParseFromString(decrypt)
|
||||
if cmd_resp5.msg == proto.network_config_pb2.TypeRespApplyWifiConfig:
|
||||
print_verbose(security_ctx, f'ApplyConfig status: 0x{str(cmd_resp5.resp_apply_wifi_config.status)}')
|
||||
return cmd_resp5.resp_apply_wifi_config.status
|
||||
elif cmd_resp5.msg == proto.network_config_pb2.TypeRespApplyThreadConfig:
|
||||
print_verbose(security_ctx, f'ApplyConfig status: 0x{str(cmd_resp5.resp_apply_thread_config.status)}')
|
||||
return cmd_resp5.resp_apply_thread_config.status
|
||||
@@ -0,0 +1,129 @@
|
||||
# SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# APIs for interpreting and creating protobuf packets for Wi-Fi Scanning
|
||||
import proto
|
||||
from utils import str_to_bytes
|
||||
|
||||
|
||||
def print_verbose(security_ctx, data):
|
||||
if (security_ctx.verbose):
|
||||
print(f'\x1b[32;20m++++ {data} ++++\x1b[0m')
|
||||
|
||||
|
||||
def scan_start_request(network_type, security_ctx, blocking=True, passive=False, group_channels=5, period_ms=120):
|
||||
# Form protobuf request packet for ScanStart command
|
||||
cmd = proto.network_scan_pb2.NetworkScanPayload()
|
||||
if network_type == 'wifi':
|
||||
cmd.msg = proto.network_scan_pb2.TypeCmdScanWifiStart
|
||||
cmd.cmd_scan_wifi_start.blocking = blocking
|
||||
cmd.cmd_scan_wifi_start.passive = passive
|
||||
cmd.cmd_scan_wifi_start.group_channels = group_channels
|
||||
cmd.cmd_scan_wifi_start.period_ms = period_ms
|
||||
elif network_type == 'thread':
|
||||
cmd.msg = proto.network_scan_pb2.TypeCmdScanThreadStart
|
||||
cmd.cmd_scan_thread_start.blocking = blocking
|
||||
cmd.cmd_scan_thread_start.channel_mask = 0
|
||||
else:
|
||||
raise RuntimeError
|
||||
|
||||
enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString())
|
||||
print_verbose(security_ctx, f'Client -> Device (Encrypted CmdScanStart): 0x{enc_cmd.hex()}')
|
||||
return enc_cmd.decode('latin-1')
|
||||
|
||||
|
||||
def scan_start_response(security_ctx, response_data):
|
||||
# Interpret protobuf response packet from ScanStart command
|
||||
dec_resp = security_ctx.decrypt_data(str_to_bytes(response_data))
|
||||
resp = proto.network_scan_pb2.NetworkScanPayload()
|
||||
resp.ParseFromString(dec_resp)
|
||||
print_verbose(security_ctx, f'ScanStart status: 0x{str(resp.status)}')
|
||||
if resp.status != 0:
|
||||
raise RuntimeError
|
||||
|
||||
|
||||
def scan_status_request(network_type, security_ctx):
|
||||
# Form protobuf request packet for ScanStatus command
|
||||
cmd = proto.network_scan_pb2.NetworkScanPayload()
|
||||
if network_type == 'wifi':
|
||||
cmd.msg = proto.network_scan_pb2.TypeCmdScanWifiStatus
|
||||
elif network_type == 'thread':
|
||||
cmd.msg = proto.network_scan_pb2.TypeCmdScanThreadStatus
|
||||
else:
|
||||
raise RuntimeError
|
||||
enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString())
|
||||
print_verbose(security_ctx, f'Client -> Device (Encrypted CmdScanStatus): 0x{enc_cmd.hex()}')
|
||||
return enc_cmd.decode('latin-1')
|
||||
|
||||
|
||||
def scan_status_response(security_ctx, response_data):
|
||||
# Interpret protobuf response packet from ScanStatus command
|
||||
dec_resp = security_ctx.decrypt_data(str_to_bytes(response_data))
|
||||
resp = proto.network_scan_pb2.NetworkScanPayload()
|
||||
resp.ParseFromString(dec_resp)
|
||||
print_verbose(security_ctx, f'ScanStatus status: 0x{str(resp.status)}')
|
||||
if resp.status != 0:
|
||||
raise RuntimeError
|
||||
if resp.msg == proto.network_scan_pb2.TypeRespScanWifiStatus:
|
||||
return {'finished': resp.resp_scan_wifi_status.scan_finished, 'count': resp.resp_scan_wifi_status.result_count}
|
||||
elif resp.msg == proto.network_scan_pb2.TypeRespScanThreadStatus:
|
||||
return {'finished': resp.resp_scan_thread_status.scan_finished, 'count': resp.resp_scan_thread_status.result_count}
|
||||
else:
|
||||
raise RuntimeError
|
||||
|
||||
|
||||
def scan_result_request(network_type, security_ctx, index, count):
|
||||
# Form protobuf request packet for ScanResult command
|
||||
cmd = proto.network_scan_pb2.NetworkScanPayload()
|
||||
if network_type == 'wifi':
|
||||
cmd.msg = proto.network_scan_pb2.TypeCmdScanWifiResult
|
||||
cmd.cmd_scan_wifi_result.start_index = index
|
||||
cmd.cmd_scan_wifi_result.count = count
|
||||
elif network_type == 'thread':
|
||||
cmd.msg = proto.network_scan_pb2.TypeCmdScanThreadResult
|
||||
cmd.cmd_scan_thread_result.start_index = index
|
||||
cmd.cmd_scan_thread_result.count = count
|
||||
else:
|
||||
raise RuntimeError
|
||||
enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString())
|
||||
print_verbose(security_ctx, f'Client -> Device (Encrypted CmdScanResult): 0x{enc_cmd.hex()}')
|
||||
return enc_cmd.decode('latin-1')
|
||||
|
||||
|
||||
def scan_result_response(security_ctx, response_data):
|
||||
# Interpret protobuf response packet from ScanResult command
|
||||
dec_resp = security_ctx.decrypt_data(str_to_bytes(response_data))
|
||||
resp = proto.network_scan_pb2.NetworkScanPayload()
|
||||
resp.ParseFromString(dec_resp)
|
||||
print_verbose(security_ctx, f'ScanResult status: 0x{str(resp.status)}')
|
||||
if resp.status != 0:
|
||||
raise RuntimeError
|
||||
results = []
|
||||
if resp.msg == proto.network_scan_pb2.TypeRespScanWifiResult:
|
||||
authmode_str = ['Open', 'WEP', 'WPA_PSK', 'WPA2_PSK', 'WPA_WPA2_PSK',
|
||||
'WPA2_ENTERPRISE', 'WPA3_PSK', 'WPA2_WPA3_PSK']
|
||||
for entry in resp.resp_scan_wifi_result.entries:
|
||||
results += [{'ssid': entry.ssid.decode('latin-1').rstrip('\x00'),
|
||||
'bssid': entry.bssid.hex(),
|
||||
'channel': entry.channel,
|
||||
'rssi': entry.rssi,
|
||||
'auth': authmode_str[entry.auth]}]
|
||||
print_verbose(security_ctx, f"ScanResult SSID : {str(results[-1]['ssid'])}")
|
||||
print_verbose(security_ctx, f"ScanResult BSSID : {str(results[-1]['bssid'])}")
|
||||
print_verbose(security_ctx, f"ScanResult Channel : {str(results[-1]['channel'])}")
|
||||
print_verbose(security_ctx, f"ScanResult RSSI : {str(results[-1]['rssi'])}")
|
||||
print_verbose(security_ctx, f"ScanResult AUTH : {str(results[-1]['auth'])}")
|
||||
elif resp.msg == proto.network_scan_pb2.TypeRespScanThreadResult:
|
||||
for entry in resp.resp_scan_thread_result.entries:
|
||||
results += [{'pan_id': entry.pan_id,
|
||||
'ext_pan_id': entry.ext_pan_id.hex(),
|
||||
'network_name': entry.network_name,
|
||||
'channel': entry.channel,
|
||||
'rssi': entry.rssi,
|
||||
'lqi': entry.lqi,
|
||||
'ext_addr': entry.ext_addr.hex()}]
|
||||
else:
|
||||
raise RuntimeError
|
||||
|
||||
return results
|
||||
@@ -0,0 +1,7 @@
|
||||
# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
from .security0 import * # noqa: F403, F401
|
||||
from .security1 import * # noqa: F403, F401
|
||||
from .security2 import * # noqa: F403, F401
|
||||
@@ -0,0 +1,10 @@
|
||||
# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# Base class for protocomm security
|
||||
|
||||
|
||||
class Security:
|
||||
def __init__(self, security_session):
|
||||
self.security_session = security_session
|
||||
@@ -0,0 +1,53 @@
|
||||
# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# APIs for interpreting and creating protobuf packets for
|
||||
# protocomm endpoint with security type protocomm_security0
|
||||
|
||||
import proto
|
||||
from utils import str_to_bytes
|
||||
|
||||
from .security import Security
|
||||
|
||||
|
||||
class Security0(Security):
|
||||
def __init__(self, verbose):
|
||||
# Initialize state of the security1 FSM
|
||||
self.session_state = 0
|
||||
self.verbose = verbose
|
||||
Security.__init__(self, self.security0_session)
|
||||
|
||||
def security0_session(self, response_data):
|
||||
# protocomm security0 FSM which interprets/forms
|
||||
# protobuf packets according to present state of session
|
||||
if (self.session_state == 0):
|
||||
self.session_state = 1
|
||||
return self.setup0_request()
|
||||
if (self.session_state == 1):
|
||||
self.setup0_response(response_data)
|
||||
return None
|
||||
|
||||
def setup0_request(self):
|
||||
# Form protocomm security0 request packet
|
||||
setup_req = proto.session_pb2.SessionData()
|
||||
setup_req.sec_ver = 0
|
||||
session_cmd = proto.sec0_pb2.S0SessionCmd()
|
||||
setup_req.sec0.sc.MergeFrom(session_cmd)
|
||||
return setup_req.SerializeToString().decode('latin-1')
|
||||
|
||||
def setup0_response(self, response_data):
|
||||
# Interpret protocomm security0 response packet
|
||||
setup_resp = proto.session_pb2.SessionData()
|
||||
setup_resp.ParseFromString(str_to_bytes(response_data))
|
||||
# Check if security scheme matches
|
||||
if setup_resp.sec_ver != proto.session_pb2.SecScheme0:
|
||||
raise RuntimeError('Incorrect security scheme')
|
||||
|
||||
def encrypt_data(self, data):
|
||||
# Passive. No encryption when security0 used
|
||||
return data
|
||||
|
||||
def decrypt_data(self, data):
|
||||
# Passive. No encryption when security0 used
|
||||
return data
|
||||
@@ -0,0 +1,140 @@
|
||||
# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# APIs for interpreting and creating protobuf packets for
|
||||
# protocomm endpoint with security type protocomm_security1
|
||||
|
||||
import proto
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes, serialization
|
||||
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey, X25519PublicKey
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
from utils import long_to_bytes, str_to_bytes
|
||||
|
||||
from .security import Security
|
||||
|
||||
|
||||
def a_xor_b(a: bytes, b: bytes) -> bytes:
|
||||
return b''.join(long_to_bytes(a[i] ^ b[i]) for i in range(0, len(b)))
|
||||
|
||||
|
||||
# Enum for state of protocomm_security1 FSM
|
||||
class security_state:
|
||||
REQUEST1 = 0
|
||||
RESPONSE1_REQUEST2 = 1
|
||||
RESPONSE2 = 2
|
||||
FINISHED = 3
|
||||
|
||||
|
||||
class Security1(Security):
|
||||
def __init__(self, pop, verbose):
|
||||
# Initialize state of the security1 FSM
|
||||
self.session_state = security_state.REQUEST1
|
||||
self.pop = str_to_bytes(pop)
|
||||
self.verbose = verbose
|
||||
Security.__init__(self, self.security1_session)
|
||||
|
||||
def security1_session(self, response_data):
|
||||
# protocomm security1 FSM which interprets/forms
|
||||
# protobuf packets according to present state of session
|
||||
if (self.session_state == security_state.REQUEST1):
|
||||
self.session_state = security_state.RESPONSE1_REQUEST2
|
||||
return self.setup0_request()
|
||||
elif (self.session_state == security_state.RESPONSE1_REQUEST2):
|
||||
self.session_state = security_state.RESPONSE2
|
||||
self.setup0_response(response_data)
|
||||
return self.setup1_request()
|
||||
elif (self.session_state == security_state.RESPONSE2):
|
||||
self.session_state = security_state.FINISHED
|
||||
self.setup1_response(response_data)
|
||||
return None
|
||||
|
||||
print('Unexpected state')
|
||||
return None
|
||||
|
||||
def __generate_key(self):
|
||||
# Generate private and public key pair for client
|
||||
self.client_private_key = X25519PrivateKey.generate()
|
||||
self.client_public_key = self.client_private_key.public_key().public_bytes(
|
||||
encoding=serialization.Encoding.Raw,
|
||||
format=serialization.PublicFormat.Raw)
|
||||
|
||||
def _print_verbose(self, data):
|
||||
if (self.verbose):
|
||||
print(f'\x1b[32;20m++++ {data} ++++\x1b[0m')
|
||||
|
||||
def setup0_request(self):
|
||||
# Form SessionCmd0 request packet using client public key
|
||||
setup_req = proto.session_pb2.SessionData()
|
||||
setup_req.sec_ver = proto.session_pb2.SecScheme1
|
||||
self.__generate_key()
|
||||
setup_req.sec1.sc0.client_pubkey = self.client_public_key
|
||||
self._print_verbose(f'Client Public Key:\t0x{self.client_public_key.hex()}')
|
||||
return setup_req.SerializeToString().decode('latin-1')
|
||||
|
||||
def setup0_response(self, response_data):
|
||||
# Interpret SessionResp0 response packet
|
||||
setup_resp = proto.session_pb2.SessionData()
|
||||
setup_resp.ParseFromString(str_to_bytes(response_data))
|
||||
self._print_verbose('Security version:\t' + str(setup_resp.sec_ver))
|
||||
if setup_resp.sec_ver != proto.session_pb2.SecScheme1:
|
||||
raise RuntimeError('Incorrect security scheme')
|
||||
|
||||
self.device_public_key = setup_resp.sec1.sr0.device_pubkey
|
||||
# Device random is the initialization vector
|
||||
device_random = setup_resp.sec1.sr0.device_random
|
||||
self._print_verbose(f'Device Public Key:\t0x{self.device_public_key.hex()}')
|
||||
self._print_verbose(f'Device Random:\t0x{device_random.hex()}')
|
||||
|
||||
# Calculate Curve25519 shared key using Client private key and Device public key
|
||||
sharedK = self.client_private_key.exchange(X25519PublicKey.from_public_bytes(self.device_public_key))
|
||||
self._print_verbose(f'Shared Key:\t0x{sharedK.hex()}')
|
||||
|
||||
# If PoP is provided, XOR SHA256 of PoP with the previously
|
||||
# calculated Shared Key to form the actual Shared Key
|
||||
if len(self.pop) > 0:
|
||||
# Calculate SHA256 of PoP
|
||||
h = hashes.Hash(hashes.SHA256(), backend=default_backend())
|
||||
h.update(self.pop)
|
||||
digest = h.finalize()
|
||||
# XOR with and update Shared Key
|
||||
sharedK = a_xor_b(sharedK, digest)
|
||||
self._print_verbose(f'Updated Shared Key (Shared key XORed with PoP):\t0x{sharedK.hex()}')
|
||||
# Initialize the encryption engine with Shared Key and initialization vector
|
||||
cipher = Cipher(algorithms.AES(sharedK), modes.CTR(device_random), backend=default_backend())
|
||||
self.cipher = cipher.encryptor()
|
||||
|
||||
def setup1_request(self):
|
||||
# Form SessionCmd1 request packet using encrypted device public key
|
||||
setup_req = proto.session_pb2.SessionData()
|
||||
setup_req.sec_ver = proto.session_pb2.SecScheme1
|
||||
setup_req.sec1.msg = proto.sec1_pb2.Session_Command1
|
||||
# Encrypt device public key and attach to the request packet
|
||||
client_verify = self.cipher.update(self.device_public_key)
|
||||
self._print_verbose(f'Client Proof:\t0x{client_verify.hex()}')
|
||||
setup_req.sec1.sc1.client_verify_data = client_verify
|
||||
return setup_req.SerializeToString().decode('latin-1')
|
||||
|
||||
def setup1_response(self, response_data):
|
||||
# Interpret SessionResp1 response packet
|
||||
setup_resp = proto.session_pb2.SessionData()
|
||||
setup_resp.ParseFromString(str_to_bytes(response_data))
|
||||
# Ensure security scheme matches
|
||||
if setup_resp.sec_ver == proto.session_pb2.SecScheme1:
|
||||
# Read encrypyed device verify string
|
||||
device_verify = setup_resp.sec1.sr1.device_verify_data
|
||||
self._print_verbose(f'Device Proof:\t0x{device_verify.hex()}')
|
||||
# Decrypt the device verify string
|
||||
enc_client_pubkey = self.cipher.update(setup_resp.sec1.sr1.device_verify_data)
|
||||
# Match decrypted string with client public key
|
||||
if enc_client_pubkey != self.client_public_key:
|
||||
raise RuntimeError('Failed to verify device!')
|
||||
else:
|
||||
raise RuntimeError('Unsupported security protocol')
|
||||
|
||||
def encrypt_data(self, data):
|
||||
return self.cipher.update(data)
|
||||
|
||||
def decrypt_data(self, data):
|
||||
return self.cipher.update(data)
|
||||
@@ -0,0 +1,182 @@
|
||||
# SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# APIs for interpreting and creating protobuf packets for
|
||||
# protocomm endpoint with security type protocomm_security2
|
||||
import struct
|
||||
from typing import Any
|
||||
from typing import Type
|
||||
|
||||
import proto
|
||||
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
||||
from utils import long_to_bytes
|
||||
from utils import str_to_bytes
|
||||
|
||||
from .security import Security
|
||||
from .srp6a import generate_salt_and_verifier
|
||||
from .srp6a import Srp6a
|
||||
|
||||
AES_KEY_LEN = 256 // 8
|
||||
|
||||
|
||||
# Enum for state of protocomm_security1 FSM
|
||||
class security_state:
|
||||
REQUEST1 = 0
|
||||
RESPONSE1_REQUEST2 = 1
|
||||
RESPONSE2 = 2
|
||||
FINISHED = 3
|
||||
|
||||
|
||||
def sec2_gen_salt_verifier(username: str, password: str, salt_len: int) -> Any:
|
||||
salt, verifier = generate_salt_and_verifier(username, password, len_s=salt_len)
|
||||
|
||||
salt_str = ', '.join([format(b, '#04x') for b in salt])
|
||||
salt_c_arr = '\n '.join(salt_str[i: i + 96] for i in range(0, len(salt_str), 96))
|
||||
print(f'static const char sec2_salt[] = {{\n {salt_c_arr}\n}};\n') # noqa E702
|
||||
|
||||
verifier_str = ', '.join([format(b, '#04x') for b in verifier])
|
||||
verifier_c_arr = '\n '.join(verifier_str[i: i + 96] for i in range(0, len(verifier_str), 96))
|
||||
print(f'static const char sec2_verifier[] = {{\n {verifier_c_arr}\n}};\n') # noqa E702
|
||||
|
||||
|
||||
class Security2(Security):
|
||||
def __init__(self, sec_patch_ver:int, username: str, password: str, verbose: bool) -> None:
|
||||
# Initialize state of the security2 FSM
|
||||
self.session_state = security_state.REQUEST1
|
||||
self.sec_patch_ver = sec_patch_ver
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.verbose = verbose
|
||||
|
||||
self.srp6a_ctx: Type[Srp6a]
|
||||
self.cipher: Type[AESGCM]
|
||||
|
||||
self.client_pop_key = None
|
||||
self.nonce = bytearray()
|
||||
|
||||
Security.__init__(self, self.security2_session)
|
||||
|
||||
def security2_session(self, response_data: bytes) -> Any:
|
||||
# protocomm security2 FSM which interprets/forms
|
||||
# protobuf packets according to present state of session
|
||||
if (self.session_state == security_state.REQUEST1):
|
||||
self.session_state = security_state.RESPONSE1_REQUEST2
|
||||
return self.setup0_request()
|
||||
|
||||
if (self.session_state == security_state.RESPONSE1_REQUEST2):
|
||||
self.session_state = security_state.RESPONSE2
|
||||
self.setup0_response(response_data)
|
||||
return self.setup1_request()
|
||||
|
||||
if (self.session_state == security_state.RESPONSE2):
|
||||
self.session_state = security_state.FINISHED
|
||||
self.setup1_response(response_data)
|
||||
return None
|
||||
|
||||
print('---- Unexpected state! ----')
|
||||
return None
|
||||
|
||||
def _print_verbose(self, data: str) -> None:
|
||||
if (self.verbose):
|
||||
print(f'\x1b[32;20m++++ {data} ++++\x1b[0m') # noqa E702
|
||||
|
||||
def setup0_request(self) -> Any:
|
||||
# Form SessionCmd0 request packet using client public key
|
||||
setup_req = proto.session_pb2.SessionData()
|
||||
setup_req.sec_ver = proto.session_pb2.SecScheme2
|
||||
setup_req.sec2.msg = proto.sec2_pb2.S2Session_Command0
|
||||
|
||||
setup_req.sec2.sc0.client_username = str_to_bytes(self.username)
|
||||
self.srp6a_ctx = Srp6a(self.username, self.password)
|
||||
if self.srp6a_ctx is None:
|
||||
raise RuntimeError('Failed to initialize SRP6a instance!')
|
||||
|
||||
client_pubkey = long_to_bytes(self.srp6a_ctx.A)
|
||||
setup_req.sec2.sc0.client_pubkey = client_pubkey
|
||||
|
||||
self._print_verbose(f'Client Public Key:\t0x{client_pubkey.hex()}')
|
||||
return setup_req.SerializeToString().decode('latin-1')
|
||||
|
||||
def setup0_response(self, response_data: bytes) -> None:
|
||||
# Interpret SessionResp0 response packet
|
||||
setup_resp = proto.session_pb2.SessionData()
|
||||
setup_resp.ParseFromString(str_to_bytes(response_data))
|
||||
self._print_verbose(f'Security version:\t{str(setup_resp.sec_ver)}')
|
||||
if setup_resp.sec_ver != proto.session_pb2.SecScheme2:
|
||||
raise RuntimeError('Incorrect security scheme')
|
||||
|
||||
# Device public key, random salt and password verifier
|
||||
device_pubkey = setup_resp.sec2.sr0.device_pubkey
|
||||
device_salt = setup_resp.sec2.sr0.device_salt
|
||||
|
||||
self._print_verbose(f'Device Public Key:\t0x{device_pubkey.hex()}')
|
||||
self.client_pop_key = self.srp6a_ctx.process_challenge(device_salt, device_pubkey)
|
||||
|
||||
def setup1_request(self) -> Any:
|
||||
# Form SessionCmd1 request packet using encrypted device public key
|
||||
setup_req = proto.session_pb2.SessionData()
|
||||
setup_req.sec_ver = proto.session_pb2.SecScheme2
|
||||
setup_req.sec2.msg = proto.sec2_pb2.S2Session_Command1
|
||||
|
||||
# Encrypt device public key and attach to the request packet
|
||||
if self.client_pop_key is None:
|
||||
raise RuntimeError('Failed to generate client proof!')
|
||||
|
||||
self._print_verbose(f'Client Proof:\t0x{self.client_pop_key.hex()}')
|
||||
setup_req.sec2.sc1.client_proof = self.client_pop_key
|
||||
|
||||
return setup_req.SerializeToString().decode('latin-1')
|
||||
|
||||
def setup1_response(self, response_data: bytes) -> Any:
|
||||
# Interpret SessionResp1 response packet
|
||||
setup_resp = proto.session_pb2.SessionData()
|
||||
setup_resp.ParseFromString(str_to_bytes(response_data))
|
||||
# Ensure security scheme matches
|
||||
if setup_resp.sec_ver == proto.session_pb2.SecScheme2:
|
||||
# Read encrypyed device proof string
|
||||
device_proof = setup_resp.sec2.sr1.device_proof
|
||||
self._print_verbose(f'Device Proof:\t0x{device_proof.hex()}')
|
||||
self.srp6a_ctx.verify_session(device_proof)
|
||||
if not self.srp6a_ctx.authenticated():
|
||||
raise RuntimeError('Failed to verify device proof')
|
||||
else:
|
||||
raise RuntimeError('Unsupported security protocol')
|
||||
|
||||
# Getting the shared secret
|
||||
shared_secret = self.srp6a_ctx.get_session_key()
|
||||
self._print_verbose(f'Shared Secret:\t0x{shared_secret.hex()}')
|
||||
|
||||
# Using the first 256 bits of a 512 bit key
|
||||
session_key = shared_secret[:AES_KEY_LEN]
|
||||
self._print_verbose(f'Session Key:\t0x{session_key.hex()}')
|
||||
|
||||
# 96-bit nonce
|
||||
self.nonce = bytearray(setup_resp.sec2.sr1.device_nonce)
|
||||
if self.nonce is None:
|
||||
raise RuntimeError('Received invalid nonce from device!')
|
||||
self._print_verbose(f'Nonce:\t0x{self.nonce.hex()}')
|
||||
|
||||
# Initialize the encryption engine with Shared Key and initialization vector
|
||||
self.cipher = AESGCM(session_key)
|
||||
if self.cipher is None:
|
||||
raise RuntimeError('Failed to initialize AES-GCM cryptographic engine!')
|
||||
|
||||
def _increment_nonce(self) -> None:
|
||||
"""Increment the last 4 bytes of nonce (big-endian counter)."""
|
||||
if self.sec_patch_ver == 1:
|
||||
counter = struct.unpack('>I', self.nonce[8:])[0] # Read last 4 bytes as big-endian integer
|
||||
counter += 1 # Increment counter
|
||||
if counter > 0xFFFFFFFF: # Check for overflow
|
||||
raise RuntimeError('Nonce counter overflow')
|
||||
self.nonce[8:] = struct.pack('>I', counter) # Store back as big-endian
|
||||
|
||||
def encrypt_data(self, data: bytes) -> Any:
|
||||
self._print_verbose(f'Nonce:\t0x{self.nonce.hex()}')
|
||||
ciphertext = self.cipher.encrypt(self.nonce, data, None)
|
||||
self._increment_nonce()
|
||||
return ciphertext
|
||||
|
||||
def decrypt_data(self, data: bytes) -> Any:
|
||||
self._print_verbose(f'Nonce:\t0x{self.nonce.hex()}')
|
||||
plaintext = self.cipher.decrypt(self.nonce, data, None)
|
||||
self._increment_nonce()
|
||||
return plaintext
|
||||
@@ -0,0 +1,301 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# N A large safe prime (N = 2q+1, where q is prime) [All arithmetic is done modulo N]
|
||||
# g A generator modulo N
|
||||
# k Multiplier parameter (k = H(N, g) in SRP-6a, k = 3 for legacy SRP-6)
|
||||
# s User's salt
|
||||
# Iu Username
|
||||
# p Cleartext Password
|
||||
# H() One-way hash function
|
||||
# ^ (Modular) Exponentiation
|
||||
# u Random scrambling parameter
|
||||
# a, b Secret ephemeral values
|
||||
# A, B Public ephemeral values
|
||||
# x Private key (derived from p and s)
|
||||
# v Password verifier
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
from typing import Any, Callable, Optional, Tuple
|
||||
|
||||
from utils import bytes_to_long, long_to_bytes
|
||||
|
||||
SHA1 = 0
|
||||
SHA224 = 1
|
||||
SHA256 = 2
|
||||
SHA384 = 3
|
||||
SHA512 = 4
|
||||
|
||||
NG_1024 = 0
|
||||
NG_2048 = 1
|
||||
NG_3072 = 2
|
||||
NG_4096 = 3
|
||||
NG_8192 = 4
|
||||
|
||||
_hash_map = {SHA1: hashlib.sha1,
|
||||
SHA224: hashlib.sha224,
|
||||
SHA256: hashlib.sha256,
|
||||
SHA384: hashlib.sha384,
|
||||
SHA512: hashlib.sha512}
|
||||
|
||||
|
||||
_ng_const = (
|
||||
# 1024-bit
|
||||
('''\
|
||||
EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496\
|
||||
EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8E\
|
||||
F4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA\
|
||||
9AFD5138FE8376435B9FC61D2FC0EB06E3''',
|
||||
'2'),
|
||||
# 2048
|
||||
('''\
|
||||
AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4\
|
||||
A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF60\
|
||||
95179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF\
|
||||
747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B907\
|
||||
8717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB37861\
|
||||
60279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DB\
|
||||
FBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73''',
|
||||
'2'),
|
||||
# 3072
|
||||
('''\
|
||||
FFFFFFFFFFFFFFFFC90FDAA22168C2\
|
||||
34C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E\
|
||||
3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B5\
|
||||
76625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE\
|
||||
9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D3\
|
||||
9A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED5290770\
|
||||
96966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E77\
|
||||
2C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF69558171839\
|
||||
95497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A\
|
||||
33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6\
|
||||
E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA\
|
||||
06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C77\
|
||||
0988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2\
|
||||
CAFFFFFFFFFFFFFFFF''',
|
||||
'5'),
|
||||
# 4096
|
||||
('''\
|
||||
FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08\
|
||||
8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B\
|
||||
302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9\
|
||||
A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6\
|
||||
49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8\
|
||||
FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D\
|
||||
670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C\
|
||||
180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718\
|
||||
3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D\
|
||||
04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D\
|
||||
B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226\
|
||||
1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C\
|
||||
BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC\
|
||||
E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26\
|
||||
99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB\
|
||||
04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2\
|
||||
233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127\
|
||||
D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199\
|
||||
FFFFFFFFFFFFFFFF''',
|
||||
'5'),
|
||||
# 8192
|
||||
('''\
|
||||
FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08\
|
||||
8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B\
|
||||
302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9\
|
||||
A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6\
|
||||
49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8\
|
||||
FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D\
|
||||
670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C\
|
||||
180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718\
|
||||
3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D\
|
||||
04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D\
|
||||
B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226\
|
||||
1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C\
|
||||
BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC\
|
||||
E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26\
|
||||
99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB\
|
||||
04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2\
|
||||
233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127\
|
||||
D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492\
|
||||
36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406\
|
||||
AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918\
|
||||
DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151\
|
||||
2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03\
|
||||
F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F\
|
||||
BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA\
|
||||
CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B\
|
||||
B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632\
|
||||
387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E\
|
||||
6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA\
|
||||
3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C\
|
||||
5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9\
|
||||
22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC886\
|
||||
2F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6\
|
||||
6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC5\
|
||||
0846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268\
|
||||
359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6\
|
||||
FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E71\
|
||||
60C980DD98EDD3DFFFFFFFFFFFFFFFFF''',
|
||||
'0x13')
|
||||
)
|
||||
|
||||
|
||||
def get_ng(ng_type: int) -> Tuple[int, int]:
|
||||
n_hex, g_hex = _ng_const[ng_type]
|
||||
return int(n_hex, 16), int(g_hex, 16)
|
||||
|
||||
|
||||
def get_random(nbytes: int) -> Any:
|
||||
return bytes_to_long(os.urandom(nbytes))
|
||||
|
||||
|
||||
def get_random_of_length(nbytes: int) -> Any:
|
||||
offset = (nbytes * 8) - 1
|
||||
return get_random(nbytes) | (1 << offset)
|
||||
|
||||
|
||||
def H(hash_class: Callable, *args: Any, **kwargs: Any) -> int:
|
||||
width = kwargs.get('width', None)
|
||||
|
||||
h = hash_class()
|
||||
|
||||
for s in args:
|
||||
if s is not None:
|
||||
data = long_to_bytes(s) if isinstance(s, int) else s
|
||||
if width is not None:
|
||||
h.update(bytes(width - len(data)))
|
||||
h.update(data)
|
||||
|
||||
return int(h.hexdigest(), 16)
|
||||
|
||||
|
||||
def H_N_xor_g(hash_class: Callable, N: int, g: int) -> bytes:
|
||||
bin_N = long_to_bytes(N)
|
||||
bin_g = long_to_bytes(g)
|
||||
|
||||
padding = len(bin_N) - len(bin_g)
|
||||
|
||||
hN = hash_class(bin_N).digest()
|
||||
hg = hash_class(b''.join([b'\0' * padding, bin_g])).digest()
|
||||
|
||||
return b''.join(long_to_bytes(hN[i] ^ hg[i]) for i in range(0, len(hN)))
|
||||
|
||||
|
||||
def calculate_x(hash_class: Callable, s: Any, Iu: str, p: str) -> int:
|
||||
_Iu = Iu.encode()
|
||||
_p = p.encode()
|
||||
|
||||
return H(hash_class, s, H(hash_class, _Iu + b':' + _p))
|
||||
|
||||
|
||||
def generate_salt_and_verifier(Iu: str, p: str, len_s: int, hash_alg: int = SHA512, ng_type: int = NG_3072) -> Tuple[bytes, bytes]:
|
||||
hash_class = _hash_map[hash_alg]
|
||||
N, g = get_ng(ng_type)
|
||||
|
||||
_s = long_to_bytes(get_random(len_s))
|
||||
_v = long_to_bytes(pow(g, calculate_x(hash_class, _s, Iu, p), N))
|
||||
|
||||
return _s, _v
|
||||
|
||||
|
||||
def calculate_M(hash_class: Callable, N: int, g: int, Iu: str, s: int, A: int, B: int, K: bytes) -> Any:
|
||||
_Iu = Iu.encode()
|
||||
h = hash_class()
|
||||
h.update(H_N_xor_g(hash_class, N, g))
|
||||
h.update(hash_class(_Iu).digest())
|
||||
h.update(long_to_bytes(s))
|
||||
h.update(long_to_bytes(A))
|
||||
h.update(long_to_bytes(B))
|
||||
h.update(K)
|
||||
return h.digest()
|
||||
|
||||
|
||||
def calculate_H_AMK(hash_class: Callable, A: int, M: bytes, K: bytes) -> Any:
|
||||
h = hash_class()
|
||||
h.update(long_to_bytes(A))
|
||||
h.update(M)
|
||||
h.update(K)
|
||||
return h.digest()
|
||||
|
||||
|
||||
class Srp6a (object):
|
||||
def __init__(self, username: str, password: str, hash_alg: int = SHA512, ng_type: int = NG_3072):
|
||||
hash_class = _hash_map[hash_alg]
|
||||
|
||||
N, g = get_ng(ng_type)
|
||||
k = H(hash_class, N, g, width=len(long_to_bytes(N)))
|
||||
|
||||
self.Iu = username
|
||||
self.p = password
|
||||
|
||||
self.a = get_random_of_length(32)
|
||||
self.A = pow(g, self.a, N)
|
||||
|
||||
self.v: Optional[int] = None
|
||||
self.K: Optional[bytes] = None
|
||||
self.H_AMK = None
|
||||
self._authenticated = False
|
||||
|
||||
self.hash_class = hash_class
|
||||
self.N = N
|
||||
self.g = g
|
||||
self.k = k
|
||||
|
||||
def authenticated(self) -> bool:
|
||||
return self._authenticated
|
||||
|
||||
def get_username(self) -> str:
|
||||
return self.Iu
|
||||
|
||||
def get_ephemeral_secret(self) -> Any:
|
||||
return long_to_bytes(self.a)
|
||||
|
||||
def get_session_key(self) -> Any:
|
||||
return self.K if self._authenticated else None
|
||||
|
||||
def start_authentication(self) -> Tuple[str, bytes]:
|
||||
return (self.Iu, long_to_bytes(self.A))
|
||||
|
||||
# Returns M or None if SRP-6a safety check is violated
|
||||
def process_challenge(self, bytes_s: bytes, bytes_B: bytes) -> Any:
|
||||
s = bytes_to_long(bytes_s)
|
||||
B = bytes_to_long(bytes_B)
|
||||
|
||||
N = self.N
|
||||
g = self.g
|
||||
k = self.k
|
||||
|
||||
hash_class = self.hash_class
|
||||
|
||||
# SRP-6a safety check
|
||||
if (B % N) == 0:
|
||||
return None
|
||||
|
||||
u = H(hash_class, self.A, B, width=len(long_to_bytes(N)))
|
||||
if u == 0: # SRP-6a safety check
|
||||
return None
|
||||
|
||||
x = calculate_x(hash_class, s, self.Iu, self.p)
|
||||
|
||||
v = pow(g, x, N)
|
||||
|
||||
S = pow((B - k * v), (self.a + u * x), N)
|
||||
|
||||
self.K = hash_class(long_to_bytes(S)).digest()
|
||||
|
||||
M = calculate_M(hash_class, N, g, self.Iu, s, self.A, B, self.K)
|
||||
if not M:
|
||||
return None
|
||||
|
||||
self.H_AMK = calculate_H_AMK(hash_class, self.A, M, self.K)
|
||||
|
||||
return M
|
||||
|
||||
def verify_session(self, host_HAMK: bytes) -> None:
|
||||
if self.H_AMK == host_HAMK:
|
||||
self._authenticated = True
|
||||
|
||||
|
||||
class AuthenticationFailed (Exception):
|
||||
pass
|
||||
@@ -0,0 +1,7 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
from .transport_ble import * # noqa: F403, F401
|
||||
from .transport_console import * # noqa: F403, F401
|
||||
from .transport_http import * # noqa: F403, F401
|
||||
@@ -0,0 +1,213 @@
|
||||
# SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
import platform
|
||||
|
||||
from utils import hex_str_to_bytes, str_to_bytes
|
||||
|
||||
fallback = True
|
||||
|
||||
|
||||
# Check if required packages are installed
|
||||
# else fallback to console mode
|
||||
try:
|
||||
import bleak
|
||||
fallback = False
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
def device_sort(device):
|
||||
return device[0].address
|
||||
|
||||
|
||||
class BLE_Bleak_Client:
|
||||
def __init__(self):
|
||||
self.adapter = None
|
||||
self.adapter_props = None
|
||||
self.characteristics = dict()
|
||||
self.chrc_names = None
|
||||
self.device = None
|
||||
self.devname = None
|
||||
self.iface = None
|
||||
self.nu_lookup = None
|
||||
self.services = None
|
||||
self.srv_uuid_adv = None
|
||||
self.srv_uuid_fallback = None
|
||||
|
||||
async def connect(self, devname, iface, chrc_names, fallback_srv_uuid):
|
||||
self.devname = devname
|
||||
self.srv_uuid_fallback = fallback_srv_uuid
|
||||
self.chrc_names = [name.lower() for name in chrc_names]
|
||||
self.iface = iface
|
||||
|
||||
print('Discovering...')
|
||||
try:
|
||||
discovery = await bleak.BleakScanner.discover(return_adv=True, adapter=self.iface)
|
||||
devices = list(discovery.values())
|
||||
except bleak.exc.BleakDBusError as e:
|
||||
if str(e) == '[org.bluez.Error.NotReady] Resource Not Ready':
|
||||
raise RuntimeError('Bluetooth is not ready. Maybe try `bluetoothctl power on`?')
|
||||
raise
|
||||
|
||||
found_device = None
|
||||
|
||||
if self.devname is None:
|
||||
if len(devices) == 0:
|
||||
print('No devices found!')
|
||||
exit(1)
|
||||
|
||||
while True:
|
||||
devices.sort(key=device_sort)
|
||||
print('==== BLE Discovery results ====')
|
||||
print('{0: >4} {1: <33} {2: <12}'.format(
|
||||
'S.N.', 'Name', 'Address'))
|
||||
for i, _ in enumerate(devices):
|
||||
print('[{0: >2}] {1: <33} {2: <12}'.format(i + 1, devices[i][0].name or 'Unknown', devices[i][0].address))
|
||||
|
||||
while True:
|
||||
try:
|
||||
select = int(input('Select device by number (0 to rescan) : '))
|
||||
if select < 0 or select > len(devices):
|
||||
raise ValueError
|
||||
break
|
||||
except ValueError:
|
||||
print('Invalid input! Retry')
|
||||
|
||||
if select != 0:
|
||||
break
|
||||
|
||||
discovery = await bleak.BleakScanner.discover(return_adv=True, adapter=self.iface)
|
||||
devices = list(discovery.values())
|
||||
|
||||
self.devname = devices[select - 1][0].name
|
||||
found_device = devices[select - 1]
|
||||
else:
|
||||
for d in devices:
|
||||
if d[0].name == self.devname:
|
||||
found_device = d
|
||||
|
||||
if not found_device:
|
||||
raise RuntimeError('Device not found')
|
||||
|
||||
uuids = found_device[1].service_uuids
|
||||
# There should be 1 service UUID in advertising data
|
||||
# If bluez had cached an old version of the advertisement data
|
||||
# the list of uuids may be incorrect, in which case connection
|
||||
# or service discovery may fail the first time. If that happens
|
||||
# the cache will be refreshed before next retry
|
||||
if len(uuids) == 1:
|
||||
self.srv_uuid_adv = uuids[0]
|
||||
|
||||
print('Connecting...')
|
||||
self.device = bleak.BleakClient(found_device[0].address, adapter=self.iface)
|
||||
await self.device.connect()
|
||||
# must be paired on Windows to access characteristics;
|
||||
# cannot be paired on Mac
|
||||
if platform.system() == 'Windows':
|
||||
await self.device.pair()
|
||||
|
||||
print('Getting Services...')
|
||||
services = self.device.services
|
||||
|
||||
service = services[self.srv_uuid_adv] or services[self.srv_uuid_fallback]
|
||||
if not service:
|
||||
await self.device.disconnect()
|
||||
self.device = None
|
||||
raise RuntimeError('Provisioning service not found')
|
||||
|
||||
nu_lookup = dict()
|
||||
for characteristic in service.characteristics:
|
||||
for descriptor in characteristic.descriptors:
|
||||
if descriptor.uuid[4:8] != '2901':
|
||||
continue
|
||||
readval = await self.device.read_gatt_descriptor(descriptor.handle)
|
||||
found_name = ''.join(chr(b) for b in readval).lower()
|
||||
nu_lookup[found_name] = characteristic.uuid
|
||||
self.characteristics[characteristic.uuid] = characteristic
|
||||
|
||||
match_found = True
|
||||
for name in self.chrc_names:
|
||||
if name not in nu_lookup:
|
||||
# Endpoint name not present
|
||||
match_found = False
|
||||
break
|
||||
|
||||
# Create lookup table only if all endpoint names found
|
||||
self.nu_lookup = [None, nu_lookup][match_found]
|
||||
|
||||
return True
|
||||
|
||||
def get_nu_lookup(self):
|
||||
return self.nu_lookup
|
||||
|
||||
def has_characteristic(self, uuid):
|
||||
print('checking for characteristic ' + uuid)
|
||||
if uuid in self.characteristics:
|
||||
return True
|
||||
return False
|
||||
|
||||
async def disconnect(self):
|
||||
if self.device:
|
||||
print('Disconnecting...')
|
||||
if platform.system() == 'Windows':
|
||||
await self.device.unpair()
|
||||
await self.device.disconnect()
|
||||
self.device = None
|
||||
self.nu_lookup = None
|
||||
self.characteristics = dict()
|
||||
|
||||
async def send_data(self, characteristic_uuid, data):
|
||||
await self.device.write_gatt_char(characteristic_uuid, bytearray(data.encode('latin-1')), True)
|
||||
readval = await self.device.read_gatt_char(characteristic_uuid)
|
||||
return ''.join(chr(b) for b in readval)
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
|
||||
# Console based BLE client for Cross Platform support
|
||||
class BLE_Console_Client:
|
||||
async def connect(self, devname, iface, chrc_names, fallback_srv_uuid):
|
||||
print('BLE client is running in console mode')
|
||||
print('\tThis could be due to your platform not being supported or dependencies not being met')
|
||||
print('\tPlease ensure all pre-requisites are met to run the full fledged client')
|
||||
print('BLECLI >> Please connect to BLE device `' + devname + '` manually using your tool of choice')
|
||||
resp = input('BLECLI >> Was the device connected successfully? [y/n] ')
|
||||
if resp != 'Y' and resp != 'y':
|
||||
return False
|
||||
print('BLECLI >> List available attributes of the connected device')
|
||||
resp = input("BLECLI >> Is the service UUID '" + fallback_srv_uuid + "' listed among available attributes? [y/n] ")
|
||||
if resp != 'Y' and resp != 'y':
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_nu_lookup(self):
|
||||
return None
|
||||
|
||||
def has_characteristic(self, uuid):
|
||||
resp = input("BLECLI >> Is the characteristic UUID '" + uuid + "' listed among available attributes? [y/n] ")
|
||||
if resp != 'Y' and resp != 'y':
|
||||
return False
|
||||
return True
|
||||
|
||||
async def disconnect(self):
|
||||
pass
|
||||
|
||||
async def send_data(self, characteristic_uuid, data):
|
||||
print("BLECLI >> Write following data to characteristic with UUID '" + characteristic_uuid + "' :")
|
||||
print('\t>> ' + str_to_bytes(data).hex())
|
||||
print('BLECLI >> Enter data read from characteristic (in hex) :')
|
||||
resp = input('\t<< ')
|
||||
return hex_str_to_bytes(resp)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
|
||||
# Function to get client instance depending upon platform
|
||||
def get_client():
|
||||
if fallback:
|
||||
return BLE_Console_Client()
|
||||
return BLE_Bleak_Client()
|
||||
@@ -0,0 +1,21 @@
|
||||
# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# Base class for protocomm transport
|
||||
|
||||
import abc
|
||||
|
||||
|
||||
class Transport():
|
||||
|
||||
@abc.abstractmethod
|
||||
def send_session_data(self, data):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def send_config_data(self, data):
|
||||
pass
|
||||
|
||||
async def disconnect(self):
|
||||
pass
|
||||
@@ -0,0 +1,53 @@
|
||||
# SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
from . import ble_cli
|
||||
from .transport import Transport
|
||||
|
||||
DEFAULT_BLE_ADAPTER = 'hci0'
|
||||
|
||||
|
||||
class Transport_BLE(Transport):
|
||||
def __init__(self, service_uuid, nu_lookup, ble_adapter=DEFAULT_BLE_ADAPTER):
|
||||
self.nu_lookup = nu_lookup
|
||||
self.service_uuid = service_uuid
|
||||
self.name_uuid_lookup = None
|
||||
self.ble_adapter = ble_adapter
|
||||
# Expect service UUID like '0000ffff-0000-1000-8000-00805f9b34fb'
|
||||
for name in nu_lookup.keys():
|
||||
# Calculate characteristic UUID for each endpoint
|
||||
nu_lookup[name] = service_uuid[:4] + '{:02x}'.format(
|
||||
int(nu_lookup[name], 16) & int(service_uuid[4:8], 16)) + service_uuid[8:]
|
||||
|
||||
# Get BLE client module
|
||||
self.cli = ble_cli.get_client()
|
||||
|
||||
async def connect(self, devname):
|
||||
# Use client to connect to BLE device and bind to service
|
||||
if not await self.cli.connect(devname=devname, iface=self.ble_adapter,
|
||||
chrc_names=self.nu_lookup.keys(),
|
||||
fallback_srv_uuid=self.service_uuid):
|
||||
raise RuntimeError('Failed to initialize transport')
|
||||
|
||||
# Irrespective of provided parameters, let the client
|
||||
# generate a lookup table by reading advertisement data
|
||||
# and characteristic user descriptors
|
||||
self.name_uuid_lookup = self.cli.get_nu_lookup()
|
||||
|
||||
# If that doesn't work, use the lookup table provided as parameter
|
||||
if self.name_uuid_lookup is None:
|
||||
self.name_uuid_lookup = self.nu_lookup
|
||||
# Check if expected characteristics are provided by the service
|
||||
for name in self.name_uuid_lookup.keys():
|
||||
if not self.cli.has_characteristic(self.name_uuid_lookup[name]):
|
||||
raise RuntimeError(f"'{name}' endpoint not found")
|
||||
|
||||
async def disconnect(self):
|
||||
await self.cli.disconnect()
|
||||
|
||||
async def send_data(self, ep_name, data):
|
||||
# Write (and read) data to characteristic corresponding to the endpoint
|
||||
if ep_name not in self.name_uuid_lookup.keys():
|
||||
raise RuntimeError(f'Invalid endpoint: {ep_name}')
|
||||
return await self.cli.send_data(self.name_uuid_lookup[ep_name], data)
|
||||
@@ -0,0 +1,19 @@
|
||||
# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
from utils import hex_str_to_bytes, str_to_bytes
|
||||
|
||||
from .transport import Transport
|
||||
|
||||
|
||||
class Transport_Console(Transport):
|
||||
|
||||
async def send_data(self, path, data, session_id=0):
|
||||
print('Client->Device msg :', path, session_id, str_to_bytes(data).hex())
|
||||
try:
|
||||
resp = input('Enter device->client msg : ')
|
||||
except Exception as err:
|
||||
print('error:', err)
|
||||
return None
|
||||
return hex_str_to_bytes(resp)
|
||||
@@ -0,0 +1,49 @@
|
||||
# SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
import socket
|
||||
from http.client import HTTPConnection, HTTPSConnection
|
||||
|
||||
from utils import str_to_bytes
|
||||
|
||||
from .transport import Transport
|
||||
|
||||
|
||||
class Transport_HTTP(Transport):
|
||||
def __init__(self, hostname, ssl_context=None):
|
||||
try:
|
||||
socket.gethostbyname(hostname.split(':')[0])
|
||||
except socket.gaierror:
|
||||
raise RuntimeError(f'Unable to resolve hostname: {hostname}')
|
||||
|
||||
if ssl_context is None:
|
||||
self.conn = HTTPConnection(hostname, timeout=60)
|
||||
else:
|
||||
self.conn = HTTPSConnection(hostname, context=ssl_context, timeout=60)
|
||||
try:
|
||||
print(f'++++ Connecting to {hostname}++++')
|
||||
self.conn.connect()
|
||||
except Exception as err:
|
||||
raise RuntimeError('Connection Failure : ' + str(err))
|
||||
self.headers = {'Content-type': 'application/x-www-form-urlencoded','Accept': 'text/plain'}
|
||||
|
||||
def _send_post_request(self, path, data):
|
||||
data = str_to_bytes(data) if isinstance(data, str) else data
|
||||
try:
|
||||
self.conn.request('POST', path, data, self.headers)
|
||||
response = self.conn.getresponse()
|
||||
# While establishing a session, the device sends the Set-Cookie header
|
||||
# with value 'session=cookie_session_id' in its first response of the session to the tool.
|
||||
# To maintain the same session, successive requests from the tool should include
|
||||
# an additional 'Cookie' header with the above received value.
|
||||
for hdr_key, hdr_val in response.getheaders():
|
||||
if hdr_key == 'Set-Cookie':
|
||||
self.headers['Cookie'] = hdr_val
|
||||
if response.status == 200:
|
||||
return response.read().decode('latin-1')
|
||||
except Exception as err:
|
||||
raise RuntimeError('Connection Failure : ' + str(err))
|
||||
raise RuntimeError('Server responded with error code ' + str(response.status))
|
||||
|
||||
async def send_data(self, ep_name, data):
|
||||
return self._send_post_request('/' + ep_name, data)
|
||||
@@ -0,0 +1,5 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
from .convenience import * # noqa: F403, F401
|
||||
@@ -0,0 +1,31 @@
|
||||
# SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# Convenience functions for commonly used data type conversions
|
||||
|
||||
def bytes_to_long(s: bytes) -> int:
|
||||
return int.from_bytes(s, 'big')
|
||||
|
||||
|
||||
def long_to_bytes(n: int) -> bytes:
|
||||
if n == 0:
|
||||
return b'\x00'
|
||||
return n.to_bytes((n.bit_length() + 7) // 8, 'big')
|
||||
|
||||
|
||||
# 'deadbeef' -> b'deadbeef'
|
||||
def str_to_bytes(s: str) -> bytes:
|
||||
return bytes(s, encoding='latin-1')
|
||||
|
||||
|
||||
# 'deadbeef' -> b'\xde\xad\xbe\xef'
|
||||
def hex_str_to_bytes(s: str) -> bytes:
|
||||
return bytes.fromhex(s)
|
||||
|
||||
|
||||
def int_to_hex_str(n: int) -> str:
|
||||
hex_string = format(n, 'x')
|
||||
if len(hex_string) % 2 != 0:
|
||||
hex_string = '0' + hex_string
|
||||
return hex_string
|
||||
+5
-8
@@ -20,7 +20,7 @@ dependencies:
|
||||
require: private
|
||||
version: '>=5.0'
|
||||
source:
|
||||
registry_url: https://components.espressif.com
|
||||
registry_url: https://components.espressif.com/
|
||||
type: service
|
||||
version: 1.7.19~2
|
||||
espressif/cmake_utilities:
|
||||
@@ -229,20 +229,16 @@ dependencies:
|
||||
type: service
|
||||
version: 1.6.58
|
||||
espressif/network_provisioning:
|
||||
component_hash: 72d27784e3daf807418a34fb00be136ec50c6db49d989ce981d22e031fc0e7f8
|
||||
dependencies:
|
||||
- name: espressif/cjson
|
||||
registry_url: https://components.espressif.com
|
||||
require: private
|
||||
rules:
|
||||
- if: idf_version >= 6.0
|
||||
version: ^1.7.19
|
||||
- name: idf
|
||||
require: private
|
||||
version: '>=5.1'
|
||||
source:
|
||||
registry_url: https://components.espressif.com/
|
||||
type: service
|
||||
path: components/network_provisioning
|
||||
type: local
|
||||
version: 1.2.4
|
||||
espressif/zlib:
|
||||
component_hash: 64ea2fd6754c5a05951f1ddb312ac835cd782e68cb5bd9dfcd1c3a107c8fbfbc
|
||||
@@ -300,6 +296,7 @@ dependencies:
|
||||
type: service
|
||||
version: 1.0.1
|
||||
direct_dependencies:
|
||||
- espressif/cjson
|
||||
- espressif/esp_codec_dev
|
||||
- espressif/esp_lcd_sh8601
|
||||
- espressif/esp_lvgl_adapter
|
||||
@@ -309,6 +306,6 @@ direct_dependencies:
|
||||
- waveshare/esp_lcd_touch_cst9217
|
||||
- waveshare/pcf85063a
|
||||
- waveshare/qmi8658
|
||||
manifest_hash: 674b865190c20edea7d5cd705b9cf52cb0fdc7084c5249c466fb87ad5be9409e
|
||||
manifest_hash: d7f80c63188d128ef11ea954c98cf33d0ce1eeeb230509bb1d96b2729a01ca42
|
||||
target: esp32c6
|
||||
version: 3.0.0
|
||||
|
||||
@@ -12,4 +12,6 @@ dependencies:
|
||||
waveshare/pcf85063a: ^1.1.1
|
||||
waveshare/qmi8658: ^1.0.1
|
||||
espressif/esp_lvgl_adapter: ^0.3.0
|
||||
espressif/network_provisioning: "*"
|
||||
espressif/network_provisioning:
|
||||
version: "*"
|
||||
override_path: ../components/network_provisioning
|
||||
|
||||
@@ -221,7 +221,9 @@ static void desktop_temperature_task(void *arg)
|
||||
LV_UNUSED(arg);
|
||||
|
||||
while(1) {
|
||||
(void)desktop_fetch_temperature_history();
|
||||
if(!WifiProvisioning_IsProvisioning()) {
|
||||
(void)desktop_fetch_temperature_history();
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(TEMP_FETCH_INTERVAL_MS));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ static bool wifi_mgr_initialized = false;
|
||||
static bool wifi_is_provisioning = false;
|
||||
static bool wifi_sntp_initialized = false;
|
||||
static bool wifi_is_connected = false;
|
||||
static bool wifi_ps_overridden_for_prov = false;
|
||||
static char prov_service_name[20] = {0};
|
||||
static char prov_qr_payload[200] = {0};
|
||||
static const char *SINGAPORE_TZ = "SGT-8";
|
||||
@@ -132,9 +133,15 @@ static void get_device_service_name(char *service_name, size_t max_len)
|
||||
|
||||
static void wifi_prov_print_url(const char *name, const char *username, const char *pop)
|
||||
{
|
||||
snprintf(prov_qr_payload, sizeof(prov_qr_payload),
|
||||
"{\"ver\":\"%s\",\"name\":\"%s\",\"username\":\"%s\",\"pop\":\"%s\",\"transport\":\"%s\"}",
|
||||
PROV_QR_VERSION, name, username, pop, PROV_TRANSPORT_SOFTAP);
|
||||
if(username != NULL && username[0] != '\0') {
|
||||
snprintf(prov_qr_payload, sizeof(prov_qr_payload),
|
||||
"{\"ver\":\"%s\",\"name\":\"%s\",\"username\":\"%s\",\"pop\":\"%s\",\"transport\":\"%s\",\"network\":\"wifi\"}",
|
||||
PROV_QR_VERSION, name, username, pop, PROV_TRANSPORT_SOFTAP);
|
||||
} else {
|
||||
snprintf(prov_qr_payload, sizeof(prov_qr_payload),
|
||||
"{\"ver\":\"%s\",\"name\":\"%s\",\"pop\":\"%s\",\"transport\":\"%s\",\"network\":\"wifi\"}",
|
||||
PROV_QR_VERSION, name, pop, PROV_TRANSPORT_SOFTAP);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Provisioning URL:\n%s?data=%s", QRCODE_BASE_URL, prov_qr_payload);
|
||||
}
|
||||
@@ -161,33 +168,40 @@ static esp_err_t wifi_prov_manager_init_if_needed(void)
|
||||
static esp_err_t wifi_start_softap_provisioning(void)
|
||||
{
|
||||
char service_name[16] = {0};
|
||||
const char *username = "wifiprov";
|
||||
const char *username = NULL;
|
||||
const char *pop = "abcd1234";
|
||||
const char *service_key = "prov1234";
|
||||
network_prov_security2_params_t sec2_params = {};
|
||||
const char *service_key = NULL;
|
||||
|
||||
get_device_service_name(service_name, sizeof(service_name));
|
||||
strncpy(prov_service_name, service_name, sizeof(prov_service_name) - 1);
|
||||
prov_service_name[sizeof(prov_service_name) - 1] = '\0';
|
||||
|
||||
sec2_params.salt = sec2_salt;
|
||||
sec2_params.salt_len = sizeof(sec2_salt);
|
||||
sec2_params.verifier = sec2_verifier;
|
||||
sec2_params.verifier_len = sizeof(sec2_verifier);
|
||||
/* Block normal STA reconnect flow while SoftAP provisioning is active. */
|
||||
wifi_is_provisioning = true;
|
||||
wifi_is_connected = false;
|
||||
xEventGroupClearBits(wifi_event_group, WIFI_CONNECTED_EVENT);
|
||||
|
||||
ESP_LOGI(TAG, "Starting SoftAP provisioning (service name: %s)", service_name);
|
||||
esp_err_t ret = network_prov_mgr_start_provisioning(NETWORK_PROV_SECURITY_2,
|
||||
(const void *)&sec2_params,
|
||||
if(!wifi_ps_overridden_for_prov) {
|
||||
esp_err_t ps_ret = esp_wifi_set_ps(WIFI_PS_NONE);
|
||||
if(ps_ret == ESP_OK) {
|
||||
wifi_ps_overridden_for_prov = true;
|
||||
ESP_LOGI(TAG, "Disabled Wi-Fi power save during provisioning");
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Failed to disable Wi-Fi power save during provisioning (error: %d)", ps_ret);
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Starting SoftAP provisioning (service name: %s, auth: open + sec1)", service_name);
|
||||
esp_err_t ret = network_prov_mgr_start_provisioning(NETWORK_PROV_SECURITY_1,
|
||||
(const void *)pop,
|
||||
service_name,
|
||||
service_key);
|
||||
if(ret != ESP_OK) {
|
||||
wifi_is_provisioning = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
wifi_prov_print_url(service_name, username, pop);
|
||||
wifi_is_provisioning = true;
|
||||
wifi_is_connected = false;
|
||||
xEventGroupClearBits(wifi_event_group, WIFI_CONNECTED_EVENT);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -214,6 +228,13 @@ static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_
|
||||
ESP_ERROR_CHECK(network_prov_mgr_deinit());
|
||||
wifi_mgr_initialized = false;
|
||||
wifi_is_provisioning = false;
|
||||
if(wifi_ps_overridden_for_prov) {
|
||||
esp_err_t ps_ret = esp_wifi_set_ps(WIFI_PS_MIN_MODEM);
|
||||
if(ps_ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Failed to restore Wi-Fi power save after provisioning (error: %d)", ps_ret);
|
||||
}
|
||||
wifi_ps_overridden_for_prov = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -221,13 +242,19 @@ static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_
|
||||
} else if(event_base == WIFI_EVENT) {
|
||||
switch(event_id) {
|
||||
case WIFI_EVENT_STA_START:
|
||||
esp_wifi_connect();
|
||||
if(!wifi_is_provisioning) {
|
||||
esp_wifi_connect();
|
||||
}
|
||||
break;
|
||||
case WIFI_EVENT_STA_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "Wi-Fi disconnected, retrying...");
|
||||
wifi_is_connected = false;
|
||||
xEventGroupClearBits(wifi_event_group, WIFI_CONNECTED_EVENT);
|
||||
esp_wifi_connect();
|
||||
if(wifi_is_provisioning) {
|
||||
ESP_LOGI(TAG, "Wi-Fi STA disconnected during provisioning; reconnect suppressed");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Wi-Fi disconnected, retrying...");
|
||||
esp_wifi_connect();
|
||||
}
|
||||
break;
|
||||
case WIFI_EVENT_AP_STACONNECTED:
|
||||
ESP_LOGI(TAG, "Provisioning SoftAP client connected");
|
||||
@@ -235,6 +262,15 @@ static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_
|
||||
case WIFI_EVENT_AP_STADISCONNECTED:
|
||||
ESP_LOGI(TAG, "Provisioning SoftAP client disconnected");
|
||||
break;
|
||||
case WIFI_EVENT_SCAN_DONE: {
|
||||
const wifi_event_sta_scan_done_t *scan = (const wifi_event_sta_scan_done_t *)event_data;
|
||||
if(scan != NULL) {
|
||||
ESP_LOGI(TAG, "Provisioning scan done (status: %u, ap_num: %u)",
|
||||
(unsigned int)scan->status,
|
||||
(unsigned int)scan->number);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user