Merge branch 'feature/prov_mgr_backport_v3.3' into 'release/v3.3'

Wi-Fi Provisioning Manager (backport v3.3)

See merge request idf/esp-idf!5371
This commit is contained in:
Mahavir Jain 2019-07-02 16:17:23 +08:00
commit e443467f37
36 changed files with 6530 additions and 78 deletions

View file

@ -156,6 +156,7 @@ exclude =
components/protocomm/python/sec0_pb2.py,
components/protocomm/python/sec1_pb2.py,
components/protocomm/python/session_pb2.py,
components/wifi_provisioning/python/wifi_scan_pb2.py,
components/wifi_provisioning/python/wifi_config_pb2.py,
components/wifi_provisioning/python/wifi_constants_pb2.py,
examples/provisioning/custom_config/components/custom_provisioning/python/custom_config_pb2.py,

View file

@ -1,10 +1,23 @@
set(COMPONENT_ADD_INCLUDEDIRS include)
set(COMPONENT_PRIV_INCLUDEDIRS proto-c ../protocomm/proto-c)
set(COMPONENT_PRIV_INCLUDEDIRS src proto-c ../protocomm/proto-c)
set(COMPONENT_SRCS "src/wifi_config.c"
"src/wifi_scan.c"
"src/manager.c"
"src/handlers.c"
"src/scheme_softap.c"
"src/scheme_console.c"
"proto-c/wifi_config.pb-c.c"
"proto-c/wifi_scan.pb-c.c"
"proto-c/wifi_constants.pb-c.c")
set(COMPONENT_REQUIRES lwip)
set(COMPONENT_PRIV_REQUIRES protobuf-c protocomm)
set(COMPONENT_REQUIRES lwip protocomm)
set(COMPONENT_PRIV_REQUIRES protobuf-c bt mdns json)
if(CONFIG_BT_ENABLED)
if(CONFIG_BLUEDROID_ENABLED)
list(APPEND COMPONENT_SRCS
"src/scheme_ble.c")
endif()
endif()
register_component()

View file

@ -0,0 +1,10 @@
menu "Wi-Fi Provisioning Manager"
config WIFI_PROV_SCAN_MAX_ENTRIES
int "Max Wi-Fi Scan Result Entries"
default 16
range 1 255
help
This sets the maximum number of entries of Wi-Fi scan results that will be kept by the provisioning manager
endmenu

View file

@ -1,3 +1,7 @@
COMPONENT_SRCDIRS := src proto-c
COMPONENT_ADD_INCLUDEDIRS := include
COMPONENT_PRIV_INCLUDEDIRS := proto-c ../protocomm/proto-c/
COMPONENT_PRIV_INCLUDEDIRS := src proto-c ../protocomm/proto-c/
ifneq ($(filter y, $(CONFIG_BT_ENABLED) $(CONFIG_BLUEDROID_ENABLED)),y y)
COMPONENT_OBJEXCLUDE := src/scheme_ble.o
endif

View file

@ -0,0 +1,553 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <esp_event_loop.h>
#include <protocomm.h>
#include "wifi_provisioning/wifi_config.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @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
*/
WIFI_PROV_INIT,
/**
* Indicates that provisioning has started
*/
WIFI_PROV_START,
/**
* Emitted when Wi-Fi AP credentials are received via `protocomm`
* endpoint `wifi_config`. The event data in this case is a pointer
* to the corresponding `wifi_sta_config_t` structure
*/
WIFI_PROV_CRED_RECV,
/**
* Emitted when device fails to connect to the AP of which the
* credentials were received earlier on event `WIFI_PROV_CRED_RECV`.
* The event data in this case is a pointer to the disconnection
* reason code with type `wifi_prov_sta_fail_reason_t`
*/
WIFI_PROV_CRED_FAIL,
/**
* Emitted when device successfully connects to the AP of which the
* credentials were received earlier on event `WIFI_PROV_CRED_RECV`
*/
WIFI_PROV_CRED_SUCCESS,
/**
* Signals that provisioning service has stopped
*/
WIFI_PROV_END,
/**
* Signals that manager has been de-initialized
*/
WIFI_PROV_DEINIT,
} wifi_prov_cb_event_t;
typedef void (*wifi_prov_cb_func_t)(void *user_data, wifi_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
*/
wifi_prov_cb_func_t event_cb;
/**
* User context data to pass as parameter to callback function
*/
void *user_data;
} wifi_prov_event_handler_t;
/**
* @brief Event handler can be set to none if not used
*/
#define WIFI_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:
* - wifi_prov_scheme_ble : for provisioning over BLE transport + GATT server
* - wifi_prov_scheme_softap : for provisioning over SoftAP transport + HTTP server
* - wifi_prov_scheme_console : for provisioning over Serial UART transport + Console (for debugging)
*/
typedef struct wifi_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);
/**
* 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;
} wifi_prov_scheme_t;
/**
* @brief Structure for specifying the manager configuration
*/
typedef struct {
/**
* Provisioning scheme to use. Following schemes are already available:
* - wifi_prov_scheme_ble : for provisioning over BLE transport + GATT server
* - wifi_prov_scheme_softap : for provisioning over SoftAP transport + HTTP server + mDNS (optional)
* - wifi_prov_scheme_console : for provisioning over Serial UART transport + Console (for debugging)
*/
wifi_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 WIFI_PROV_EVENT_HANDLER_NONE
* when not used. When using scheme wifi_prov_scheme_ble, the following
* options are available:
* - WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM
* - WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BLE
* - WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BT
*/
wifi_prov_event_handler_t scheme_event_handler;
/**
* Event handler that can be set for the purpose of incorporating application
* specific behavior. Use WIFI_PROV_EVENT_HANDLER_NONE when not used.
*/
wifi_prov_event_handler_t app_event_handler;
} wifi_prov_mgr_config_t;
/**
* @brief Security modes supported by the Provisioning Manager.
*
* These are same as the security modes provided by protocomm
*/
typedef enum wifi_prov_security {
/**
* No security (plain-text communication)
*/
WIFI_PROV_SECURITY_0 = 0,
/**
* This secure communication mode consists of
* X25519 key exchange
* + proof of possession (pop) based authentication
* + AES-CTR encryption
*/
WIFI_PROV_SECURITY_1
} wifi_prov_security_t;
/**
* @brief Initialize provisioning manager instance
*
* Configures the manager and allocates internal resources
*
* Configuration specifies the provisioning scheme (transport)
* and event handlers
*
* Event WIFI_PROV_INIT is emitted right after initialization
* is complete
*
* @param[in] config Configuration structure
*
* @return
* - ESP_OK : Success
* - ESP_FAIL : Fail
*/
esp_err_t wifi_prov_mgr_init(wifi_prov_mgr_config_t config);
/**
* @brief Stop provisioning (if running) and release
* resource used by the manager
*
* Event WIFI_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 WIFI_PROV_END, and
* then performs the de-initialization
*/
void wifi_prov_mgr_deinit(void);
/**
* @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 wifi_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_INVALID_STATE : Manager not initialized
*/
esp_err_t wifi_prov_mgr_is_provisioned(bool *provisioned);
/**
* @brief Start provisioning service
*
* This starts the provisioning service according to the scheme
* configured at the time of initialization. For scheme :
* - wifi_prov_scheme_ble : This starts protocomm_ble, which internally initializes
* BLE transport and starts GATT server for handling
* provisioning requests
* - wifi_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 WIFI_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. wifi_prov_mgr_is_provisioned() yields true
*
* @param[in] security Specify which protocomm security scheme to use :
* - WIFI_PROV_SECURITY_0 : For no security
* - WIFI_PROV_SECURITY_1 : x25519 secure handshake for session
* establishment followed by AES-CTR encryption of provisioning messages
* @param[in] pop Pointer to proof of possession string (NULL if not needed). This
* is relevant only for protocomm security 1, in which case it is used
* for authenticating secure session
* @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 wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const char *pop,
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 WIFI_PROV_END
* will be emitted.
*
* If wifi_prov_mgr_deinit() is called without calling this API first, it will
* automatically stop the provisioning service and emit the WIFI_PROV_END, followed
* by WIFI_PROV_DEINIT, before returning.
*
* This API will generally be used along with wifi_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 wifi_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 WIFI_PROV_CRED_SUCCESS is emitted.
* Stopping is delayed (maximum 30 seconds) thus allowing the client side
* application to query for Wi-Fi state, i.e. after receiving the first query
* and sending `Wi-Fi state connected` response the service is stopped immediately.
*/
void wifi_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 WIFI_PROV_END is emitted.
*
* This will not block if provisioning is not started or not initialized.
*/
void wifi_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 Wi-Fi, 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 wifi_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 wifi_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 wifi_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 wifi_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 wifi_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 wifi_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
* wifi_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, 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 configuration,
* because once Wi-Fi 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 wifi_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 wifi_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, 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 configuration,
* because once Wi-Fi 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 wifi_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 wifi_prov_mgr_endpoint_unregister(const char *ep_name);
/**
* @brief Event handler for provisioning manager
*
* This is called from the main event handler and controls the
* provisioning manager's internal state machine depending on
* incoming Wi-Fi events
*
* @param[in] ctx Event context data
* @param[in] event Event info
*
* @return
* - ESP_OK : Event handled successfully
* - ESP_ERR_FAIL : This event cannot be handled
*/
esp_err_t wifi_prov_mgr_event_handler(void *ctx, system_event_t *event);
/**
* @brief Get state of Wi-Fi Station during provisioning
*
* @param[out] state Pointer to wifi_prov_sta_state_t
* variable to be filled
*
* @return
* - ESP_OK : Successfully retrieved Wi-Fi state
* - ESP_FAIL : Provisioning app not running
*/
esp_err_t wifi_prov_mgr_get_wifi_state(wifi_prov_sta_state_t *state);
/**
* @brief Get reason code in case of Wi-Fi station
* disconnection during provisioning
*
* @param[out] reason Pointer to wifi_prov_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 wifi_prov_mgr_get_wifi_disconnect_reason(wifi_prov_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 WIFI_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 wifi_prov_mgr_configure_sta(wifi_config_t *wifi_cfg);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,82 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <protocomm.h>
#include <protocomm_ble.h>
#include "wifi_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 wifi_prov_scheme_t wifi_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 WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM { \
.event_cb = wifi_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 WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BLE { \
.event_cb = wifi_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 WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BT { \
.event_cb = wifi_prov_scheme_ble_event_cb_free_bt, \
.user_data = NULL \
}
void wifi_prov_scheme_ble_event_cb_free_btdm(void *user_data, wifi_prov_cb_event_t event, void *event_data);
void wifi_prov_scheme_ble_event_cb_free_ble (void *user_data, wifi_prov_cb_event_t event, void *event_data);
void wifi_prov_scheme_ble_event_cb_free_bt (void *user_data, wifi_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 wifi_prov_mgr_start_provisioning(), otherwise
* the default UUID will be used.
*
* @note The data being pointed to by the argument must be valid
* atleast till provisioning is started. Upon start, the
* manager will store an internal copy of this UUID, and
* this data can be freed or invalidated afterwords.
*
* @param[in] uuid128 A custom 128 bit UUID
*
* @return
* - ESP_OK : Success
* - ESP_ERR_INVALID_ARG : Null argument
*/
esp_err_t wifi_prov_scheme_ble_set_service_uuid(uint8_t *uuid128);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,34 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <protocomm.h>
#include <protocomm_console.h>
#include "wifi_provisioning/manager.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Scheme that can be used by manager for provisioning
* over console (Serial UART)
*/
extern const wifi_prov_scheme_t wifi_prov_scheme_console;
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,34 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <protocomm.h>
#include <protocomm_httpd.h>
#include "wifi_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 wifi_prov_scheme_t wifi_prov_scheme_softap;
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,166 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _PROV_WIFI_SCAN_H_
#define _PROV_WIFI_SCAN_H_
#ifdef __cplusplus
extern "C" {
#endif
#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)
/**
* @brief Type of context data passed to each get/set/apply handler
* function set in `wifi_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 wifi_prov_scan_ctx wifi_prov_scan_ctx_t;
/**
* @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;
} wifi_prov_scan_result_t;
/**
* @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 `wifi_prov_scan_handler()`) when calling `protocomm_add_endpoint()`.
*/
typedef struct wifi_prov_scan_handlers {
/**
* 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 atleast
* 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 (*scan_start)(bool blocking, bool passive,
uint8_t group_channels, uint32_t period_ms,
wifi_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 (*scan_status)(bool *scan_finished,
uint16_t *result_count,
wifi_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 (*scan_result)(uint16_t result_index,
wifi_prov_scan_result_t *result,
wifi_prov_scan_ctx_t **ctx);
/**
* Context pointer to be passed to above handler functions upon invocation
*/
wifi_prov_scan_ctx_t *ctx;
} wifi_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 wifi_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

View file

@ -0,0 +1,878 @@
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
/* Generated from: wifi_scan.proto */
/* Do not generate deprecated warnings for self */
#ifndef PROTOBUF_C__NO_DEPRECATED
#define PROTOBUF_C__NO_DEPRECATED
#endif
#include "wifi_scan.pb-c.h"
void cmd_scan_start__init
(CmdScanStart *message)
{
static const CmdScanStart init_value = CMD_SCAN_START__INIT;
*message = init_value;
}
size_t cmd_scan_start__get_packed_size
(const CmdScanStart *message)
{
assert(message->base.descriptor == &cmd_scan_start__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t cmd_scan_start__pack
(const CmdScanStart *message,
uint8_t *out)
{
assert(message->base.descriptor == &cmd_scan_start__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t cmd_scan_start__pack_to_buffer
(const CmdScanStart *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &cmd_scan_start__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
CmdScanStart *
cmd_scan_start__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (CmdScanStart *)
protobuf_c_message_unpack (&cmd_scan_start__descriptor,
allocator, len, data);
}
void cmd_scan_start__free_unpacked
(CmdScanStart *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &cmd_scan_start__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void resp_scan_start__init
(RespScanStart *message)
{
static const RespScanStart init_value = RESP_SCAN_START__INIT;
*message = init_value;
}
size_t resp_scan_start__get_packed_size
(const RespScanStart *message)
{
assert(message->base.descriptor == &resp_scan_start__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t resp_scan_start__pack
(const RespScanStart *message,
uint8_t *out)
{
assert(message->base.descriptor == &resp_scan_start__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t resp_scan_start__pack_to_buffer
(const RespScanStart *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &resp_scan_start__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
RespScanStart *
resp_scan_start__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (RespScanStart *)
protobuf_c_message_unpack (&resp_scan_start__descriptor,
allocator, len, data);
}
void resp_scan_start__free_unpacked
(RespScanStart *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &resp_scan_start__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void cmd_scan_status__init
(CmdScanStatus *message)
{
static const CmdScanStatus init_value = CMD_SCAN_STATUS__INIT;
*message = init_value;
}
size_t cmd_scan_status__get_packed_size
(const CmdScanStatus *message)
{
assert(message->base.descriptor == &cmd_scan_status__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t cmd_scan_status__pack
(const CmdScanStatus *message,
uint8_t *out)
{
assert(message->base.descriptor == &cmd_scan_status__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t cmd_scan_status__pack_to_buffer
(const CmdScanStatus *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &cmd_scan_status__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
CmdScanStatus *
cmd_scan_status__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (CmdScanStatus *)
protobuf_c_message_unpack (&cmd_scan_status__descriptor,
allocator, len, data);
}
void cmd_scan_status__free_unpacked
(CmdScanStatus *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &cmd_scan_status__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void resp_scan_status__init
(RespScanStatus *message)
{
static const RespScanStatus init_value = RESP_SCAN_STATUS__INIT;
*message = init_value;
}
size_t resp_scan_status__get_packed_size
(const RespScanStatus *message)
{
assert(message->base.descriptor == &resp_scan_status__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t resp_scan_status__pack
(const RespScanStatus *message,
uint8_t *out)
{
assert(message->base.descriptor == &resp_scan_status__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t resp_scan_status__pack_to_buffer
(const RespScanStatus *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &resp_scan_status__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
RespScanStatus *
resp_scan_status__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (RespScanStatus *)
protobuf_c_message_unpack (&resp_scan_status__descriptor,
allocator, len, data);
}
void resp_scan_status__free_unpacked
(RespScanStatus *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &resp_scan_status__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void cmd_scan_result__init
(CmdScanResult *message)
{
static const CmdScanResult init_value = CMD_SCAN_RESULT__INIT;
*message = init_value;
}
size_t cmd_scan_result__get_packed_size
(const CmdScanResult *message)
{
assert(message->base.descriptor == &cmd_scan_result__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t cmd_scan_result__pack
(const CmdScanResult *message,
uint8_t *out)
{
assert(message->base.descriptor == &cmd_scan_result__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t cmd_scan_result__pack_to_buffer
(const CmdScanResult *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &cmd_scan_result__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
CmdScanResult *
cmd_scan_result__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (CmdScanResult *)
protobuf_c_message_unpack (&cmd_scan_result__descriptor,
allocator, len, data);
}
void cmd_scan_result__free_unpacked
(CmdScanResult *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &cmd_scan_result__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void wi_fi_scan_result__init
(WiFiScanResult *message)
{
static const WiFiScanResult init_value = WI_FI_SCAN_RESULT__INIT;
*message = init_value;
}
size_t wi_fi_scan_result__get_packed_size
(const WiFiScanResult *message)
{
assert(message->base.descriptor == &wi_fi_scan_result__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t wi_fi_scan_result__pack
(const WiFiScanResult *message,
uint8_t *out)
{
assert(message->base.descriptor == &wi_fi_scan_result__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t wi_fi_scan_result__pack_to_buffer
(const WiFiScanResult *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &wi_fi_scan_result__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
WiFiScanResult *
wi_fi_scan_result__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (WiFiScanResult *)
protobuf_c_message_unpack (&wi_fi_scan_result__descriptor,
allocator, len, data);
}
void wi_fi_scan_result__free_unpacked
(WiFiScanResult *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &wi_fi_scan_result__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void resp_scan_result__init
(RespScanResult *message)
{
static const RespScanResult init_value = RESP_SCAN_RESULT__INIT;
*message = init_value;
}
size_t resp_scan_result__get_packed_size
(const RespScanResult *message)
{
assert(message->base.descriptor == &resp_scan_result__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t resp_scan_result__pack
(const RespScanResult *message,
uint8_t *out)
{
assert(message->base.descriptor == &resp_scan_result__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t resp_scan_result__pack_to_buffer
(const RespScanResult *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &resp_scan_result__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
RespScanResult *
resp_scan_result__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (RespScanResult *)
protobuf_c_message_unpack (&resp_scan_result__descriptor,
allocator, len, data);
}
void resp_scan_result__free_unpacked
(RespScanResult *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &resp_scan_result__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void wi_fi_scan_payload__init
(WiFiScanPayload *message)
{
static const WiFiScanPayload init_value = WI_FI_SCAN_PAYLOAD__INIT;
*message = init_value;
}
size_t wi_fi_scan_payload__get_packed_size
(const WiFiScanPayload *message)
{
assert(message->base.descriptor == &wi_fi_scan_payload__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t wi_fi_scan_payload__pack
(const WiFiScanPayload *message,
uint8_t *out)
{
assert(message->base.descriptor == &wi_fi_scan_payload__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t wi_fi_scan_payload__pack_to_buffer
(const WiFiScanPayload *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &wi_fi_scan_payload__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
WiFiScanPayload *
wi_fi_scan_payload__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (WiFiScanPayload *)
protobuf_c_message_unpack (&wi_fi_scan_payload__descriptor,
allocator, len, data);
}
void wi_fi_scan_payload__free_unpacked
(WiFiScanPayload *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &wi_fi_scan_payload__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
static const ProtobufCFieldDescriptor cmd_scan_start__field_descriptors[4] =
{
{
"blocking",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BOOL,
0, /* quantifier_offset */
offsetof(CmdScanStart, blocking),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"passive",
2,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BOOL,
0, /* quantifier_offset */
offsetof(CmdScanStart, passive),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"group_channels",
3,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_UINT32,
0, /* quantifier_offset */
offsetof(CmdScanStart, group_channels),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"period_ms",
4,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_UINT32,
0, /* quantifier_offset */
offsetof(CmdScanStart, period_ms),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned cmd_scan_start__field_indices_by_name[] = {
0, /* field[0] = blocking */
2, /* field[2] = group_channels */
1, /* field[1] = passive */
3, /* field[3] = period_ms */
};
static const ProtobufCIntRange cmd_scan_start__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 4 }
};
const ProtobufCMessageDescriptor cmd_scan_start__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"CmdScanStart",
"CmdScanStart",
"CmdScanStart",
"",
sizeof(CmdScanStart),
4,
cmd_scan_start__field_descriptors,
cmd_scan_start__field_indices_by_name,
1, cmd_scan_start__number_ranges,
(ProtobufCMessageInit) cmd_scan_start__init,
NULL,NULL,NULL /* reserved[123] */
};
#define resp_scan_start__field_descriptors NULL
#define resp_scan_start__field_indices_by_name NULL
#define resp_scan_start__number_ranges NULL
const ProtobufCMessageDescriptor resp_scan_start__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"RespScanStart",
"RespScanStart",
"RespScanStart",
"",
sizeof(RespScanStart),
0,
resp_scan_start__field_descriptors,
resp_scan_start__field_indices_by_name,
0, resp_scan_start__number_ranges,
(ProtobufCMessageInit) resp_scan_start__init,
NULL,NULL,NULL /* reserved[123] */
};
#define cmd_scan_status__field_descriptors NULL
#define cmd_scan_status__field_indices_by_name NULL
#define cmd_scan_status__number_ranges NULL
const ProtobufCMessageDescriptor cmd_scan_status__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"CmdScanStatus",
"CmdScanStatus",
"CmdScanStatus",
"",
sizeof(CmdScanStatus),
0,
cmd_scan_status__field_descriptors,
cmd_scan_status__field_indices_by_name,
0, cmd_scan_status__number_ranges,
(ProtobufCMessageInit) cmd_scan_status__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor resp_scan_status__field_descriptors[2] =
{
{
"scan_finished",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BOOL,
0, /* quantifier_offset */
offsetof(RespScanStatus, scan_finished),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"result_count",
2,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_UINT32,
0, /* quantifier_offset */
offsetof(RespScanStatus, result_count),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned resp_scan_status__field_indices_by_name[] = {
1, /* field[1] = result_count */
0, /* field[0] = scan_finished */
};
static const ProtobufCIntRange resp_scan_status__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 2 }
};
const ProtobufCMessageDescriptor resp_scan_status__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"RespScanStatus",
"RespScanStatus",
"RespScanStatus",
"",
sizeof(RespScanStatus),
2,
resp_scan_status__field_descriptors,
resp_scan_status__field_indices_by_name,
1, resp_scan_status__number_ranges,
(ProtobufCMessageInit) resp_scan_status__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor cmd_scan_result__field_descriptors[2] =
{
{
"start_index",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_UINT32,
0, /* quantifier_offset */
offsetof(CmdScanResult, start_index),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"count",
2,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_UINT32,
0, /* quantifier_offset */
offsetof(CmdScanResult, count),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned cmd_scan_result__field_indices_by_name[] = {
1, /* field[1] = count */
0, /* field[0] = start_index */
};
static const ProtobufCIntRange cmd_scan_result__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 2 }
};
const ProtobufCMessageDescriptor cmd_scan_result__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"CmdScanResult",
"CmdScanResult",
"CmdScanResult",
"",
sizeof(CmdScanResult),
2,
cmd_scan_result__field_descriptors,
cmd_scan_result__field_indices_by_name,
1, cmd_scan_result__number_ranges,
(ProtobufCMessageInit) cmd_scan_result__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor wi_fi_scan_result__field_descriptors[5] =
{
{
"ssid",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
offsetof(WiFiScanResult, ssid),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"channel",
2,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_UINT32,
0, /* quantifier_offset */
offsetof(WiFiScanResult, channel),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"rssi",
3,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_INT32,
0, /* quantifier_offset */
offsetof(WiFiScanResult, rssi),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"bssid",
4,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
offsetof(WiFiScanResult, bssid),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"auth",
5,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_ENUM,
0, /* quantifier_offset */
offsetof(WiFiScanResult, auth),
&wifi_auth_mode__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned wi_fi_scan_result__field_indices_by_name[] = {
4, /* field[4] = auth */
3, /* field[3] = bssid */
1, /* field[1] = channel */
2, /* field[2] = rssi */
0, /* field[0] = ssid */
};
static const ProtobufCIntRange wi_fi_scan_result__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 5 }
};
const ProtobufCMessageDescriptor wi_fi_scan_result__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"WiFiScanResult",
"WiFiScanResult",
"WiFiScanResult",
"",
sizeof(WiFiScanResult),
5,
wi_fi_scan_result__field_descriptors,
wi_fi_scan_result__field_indices_by_name,
1, wi_fi_scan_result__number_ranges,
(ProtobufCMessageInit) wi_fi_scan_result__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor resp_scan_result__field_descriptors[1] =
{
{
"entries",
1,
PROTOBUF_C_LABEL_REPEATED,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(RespScanResult, n_entries),
offsetof(RespScanResult, entries),
&wi_fi_scan_result__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned resp_scan_result__field_indices_by_name[] = {
0, /* field[0] = entries */
};
static const ProtobufCIntRange resp_scan_result__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 1 }
};
const ProtobufCMessageDescriptor resp_scan_result__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"RespScanResult",
"RespScanResult",
"RespScanResult",
"",
sizeof(RespScanResult),
1,
resp_scan_result__field_descriptors,
resp_scan_result__field_indices_by_name,
1, resp_scan_result__number_ranges,
(ProtobufCMessageInit) resp_scan_result__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor wi_fi_scan_payload__field_descriptors[8] =
{
{
"msg",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_ENUM,
0, /* quantifier_offset */
offsetof(WiFiScanPayload, msg),
&wi_fi_scan_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(WiFiScanPayload, status),
&status__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"cmd_scan_start",
10,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(WiFiScanPayload, payload_case),
offsetof(WiFiScanPayload, cmd_scan_start),
&cmd_scan_start__descriptor,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"resp_scan_start",
11,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(WiFiScanPayload, payload_case),
offsetof(WiFiScanPayload, resp_scan_start),
&resp_scan_start__descriptor,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"cmd_scan_status",
12,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(WiFiScanPayload, payload_case),
offsetof(WiFiScanPayload, cmd_scan_status),
&cmd_scan_status__descriptor,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"resp_scan_status",
13,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(WiFiScanPayload, payload_case),
offsetof(WiFiScanPayload, resp_scan_status),
&resp_scan_status__descriptor,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"cmd_scan_result",
14,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(WiFiScanPayload, payload_case),
offsetof(WiFiScanPayload, cmd_scan_result),
&cmd_scan_result__descriptor,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"resp_scan_result",
15,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(WiFiScanPayload, payload_case),
offsetof(WiFiScanPayload, resp_scan_result),
&resp_scan_result__descriptor,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned wi_fi_scan_payload__field_indices_by_name[] = {
6, /* field[6] = cmd_scan_result */
2, /* field[2] = cmd_scan_start */
4, /* field[4] = cmd_scan_status */
0, /* field[0] = msg */
7, /* field[7] = resp_scan_result */
3, /* field[3] = resp_scan_start */
5, /* field[5] = resp_scan_status */
1, /* field[1] = status */
};
static const ProtobufCIntRange wi_fi_scan_payload__number_ranges[2 + 1] =
{
{ 1, 0 },
{ 10, 2 },
{ 0, 8 }
};
const ProtobufCMessageDescriptor wi_fi_scan_payload__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"WiFiScanPayload",
"WiFiScanPayload",
"WiFiScanPayload",
"",
sizeof(WiFiScanPayload),
8,
wi_fi_scan_payload__field_descriptors,
wi_fi_scan_payload__field_indices_by_name,
2, wi_fi_scan_payload__number_ranges,
(ProtobufCMessageInit) wi_fi_scan_payload__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCEnumValue wi_fi_scan_msg_type__enum_values_by_number[6] =
{
{ "TypeCmdScanStart", "WI_FI_SCAN_MSG_TYPE__TypeCmdScanStart", 0 },
{ "TypeRespScanStart", "WI_FI_SCAN_MSG_TYPE__TypeRespScanStart", 1 },
{ "TypeCmdScanStatus", "WI_FI_SCAN_MSG_TYPE__TypeCmdScanStatus", 2 },
{ "TypeRespScanStatus", "WI_FI_SCAN_MSG_TYPE__TypeRespScanStatus", 3 },
{ "TypeCmdScanResult", "WI_FI_SCAN_MSG_TYPE__TypeCmdScanResult", 4 },
{ "TypeRespScanResult", "WI_FI_SCAN_MSG_TYPE__TypeRespScanResult", 5 },
};
static const ProtobufCIntRange wi_fi_scan_msg_type__value_ranges[] = {
{0, 0},{0, 6}
};
static const ProtobufCEnumValueIndex wi_fi_scan_msg_type__enum_values_by_name[6] =
{
{ "TypeCmdScanResult", 4 },
{ "TypeCmdScanStart", 0 },
{ "TypeCmdScanStatus", 2 },
{ "TypeRespScanResult", 5 },
{ "TypeRespScanStart", 1 },
{ "TypeRespScanStatus", 3 },
};
const ProtobufCEnumDescriptor wi_fi_scan_msg_type__descriptor =
{
PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,
"WiFiScanMsgType",
"WiFiScanMsgType",
"WiFiScanMsgType",
"",
6,
wi_fi_scan_msg_type__enum_values_by_number,
6,
wi_fi_scan_msg_type__enum_values_by_name,
1,
wi_fi_scan_msg_type__value_ranges,
NULL,NULL,NULL,NULL /* reserved[1234] */
};

View file

@ -0,0 +1,350 @@
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
/* Generated from: wifi_scan.proto */
#ifndef PROTOBUF_C_wifi_5fscan_2eproto__INCLUDED
#define PROTOBUF_C_wifi_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 1003001 < 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 "wifi_constants.pb-c.h"
typedef struct _CmdScanStart CmdScanStart;
typedef struct _RespScanStart RespScanStart;
typedef struct _CmdScanStatus CmdScanStatus;
typedef struct _RespScanStatus RespScanStatus;
typedef struct _CmdScanResult CmdScanResult;
typedef struct _WiFiScanResult WiFiScanResult;
typedef struct _RespScanResult RespScanResult;
typedef struct _WiFiScanPayload WiFiScanPayload;
/* --- enums --- */
typedef enum _WiFiScanMsgType {
WI_FI_SCAN_MSG_TYPE__TypeCmdScanStart = 0,
WI_FI_SCAN_MSG_TYPE__TypeRespScanStart = 1,
WI_FI_SCAN_MSG_TYPE__TypeCmdScanStatus = 2,
WI_FI_SCAN_MSG_TYPE__TypeRespScanStatus = 3,
WI_FI_SCAN_MSG_TYPE__TypeCmdScanResult = 4,
WI_FI_SCAN_MSG_TYPE__TypeRespScanResult = 5
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(WI_FI_SCAN_MSG_TYPE)
} WiFiScanMsgType;
/* --- messages --- */
struct _CmdScanStart
{
ProtobufCMessage base;
protobuf_c_boolean blocking;
protobuf_c_boolean passive;
uint32_t group_channels;
uint32_t period_ms;
};
#define CMD_SCAN_START__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&cmd_scan_start__descriptor) \
, 0, 0, 0, 0 }
struct _RespScanStart
{
ProtobufCMessage base;
};
#define RESP_SCAN_START__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&resp_scan_start__descriptor) \
}
struct _CmdScanStatus
{
ProtobufCMessage base;
};
#define CMD_SCAN_STATUS__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&cmd_scan_status__descriptor) \
}
struct _RespScanStatus
{
ProtobufCMessage base;
protobuf_c_boolean scan_finished;
uint32_t result_count;
};
#define RESP_SCAN_STATUS__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&resp_scan_status__descriptor) \
, 0, 0 }
struct _CmdScanResult
{
ProtobufCMessage base;
uint32_t start_index;
uint32_t count;
};
#define CMD_SCAN_RESULT__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&cmd_scan_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 _RespScanResult
{
ProtobufCMessage base;
size_t n_entries;
WiFiScanResult **entries;
};
#define RESP_SCAN_RESULT__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&resp_scan_result__descriptor) \
, 0,NULL }
typedef enum {
WI_FI_SCAN_PAYLOAD__PAYLOAD__NOT_SET = 0,
WI_FI_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_START = 10,
WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_START = 11,
WI_FI_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_STATUS = 12,
WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_STATUS = 13,
WI_FI_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_RESULT = 14,
WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_RESULT = 15
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(WI_FI_SCAN_PAYLOAD__PAYLOAD)
} WiFiScanPayload__PayloadCase;
struct _WiFiScanPayload
{
ProtobufCMessage base;
WiFiScanMsgType msg;
Status status;
WiFiScanPayload__PayloadCase payload_case;
union {
CmdScanStart *cmd_scan_start;
RespScanStart *resp_scan_start;
CmdScanStatus *cmd_scan_status;
RespScanStatus *resp_scan_status;
CmdScanResult *cmd_scan_result;
RespScanResult *resp_scan_result;
};
};
#define WI_FI_SCAN_PAYLOAD__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&wi_fi_scan_payload__descriptor) \
, WI_FI_SCAN_MSG_TYPE__TypeCmdScanStart, STATUS__Success, WI_FI_SCAN_PAYLOAD__PAYLOAD__NOT_SET, {0} }
/* CmdScanStart methods */
void cmd_scan_start__init
(CmdScanStart *message);
size_t cmd_scan_start__get_packed_size
(const CmdScanStart *message);
size_t cmd_scan_start__pack
(const CmdScanStart *message,
uint8_t *out);
size_t cmd_scan_start__pack_to_buffer
(const CmdScanStart *message,
ProtobufCBuffer *buffer);
CmdScanStart *
cmd_scan_start__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void cmd_scan_start__free_unpacked
(CmdScanStart *message,
ProtobufCAllocator *allocator);
/* RespScanStart methods */
void resp_scan_start__init
(RespScanStart *message);
size_t resp_scan_start__get_packed_size
(const RespScanStart *message);
size_t resp_scan_start__pack
(const RespScanStart *message,
uint8_t *out);
size_t resp_scan_start__pack_to_buffer
(const RespScanStart *message,
ProtobufCBuffer *buffer);
RespScanStart *
resp_scan_start__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void resp_scan_start__free_unpacked
(RespScanStart *message,
ProtobufCAllocator *allocator);
/* CmdScanStatus methods */
void cmd_scan_status__init
(CmdScanStatus *message);
size_t cmd_scan_status__get_packed_size
(const CmdScanStatus *message);
size_t cmd_scan_status__pack
(const CmdScanStatus *message,
uint8_t *out);
size_t cmd_scan_status__pack_to_buffer
(const CmdScanStatus *message,
ProtobufCBuffer *buffer);
CmdScanStatus *
cmd_scan_status__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void cmd_scan_status__free_unpacked
(CmdScanStatus *message,
ProtobufCAllocator *allocator);
/* RespScanStatus methods */
void resp_scan_status__init
(RespScanStatus *message);
size_t resp_scan_status__get_packed_size
(const RespScanStatus *message);
size_t resp_scan_status__pack
(const RespScanStatus *message,
uint8_t *out);
size_t resp_scan_status__pack_to_buffer
(const RespScanStatus *message,
ProtobufCBuffer *buffer);
RespScanStatus *
resp_scan_status__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void resp_scan_status__free_unpacked
(RespScanStatus *message,
ProtobufCAllocator *allocator);
/* CmdScanResult methods */
void cmd_scan_result__init
(CmdScanResult *message);
size_t cmd_scan_result__get_packed_size
(const CmdScanResult *message);
size_t cmd_scan_result__pack
(const CmdScanResult *message,
uint8_t *out);
size_t cmd_scan_result__pack_to_buffer
(const CmdScanResult *message,
ProtobufCBuffer *buffer);
CmdScanResult *
cmd_scan_result__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void cmd_scan_result__free_unpacked
(CmdScanResult *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);
/* RespScanResult methods */
void resp_scan_result__init
(RespScanResult *message);
size_t resp_scan_result__get_packed_size
(const RespScanResult *message);
size_t resp_scan_result__pack
(const RespScanResult *message,
uint8_t *out);
size_t resp_scan_result__pack_to_buffer
(const RespScanResult *message,
ProtobufCBuffer *buffer);
RespScanResult *
resp_scan_result__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void resp_scan_result__free_unpacked
(RespScanResult *message,
ProtobufCAllocator *allocator);
/* WiFiScanPayload methods */
void wi_fi_scan_payload__init
(WiFiScanPayload *message);
size_t wi_fi_scan_payload__get_packed_size
(const WiFiScanPayload *message);
size_t wi_fi_scan_payload__pack
(const WiFiScanPayload *message,
uint8_t *out);
size_t wi_fi_scan_payload__pack_to_buffer
(const WiFiScanPayload *message,
ProtobufCBuffer *buffer);
WiFiScanPayload *
wi_fi_scan_payload__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void wi_fi_scan_payload__free_unpacked
(WiFiScanPayload *message,
ProtobufCAllocator *allocator);
/* --- per-message closures --- */
typedef void (*CmdScanStart_Closure)
(const CmdScanStart *message,
void *closure_data);
typedef void (*RespScanStart_Closure)
(const RespScanStart *message,
void *closure_data);
typedef void (*CmdScanStatus_Closure)
(const CmdScanStatus *message,
void *closure_data);
typedef void (*RespScanStatus_Closure)
(const RespScanStatus *message,
void *closure_data);
typedef void (*CmdScanResult_Closure)
(const CmdScanResult *message,
void *closure_data);
typedef void (*WiFiScanResult_Closure)
(const WiFiScanResult *message,
void *closure_data);
typedef void (*RespScanResult_Closure)
(const RespScanResult *message,
void *closure_data);
typedef void (*WiFiScanPayload_Closure)
(const WiFiScanPayload *message,
void *closure_data);
/* --- services --- */
/* --- descriptors --- */
extern const ProtobufCEnumDescriptor wi_fi_scan_msg_type__descriptor;
extern const ProtobufCMessageDescriptor cmd_scan_start__descriptor;
extern const ProtobufCMessageDescriptor resp_scan_start__descriptor;
extern const ProtobufCMessageDescriptor cmd_scan_status__descriptor;
extern const ProtobufCMessageDescriptor resp_scan_status__descriptor;
extern const ProtobufCMessageDescriptor cmd_scan_result__descriptor;
extern const ProtobufCMessageDescriptor wi_fi_scan_result__descriptor;
extern const ProtobufCMessageDescriptor resp_scan_result__descriptor;
extern const ProtobufCMessageDescriptor wi_fi_scan_payload__descriptor;
PROTOBUF_C__END_DECLS
#endif /* PROTOBUF_C_wifi_5fscan_2eproto__INCLUDED */

View file

@ -0,0 +1,63 @@
syntax = "proto3";
import "constants.proto";
import "wifi_constants.proto";
message CmdScanStart {
bool blocking = 1;
bool passive = 2;
uint32 group_channels = 3;
uint32 period_ms = 4;
}
message RespScanStart {
}
message CmdScanStatus {
}
message RespScanStatus {
bool scan_finished = 1;
uint32 result_count = 2;
}
message CmdScanResult {
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 RespScanResult {
repeated WiFiScanResult entries = 1;
}
enum WiFiScanMsgType {
TypeCmdScanStart = 0;
TypeRespScanStart = 1;
TypeCmdScanStatus = 2;
TypeRespScanStatus = 3;
TypeCmdScanResult = 4;
TypeRespScanResult = 5;
}
message WiFiScanPayload {
WiFiScanMsgType msg = 1;
Status status = 2;
oneof payload {
CmdScanStart cmd_scan_start = 10;
RespScanStart resp_scan_start = 11;
CmdScanStatus cmd_scan_status = 12;
RespScanStatus resp_scan_status = 13;
CmdScanResult cmd_scan_result = 14;
RespScanResult resp_scan_result = 15;
}
}

View file

@ -0,0 +1,522 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: wifi_scan.proto
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf.internal import enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
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 wifi_constants_pb2 as wifi__constants__pb2
DESCRIPTOR = _descriptor.FileDescriptor(
name='wifi_scan.proto',
package='',
syntax='proto3',
serialized_options=None,
serialized_pb=_b('\n\x0fwifi_scan.proto\x1a\x0f\x63onstants.proto\x1a\x14wifi_constants.proto\"\\\n\x0c\x43mdScanStart\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\"\x0f\n\rRespScanStart\"\x0f\n\rCmdScanStatus\"=\n\x0eRespScanStatus\x12\x15\n\rscan_finished\x18\x01 \x01(\x08\x12\x14\n\x0cresult_count\x18\x02 \x01(\r\"3\n\rCmdScanResult\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\"2\n\x0eRespScanResult\x12 \n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x0f.WiFiScanResult\"\xd8\x02\n\x0fWiFiScanPayload\x12\x1d\n\x03msg\x18\x01 \x01(\x0e\x32\x10.WiFiScanMsgType\x12\x17\n\x06status\x18\x02 \x01(\x0e\x32\x07.Status\x12\'\n\x0e\x63md_scan_start\x18\n \x01(\x0b\x32\r.CmdScanStartH\x00\x12)\n\x0fresp_scan_start\x18\x0b \x01(\x0b\x32\x0e.RespScanStartH\x00\x12)\n\x0f\x63md_scan_status\x18\x0c \x01(\x0b\x32\x0e.CmdScanStatusH\x00\x12+\n\x10resp_scan_status\x18\r \x01(\x0b\x32\x0f.RespScanStatusH\x00\x12)\n\x0f\x63md_scan_result\x18\x0e \x01(\x0b\x32\x0e.CmdScanResultH\x00\x12+\n\x10resp_scan_result\x18\x0f \x01(\x0b\x32\x0f.RespScanResultH\x00\x42\t\n\x07payload*\x9c\x01\n\x0fWiFiScanMsgType\x12\x14\n\x10TypeCmdScanStart\x10\x00\x12\x15\n\x11TypeRespScanStart\x10\x01\x12\x15\n\x11TypeCmdScanStatus\x10\x02\x12\x16\n\x12TypeRespScanStatus\x10\x03\x12\x15\n\x11TypeCmdScanResult\x10\x04\x12\x16\n\x12TypeRespScanResult\x10\x05\x62\x06proto3')
,
dependencies=[constants__pb2.DESCRIPTOR,wifi__constants__pb2.DESCRIPTOR,])
_WIFISCANMSGTYPE = _descriptor.EnumDescriptor(
name='WiFiScanMsgType',
full_name='WiFiScanMsgType',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='TypeCmdScanStart', index=0, number=0,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='TypeRespScanStart', index=1, number=1,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='TypeCmdScanStatus', index=2, number=2,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='TypeRespScanStatus', index=3, number=3,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='TypeCmdScanResult', index=4, number=4,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='TypeRespScanResult', index=5, number=5,
serialized_options=None,
type=None),
],
containing_type=None,
serialized_options=None,
serialized_start=809,
serialized_end=965,
)
_sym_db.RegisterEnumDescriptor(_WIFISCANMSGTYPE)
WiFiScanMsgType = enum_type_wrapper.EnumTypeWrapper(_WIFISCANMSGTYPE)
TypeCmdScanStart = 0
TypeRespScanStart = 1
TypeCmdScanStatus = 2
TypeRespScanStatus = 3
TypeCmdScanResult = 4
TypeRespScanResult = 5
_CMDSCANSTART = _descriptor.Descriptor(
name='CmdScanStart',
full_name='CmdScanStart',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='blocking', full_name='CmdScanStart.blocking', index=0,
number=1, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='passive', full_name='CmdScanStart.passive', index=1,
number=2, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='group_channels', full_name='CmdScanStart.group_channels', index=2,
number=3, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='period_ms', full_name='CmdScanStart.period_ms', index=3,
number=4, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=58,
serialized_end=150,
)
_RESPSCANSTART = _descriptor.Descriptor(
name='RespScanStart',
full_name='RespScanStart',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=152,
serialized_end=167,
)
_CMDSCANSTATUS = _descriptor.Descriptor(
name='CmdScanStatus',
full_name='CmdScanStatus',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=169,
serialized_end=184,
)
_RESPSCANSTATUS = _descriptor.Descriptor(
name='RespScanStatus',
full_name='RespScanStatus',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='scan_finished', full_name='RespScanStatus.scan_finished', index=0,
number=1, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='result_count', full_name='RespScanStatus.result_count', index=1,
number=2, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=186,
serialized_end=247,
)
_CMDSCANRESULT = _descriptor.Descriptor(
name='CmdScanResult',
full_name='CmdScanResult',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='start_index', full_name='CmdScanResult.start_index', index=0,
number=1, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='count', full_name='CmdScanResult.count', index=1,
number=2, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=249,
serialized_end=300,
)
_WIFISCANRESULT = _descriptor.Descriptor(
name='WiFiScanResult',
full_name='WiFiScanResult',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='ssid', full_name='WiFiScanResult.ssid', index=0,
number=1, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='channel', full_name='WiFiScanResult.channel', index=1,
number=2, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='rssi', full_name='WiFiScanResult.rssi', index=2,
number=3, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='bssid', full_name='WiFiScanResult.bssid', index=3,
number=4, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='auth', full_name='WiFiScanResult.auth', index=4,
number=5, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=302,
serialized_end=407,
)
_RESPSCANRESULT = _descriptor.Descriptor(
name='RespScanResult',
full_name='RespScanResult',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='entries', full_name='RespScanResult.entries', index=0,
number=1, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=409,
serialized_end=459,
)
_WIFISCANPAYLOAD = _descriptor.Descriptor(
name='WiFiScanPayload',
full_name='WiFiScanPayload',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='msg', full_name='WiFiScanPayload.msg', index=0,
number=1, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='status', full_name='WiFiScanPayload.status', index=1,
number=2, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='cmd_scan_start', full_name='WiFiScanPayload.cmd_scan_start', index=2,
number=10, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='resp_scan_start', full_name='WiFiScanPayload.resp_scan_start', index=3,
number=11, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='cmd_scan_status', full_name='WiFiScanPayload.cmd_scan_status', index=4,
number=12, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='resp_scan_status', full_name='WiFiScanPayload.resp_scan_status', index=5,
number=13, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='cmd_scan_result', full_name='WiFiScanPayload.cmd_scan_result', index=6,
number=14, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='resp_scan_result', full_name='WiFiScanPayload.resp_scan_result', index=7,
number=15, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
_descriptor.OneofDescriptor(
name='payload', full_name='WiFiScanPayload.payload',
index=0, containing_type=None, fields=[]),
],
serialized_start=462,
serialized_end=806,
)
_WIFISCANRESULT.fields_by_name['auth'].enum_type = wifi__constants__pb2._WIFIAUTHMODE
_RESPSCANRESULT.fields_by_name['entries'].message_type = _WIFISCANRESULT
_WIFISCANPAYLOAD.fields_by_name['msg'].enum_type = _WIFISCANMSGTYPE
_WIFISCANPAYLOAD.fields_by_name['status'].enum_type = constants__pb2._STATUS
_WIFISCANPAYLOAD.fields_by_name['cmd_scan_start'].message_type = _CMDSCANSTART
_WIFISCANPAYLOAD.fields_by_name['resp_scan_start'].message_type = _RESPSCANSTART
_WIFISCANPAYLOAD.fields_by_name['cmd_scan_status'].message_type = _CMDSCANSTATUS
_WIFISCANPAYLOAD.fields_by_name['resp_scan_status'].message_type = _RESPSCANSTATUS
_WIFISCANPAYLOAD.fields_by_name['cmd_scan_result'].message_type = _CMDSCANRESULT
_WIFISCANPAYLOAD.fields_by_name['resp_scan_result'].message_type = _RESPSCANRESULT
_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append(
_WIFISCANPAYLOAD.fields_by_name['cmd_scan_start'])
_WIFISCANPAYLOAD.fields_by_name['cmd_scan_start'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload']
_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append(
_WIFISCANPAYLOAD.fields_by_name['resp_scan_start'])
_WIFISCANPAYLOAD.fields_by_name['resp_scan_start'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload']
_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append(
_WIFISCANPAYLOAD.fields_by_name['cmd_scan_status'])
_WIFISCANPAYLOAD.fields_by_name['cmd_scan_status'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload']
_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append(
_WIFISCANPAYLOAD.fields_by_name['resp_scan_status'])
_WIFISCANPAYLOAD.fields_by_name['resp_scan_status'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload']
_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append(
_WIFISCANPAYLOAD.fields_by_name['cmd_scan_result'])
_WIFISCANPAYLOAD.fields_by_name['cmd_scan_result'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload']
_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append(
_WIFISCANPAYLOAD.fields_by_name['resp_scan_result'])
_WIFISCANPAYLOAD.fields_by_name['resp_scan_result'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload']
DESCRIPTOR.message_types_by_name['CmdScanStart'] = _CMDSCANSTART
DESCRIPTOR.message_types_by_name['RespScanStart'] = _RESPSCANSTART
DESCRIPTOR.message_types_by_name['CmdScanStatus'] = _CMDSCANSTATUS
DESCRIPTOR.message_types_by_name['RespScanStatus'] = _RESPSCANSTATUS
DESCRIPTOR.message_types_by_name['CmdScanResult'] = _CMDSCANRESULT
DESCRIPTOR.message_types_by_name['WiFiScanResult'] = _WIFISCANRESULT
DESCRIPTOR.message_types_by_name['RespScanResult'] = _RESPSCANRESULT
DESCRIPTOR.message_types_by_name['WiFiScanPayload'] = _WIFISCANPAYLOAD
DESCRIPTOR.enum_types_by_name['WiFiScanMsgType'] = _WIFISCANMSGTYPE
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
CmdScanStart = _reflection.GeneratedProtocolMessageType('CmdScanStart', (_message.Message,), dict(
DESCRIPTOR = _CMDSCANSTART,
__module__ = 'wifi_scan_pb2'
# @@protoc_insertion_point(class_scope:CmdScanStart)
))
_sym_db.RegisterMessage(CmdScanStart)
RespScanStart = _reflection.GeneratedProtocolMessageType('RespScanStart', (_message.Message,), dict(
DESCRIPTOR = _RESPSCANSTART,
__module__ = 'wifi_scan_pb2'
# @@protoc_insertion_point(class_scope:RespScanStart)
))
_sym_db.RegisterMessage(RespScanStart)
CmdScanStatus = _reflection.GeneratedProtocolMessageType('CmdScanStatus', (_message.Message,), dict(
DESCRIPTOR = _CMDSCANSTATUS,
__module__ = 'wifi_scan_pb2'
# @@protoc_insertion_point(class_scope:CmdScanStatus)
))
_sym_db.RegisterMessage(CmdScanStatus)
RespScanStatus = _reflection.GeneratedProtocolMessageType('RespScanStatus', (_message.Message,), dict(
DESCRIPTOR = _RESPSCANSTATUS,
__module__ = 'wifi_scan_pb2'
# @@protoc_insertion_point(class_scope:RespScanStatus)
))
_sym_db.RegisterMessage(RespScanStatus)
CmdScanResult = _reflection.GeneratedProtocolMessageType('CmdScanResult', (_message.Message,), dict(
DESCRIPTOR = _CMDSCANRESULT,
__module__ = 'wifi_scan_pb2'
# @@protoc_insertion_point(class_scope:CmdScanResult)
))
_sym_db.RegisterMessage(CmdScanResult)
WiFiScanResult = _reflection.GeneratedProtocolMessageType('WiFiScanResult', (_message.Message,), dict(
DESCRIPTOR = _WIFISCANRESULT,
__module__ = 'wifi_scan_pb2'
# @@protoc_insertion_point(class_scope:WiFiScanResult)
))
_sym_db.RegisterMessage(WiFiScanResult)
RespScanResult = _reflection.GeneratedProtocolMessageType('RespScanResult', (_message.Message,), dict(
DESCRIPTOR = _RESPSCANRESULT,
__module__ = 'wifi_scan_pb2'
# @@protoc_insertion_point(class_scope:RespScanResult)
))
_sym_db.RegisterMessage(RespScanResult)
WiFiScanPayload = _reflection.GeneratedProtocolMessageType('WiFiScanPayload', (_message.Message,), dict(
DESCRIPTOR = _WIFISCANPAYLOAD,
__module__ = 'wifi_scan_pb2'
# @@protoc_insertion_point(class_scope:WiFiScanPayload)
))
_sym_db.RegisterMessage(WiFiScanPayload)
# @@protoc_insertion_point(module_scope)

View file

@ -0,0 +1,199 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <string.h>
#include <esp_err.h>
#include <esp_log.h>
#include <esp_wifi.h>
#include <tcpip_adapter.h>
#include "wifi_provisioning/wifi_config.h"
#include "wifi_provisioning/wifi_scan.h"
#include "wifi_provisioning/manager.h"
#include "wifi_provisioning_priv.h"
static const char *TAG = "wifi_prov_handlers";
/* Provide definition of wifi_prov_ctx_t */
struct wifi_prov_ctx {
wifi_config_t wifi_cfg;
};
static wifi_config_t *get_config(wifi_prov_ctx_t **ctx)
{
return (*ctx ? & (*ctx)->wifi_cfg : NULL);
}
static wifi_config_t *new_config(wifi_prov_ctx_t **ctx)
{
free(*ctx);
(*ctx) = (wifi_prov_ctx_t *) calloc(1, sizeof(wifi_prov_ctx_t));
return get_config(ctx);
}
static void free_config(wifi_prov_ctx_t **ctx)
{
free(*ctx);
*ctx = NULL;
}
static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi_prov_ctx_t **ctx)
{
/* Initialize to zero */
memset(resp_data, 0, sizeof(wifi_prov_config_get_data_t));
if (wifi_prov_mgr_get_wifi_state(&resp_data->wifi_state) != ESP_OK) {
ESP_LOGW(TAG, "Wi-Fi provisioning manager not running");
return ESP_ERR_INVALID_STATE;
}
if (resp_data->wifi_state == WIFI_PROV_STA_CONNECTED) {
ESP_LOGD(TAG, "Got state : connected");
/* IP Addr assigned to STA */
tcpip_adapter_ip_info_t ip_info;
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info);
char *ip_addr = ip4addr_ntoa(&ip_info.ip);
strcpy(resp_data->conn_info.ip_addr, 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 */
wifi_prov_mgr_done();
} else if (resp_data->wifi_state == WIFI_PROV_STA_DISCONNECTED) {
ESP_LOGD(TAG, "Got state : disconnected");
/* If disconnected, convey reason */
wifi_prov_mgr_get_wifi_disconnect_reason(&resp_data->fail_reason);
} else {
ESP_LOGD(TAG, "Got state : connecting");
}
return ESP_OK;
}
static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, wifi_prov_ctx_t **ctx)
{
wifi_config_t *wifi_cfg = get_config(ctx);
if (wifi_cfg) {
free_config(ctx);
}
wifi_cfg = new_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 strncpy 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) */
strncpy((char *) wifi_cfg->sta.ssid, req_data->ssid, sizeof(wifi_cfg->sta.ssid));
/* 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));
return ESP_OK;
}
static esp_err_t apply_config_handler(wifi_prov_ctx_t **ctx)
{
wifi_config_t *wifi_cfg = get_config(ctx);
if (!wifi_cfg) {
ESP_LOGE(TAG, "Wi-Fi config not set");
return ESP_ERR_INVALID_STATE;
}
esp_err_t ret = wifi_prov_mgr_configure_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_config(ctx);
return ret;
}
esp_err_t get_wifi_prov_handlers(wifi_prov_config_handlers_t *ptr)
{
if (!ptr) {
return ESP_ERR_INVALID_ARG;
}
ptr->get_status_handler = get_status_handler;
ptr->set_config_handler = set_config_handler;
ptr->apply_config_handler = apply_config_handler;
ptr->ctx = NULL;
return ESP_OK;
}
/*************************************************************************/
static esp_err_t scan_start(bool blocking, bool passive,
uint8_t group_channels, uint32_t period_ms,
wifi_prov_scan_ctx_t **ctx)
{
return wifi_prov_mgr_wifi_scan_start(blocking, passive, group_channels, period_ms);
}
static esp_err_t scan_status(bool *scan_finished,
uint16_t *result_count,
wifi_prov_scan_ctx_t **ctx)
{
*scan_finished = wifi_prov_mgr_wifi_scan_finished();
*result_count = wifi_prov_mgr_wifi_scan_result_count();
return ESP_OK;
}
static esp_err_t scan_result(uint16_t result_index,
wifi_prov_scan_result_t *result,
wifi_prov_scan_ctx_t **ctx)
{
const wifi_ap_record_t *record = wifi_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;
}
esp_err_t get_wifi_scan_handlers(wifi_prov_scan_handlers_t *ptr)
{
if (!ptr) {
return ESP_ERR_INVALID_ARG;
}
ptr->scan_start = scan_start;
ptr->scan_status = scan_status;
ptr->scan_result = scan_result;
ptr->ctx = NULL;
return ESP_OK;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,232 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <esp_log.h>
#include <esp_err.h>
#include <esp_bt.h>
#include <protocomm.h>
#include <protocomm_ble.h>
#include "wifi_provisioning/scheme_ble.h"
#include "wifi_provisioning_priv.h"
static const char *TAG = "wifi_prov_scheme_ble";
extern const wifi_prov_scheme_t wifi_prov_scheme_ble;
static uint8_t *custom_service_uuid;
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;
/* 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;
}
esp_err_t wifi_prov_scheme_ble_set_service_uuid(uint8_t *uuid128)
{
if (!uuid128) {
return ESP_ERR_INVALID_ARG;
}
custom_service_uuid = uuid128;
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 */
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
0x00, 0x10, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
};
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));
}
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");
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 wifi_prov_scheme_ble_event_cb_free_btdm(void *user_data, wifi_prov_cb_event_t event, void *event_data)
{
esp_err_t err;
switch (event) {
case WIFI_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 WIFI_PROV_DEINIT:
/* 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");
}
break;
default:
break;
}
}
/* Used when BT is not needed by application */
void wifi_prov_scheme_ble_event_cb_free_bt(void *user_data, wifi_prov_cb_event_t event, void *event_data)
{
esp_err_t err;
switch (event) {
case WIFI_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;
}
}
/* Used when BLE is not needed by application */
void wifi_prov_scheme_ble_event_cb_free_ble(void *user_data, wifi_prov_cb_event_t event, void *event_data)
{
esp_err_t err;
switch (event) {
case WIFI_PROV_DEINIT:
/* 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");
}
break;
default:
break;
}
}
const wifi_prov_scheme_t wifi_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,
.wifi_mode = WIFI_MODE_STA
};

View file

@ -0,0 +1,92 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <esp_log.h>
#include <esp_err.h>
#include <esp_wifi.h>
#include <protocomm.h>
#include <protocomm_console.h>
#include "wifi_provisioning/scheme_console.h"
#include "wifi_provisioning_priv.h"
static const char *TAG = "wifi_prov_scheme_console";
extern const wifi_prov_scheme_t wifi_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 wifi_prov_scheme_t wifi_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,
.wifi_mode = WIFI_MODE_STA
};

View file

@ -0,0 +1,197 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <esp_log.h>
#include <esp_err.h>
#include <esp_wifi.h>
#include <mdns.h>
#include <protocomm.h>
#include <protocomm_httpd.h>
#include "wifi_provisioning/scheme_softap.h"
#include "wifi_provisioning_priv.h"
typedef struct softap_config {
protocomm_httpd_config_t httpd_config;
char ssid[33];
char password[65];
} wifi_prov_softap_config_t;
static const char *TAG = "wifi_prov_scheme_softap";
extern const wifi_prov_scheme_t wifi_prov_scheme_softap;
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,
},
};
strncpy((char *) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid));
wifi_config.ap.ssid_len = strnlen(ssid, sizeof(wifi_config.ap.ssid));
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(ESP_IF_WIFI_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;
}
wifi_prov_softap_config_t *softap_config = (wifi_prov_softap_config_t *) config;
protocomm_httpd_config_t *httpd_config = &softap_config->httpd_config;
/* 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;
}
/* Add mDNS service for allowing discovery of provisioning
* service on the SoftAP network (Optional). Even though
* this is an http service we identify it by _esp_wifi_prov so
* that application is free to use _http without conflict */
err = mdns_service_add("Wi-Fi Provisioning Service", "_esp_wifi_prov", "_tcp",
softap_config->httpd_config.data.config.port, NULL, 0);
if (err != ESP_OK) {
/* mDNS is not mandatory for provisioning to work,
* so print warning and return without failure */
ESP_LOGW(TAG, "Error adding mDNS service! Check if mDNS is running");
} else {
/* Information to identify the roles of the various
* protocomm endpoint URIs provided by the service */
err |= mdns_service_txt_item_set("_esp_wifi_prov", "_tcp", "version_endpoint", "/proto-ver");
err |= mdns_service_txt_item_set("_esp_wifi_prov", "_tcp", "session_endpoint", "/prov-session");
err |= mdns_service_txt_item_set("_esp_wifi_prov", "_tcp", "config_endpoint", "/prov-config");
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error adding mDNS service text item");
}
}
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");
}
mdns_service_remove("_esp_wifi_prov", "_tcp");
return err;
}
static void *new_config(void)
{
wifi_prov_softap_config_t *softap_config = calloc(1, sizeof(wifi_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;
}
wifi_prov_softap_config_t *softap_config = (wifi_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;
}
wifi_prov_softap_config_t *softap_config = (wifi_prov_softap_config_t *) config;
strlcpy(softap_config->ssid, service_name, sizeof(softap_config->ssid));
if (service_key) {
strlcpy(softap_config->password, service_key, sizeof(softap_config->password));
}
return ESP_OK;
}
static esp_err_t set_config_endpoint(void *config, const char *endpoint_name, uint16_t uuid)
{
return ESP_OK;
}
const wifi_prov_scheme_t wifi_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,
.wifi_mode = WIFI_MODE_APSTA
};

View file

@ -0,0 +1,104 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <esp_event_loop.h>
#include <protocomm.h>
#include <protocomm_security.h>
#include "wifi_provisioning/manager.h"
#include "wifi_provisioning/wifi_config.h"
#include "wifi_provisioning/wifi_scan.h"
/**
* @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
* wifi_prov_mgr_disable_auto_stop()
*
* @return
* - ESP_OK : Provisioning will be stopped
* - ESP_FAIL : Failed to stop provisioning
*/
esp_err_t wifi_prov_mgr_done(void);
/**
* @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 wifi_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 wifi_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 wifi_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 *wifi_prov_mgr_wifi_scan_result(uint16_t index);
/**
* @brief Get protocomm handlers for wifi_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_wifi_prov_handlers(wifi_prov_config_handlers_t *ptr);
/**
* @brief Get protocomm handlers for wifi_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_wifi_scan_handlers(wifi_prov_scan_handlers_t *ptr);

View file

@ -0,0 +1,297 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <esp_log.h>
#include <string.h>
#include <esp_err.h>
#include <esp_wifi.h>
#include "wifi_scan.pb-c.h"
#include <wifi_provisioning/wifi_scan.h>
static const char *TAG = "proto_wifi_scan";
typedef struct wifi_prov_scan_cmd {
int cmd_num;
esp_err_t (*command_handler)(WiFiScanPayload *req,
WiFiScanPayload *resp, void *priv_data);
} wifi_prov_scan_cmd_t;
static esp_err_t cmd_scan_start_handler(WiFiScanPayload *req,
WiFiScanPayload *resp,
void *priv_data);
static esp_err_t cmd_scan_status_handler(WiFiScanPayload *req,
WiFiScanPayload *resp,
void *priv_data);
static esp_err_t cmd_scan_result_handler(WiFiScanPayload *req,
WiFiScanPayload *resp,
void *priv_data);
static wifi_prov_scan_cmd_t cmd_table[] = {
{
.cmd_num = WI_FI_SCAN_MSG_TYPE__TypeCmdScanStart,
.command_handler = cmd_scan_start_handler
},
{
.cmd_num = WI_FI_SCAN_MSG_TYPE__TypeCmdScanStatus,
.command_handler = cmd_scan_status_handler
},
{
.cmd_num = WI_FI_SCAN_MSG_TYPE__TypeCmdScanResult,
.command_handler = cmd_scan_result_handler
}
};
static esp_err_t cmd_scan_start_handler(WiFiScanPayload *req,
WiFiScanPayload *resp, void *priv_data)
{
wifi_prov_scan_handlers_t *h = (wifi_prov_scan_handlers_t *) priv_data;
if (!h) {
ESP_LOGE(TAG, "Command invoked without handlers");
return ESP_ERR_INVALID_STATE;
}
RespScanStart *resp_payload = (RespScanStart *) malloc(sizeof(RespScanStart));
if (!resp_payload) {
ESP_LOGE(TAG, "Error allocating memory");
return ESP_ERR_NO_MEM;
}
resp_scan_start__init(resp_payload);
resp->status = (h->scan_start(req->cmd_scan_start->blocking,
req->cmd_scan_start->passive,
req->cmd_scan_start->group_channels,
req->cmd_scan_start->period_ms,
&h->ctx) == ESP_OK ?
STATUS__Success : STATUS__InternalError);
resp->payload_case = WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_START;
resp->resp_scan_start = resp_payload;
return ESP_OK;
}
static esp_err_t cmd_scan_status_handler(WiFiScanPayload *req,
WiFiScanPayload *resp, void *priv_data)
{
bool scan_finished = false;
uint16_t result_count = 0;
wifi_prov_scan_handlers_t *h = (wifi_prov_scan_handlers_t *) priv_data;
if (!h) {
ESP_LOGE(TAG, "Command invoked without handlers");
return ESP_ERR_INVALID_STATE;
}
RespScanStatus *resp_payload = (RespScanStatus *) malloc(sizeof(RespScanStatus));
if (!resp_payload) {
ESP_LOGE(TAG, "Error allocating memory");
return ESP_ERR_NO_MEM;
}
resp_scan_status__init(resp_payload);
resp->status = (h->scan_status(&scan_finished, &result_count, &h->ctx) == ESP_OK ?
STATUS__Success : STATUS__InternalError);
resp_payload->scan_finished = scan_finished;
resp_payload->result_count = result_count;
resp->payload_case = WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_STATUS;
resp->resp_scan_status = resp_payload;
return ESP_OK;
}
static esp_err_t cmd_scan_result_handler(WiFiScanPayload *req,
WiFiScanPayload *resp, void *priv_data)
{
esp_err_t err;
wifi_prov_scan_result_t scan_result = {{0}, {0}, 0, 0, 0};
WiFiScanResult **results = NULL;
wifi_prov_scan_handlers_t *h = (wifi_prov_scan_handlers_t *) priv_data;
if (!h) {
ESP_LOGE(TAG, "Command invoked without handlers");
return ESP_ERR_INVALID_STATE;
}
RespScanResult *resp_payload = (RespScanResult *) malloc(sizeof(RespScanResult));
if (!resp_payload) {
ESP_LOGE(TAG, "Error allocating memory");
return ESP_ERR_NO_MEM;
}
resp_scan_result__init(resp_payload);
resp->status = STATUS__Success;
resp->payload_case = WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_RESULT;
resp->resp_scan_result = resp_payload;
results = (WiFiScanResult **) calloc(req->cmd_scan_result->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 = req->cmd_scan_result->count;
for (uint16_t i = 0; i < req->cmd_scan_result->count; i++) {
err = h->scan_result(i + req->cmd_scan_result->start_index,
&scan_result, &h->ctx);
if (err != ESP_OK) {
resp->status = STATUS__InternalError;
break;
}
results[i] = (WiFiScanResult *) malloc(sizeof(WiFiScanResult));
if (!results[i]) {
ESP_LOGE(TAG, "Failed to allocate memory for result entry");
return ESP_ERR_NO_MEM;
}
wi_fi_scan_result__init(results[i]);
results[i]->ssid.len = strnlen(scan_result.ssid, 32);
results[i]->ssid.data = (uint8_t *) strndup(scan_result.ssid, 32);
if (!results[i]->ssid.data) {
ESP_LOGE(TAG, "Failed to allocate memory for scan result entry SSID");
return ESP_ERR_NO_MEM;
}
results[i]->channel = scan_result.channel;
results[i]->rssi = scan_result.rssi;
results[i]->auth = 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");
return ESP_ERR_NO_MEM;
}
memcpy(results[i]->bssid.data, scan_result.bssid, results[i]->bssid.len);
}
return ESP_OK;
}
static int lookup_cmd_handler(int cmd_id)
{
int i;
for (i = 0; i < sizeof(cmd_table)/sizeof(wifi_prov_scan_cmd_t); i++) {
if (cmd_table[i].cmd_num == cmd_id) {
return i;
}
}
return -1;
}
static void wifi_prov_scan_cmd_cleanup(WiFiScanPayload *resp, void *priv_data)
{
switch (resp->msg) {
case WI_FI_SCAN_MSG_TYPE__TypeRespScanStart:
{
free(resp->resp_scan_start);
}
break;
case WI_FI_SCAN_MSG_TYPE__TypeRespScanStatus:
{
free(resp->resp_scan_status);
}
break;
case WI_FI_SCAN_MSG_TYPE__TypeRespScanResult:
{
if (!resp->resp_scan_result) return;
if (resp->resp_scan_result->entries) {
for (uint16_t i = 0; i < resp->resp_scan_result->n_entries; i++) {
if (!resp->resp_scan_result->entries[i]) continue;
free(resp->resp_scan_result->entries[i]->ssid.data);
free(resp->resp_scan_result->entries[i]->bssid.data);
free(resp->resp_scan_result->entries[i]);
}
free(resp->resp_scan_result->entries);
}
free(resp->resp_scan_result);
}
break;
default:
ESP_LOGE(TAG, "Unsupported response type in cleanup_handler");
break;
}
return;
}
static esp_err_t wifi_prov_scan_cmd_dispatcher(WiFiScanPayload *req,
WiFiScanPayload *resp, void *priv_data)
{
esp_err_t ret;
ESP_LOGD(TAG, "In wifi_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;
}
esp_err_t wifi_prov_scan_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,
uint8_t **outbuf, ssize_t *outlen, void *priv_data)
{
WiFiScanPayload *req;
WiFiScanPayload resp;
esp_err_t ret = ESP_OK;
req = wi_fi_scan_payload__unpack(NULL, inlen, inbuf);
if (!req) {
ESP_LOGE(TAG, "Unable to unpack scan message");
return ESP_ERR_INVALID_ARG;
}
wi_fi_scan_payload__init(&resp);
ret = wifi_prov_scan_cmd_dispatcher(req, &resp, priv_data);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Command dispatcher error %d", ret);
ret = ESP_FAIL;
goto exit;
}
resp.msg = req->msg + 1; /* Response is request + 1 */
*outlen = wi_fi_scan_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;
}
wi_fi_scan_payload__pack(&resp, *outbuf);
ESP_LOGD(TAG, "Response packet size : %d", *outlen);
exit:
wi_fi_scan_payload__free_unpacked(req, NULL);
wifi_prov_scan_cmd_cleanup(&resp, priv_data);
return ret;
}

View file

@ -114,7 +114,12 @@ INPUT = \
../../components/protocomm/include/transports/protocomm_console.h \
../../components/protocomm/include/transports/protocomm_httpd.h \
## WiFi Provisioning
../../components/wifi_provisioning/include/wifi_provisioning/manager.h \
../../components/wifi_provisioning/include/wifi_provisioning/scheme_ble.h \
../../components/wifi_provisioning/include/wifi_provisioning/scheme_softap.h \
../../components/wifi_provisioning/include/wifi_provisioning/scheme_console.h \
../../components/wifi_provisioning/include/wifi_provisioning/wifi_config.h \
../../components/wifi_provisioning/include/wifi_provisioning/wifi_scan.h \
##
## Storage - API Reference
##

View file

@ -4,60 +4,316 @@ Wi-Fi Provisioning
Overview
--------
This component provides protocomm endpoint handler - `wifi_prov_config_data_handler` - and related protobuf framework which can be used for Wi-Fi configuration in the context of device provisioning, though it may be used in non-provisioning cases as well.
This component provides APIs that control Wi-Fi provisioning service for receiving and configuring Wi-Fi credentials over SoftAP or BLE transport via secure :doc:`Protocol Communication (protocomm)<protocomm>` sessions. The set of ``wifi_prov_mgr_`` APIs help in quickly implementing a provisioning service having necessary features with minimal amount of code and sufficient flexibility.
The configuration consists of three commands :
* `get_status` - For querying the Wi-Fi connection status
* `set_config` - For setting the Wi-Fi connection credentials
* `apply_config` - For applying the credentials saved during `set_config` and (re)start the Wi-Fi station
.. _wifi-prov-mgr-init:
The way this is supposed to work is that the desired Wi-Fi configuration for the ESP32, which is to run as a station and thus connect to an AP with certain credentials, is to be sent during `set_config`. Then `apply_config` is supposed to start (or restart) the Wi-Fi in station mode with the previously set AP credentials. Afterwords, `get_config` command is used to probe the device continuously for Wi-Fi connection status, to ensure that the connection was indeed successful. If the connection failed, then appropriate status code along with disconnection reason, is to be conveyed through `get_config`.
Initialization
^^^^^^^^^^^^^^
Application Example
-------------------
:cpp:func:`wifi_prov_mgr_init()` is called to configure and initialize the provisioning manager and thus this must be called prior to invoking any other ``wifi_prov_mgr_`` APIs. Note that the manager relies on other components of IDF, namely NVS, TCP/IP, Event Loop and Wi-Fi (and optionally mDNS), hence these must be initialized beforehand. The manager can be de-initialized at any moment by making a call to :cpp:func:`wifi_prov_mgr_deinit()`.
.. highlight:: c
::
esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi_prov_ctx_t **ctx)
{
/* Fill the wifi_prov_config_get_data_t structure
* with Wi-Fi station connection status information. */
return ESP_OK;
}
esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, wifi_prov_ctx_t **ctx)
{
/* Copy contents of req_data->ssid and req_data->password
* which are Wi-Fi AP credentials to which the device will connect */
return ESP_OK;
}
esp_err_t apply_config_handler(wifi_prov_ctx_t **ctx)
{
/* Apply the Wi-Fi STA credentials saved during set_config */
return ESP_OK;
}
/* Structure with various config command handlers to be passed
* as private data during endpoint registration with protocomm */
wifi_prov_config_handlers_t wifi_prov_handlers = {
.get_status_handler = get_status_handler,
.set_config_handler = set_config_handler,
.apply_config_handler = apply_config_handler,
.ctx = NULL
wifi_prov_mgr_config_t config = {
.scheme = wifi_prov_scheme_ble,
.scheme_event_handler = WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM,
.app_event_handler = {
.event_cb = prov_event_handler,
.user_data = NULL
}
};
/* Set the endpoint handler */
protocomm_add_endpoint(pc, "wifi_config_endpoint",
wifi_prov_config_data_handler,
(void *) &wifi_prov_handlers);
ESP_ERR_CHECK( wifi_prov_mgr_init(config) );
The configuration structure ``wifi_prov_mgr_config_t`` has a few fields to specify the behavior desired of the manager :
* `scheme` : This is used to specify the provisioning scheme. Each scheme corresponds to one of the modes of transport supported by protocomm. Hence, we have three options :
* ``wifi_prov_scheme_ble`` : BLE transport and GATT Server for handling provisioning commands
* ``wifi_prov_scheme_softap`` : Wi-Fi SoftAP transport and HTTP Server for handling provisioning commands
* ``wifi_prov_scheme_console`` : Serial transport and console for handling provisioning commands
* `scheme_event_handler` : An event handler defined along with scheme. Choosing appropriate scheme specific event handler allows the manager to take care of certain matters automatically. Presently this is not used for either SoftAP or Console based provisioning, but is very convenient for BLE. To understand how, we must recall that Bluetooth requires quite some amount of memory to function and once provisioning is finished, the main application may want to reclaim back this memory (or part of it, if it needs to use either BLE or classic BT). Also, upon every future reboot of a provisioned device, this reclamation of memory needs to be performed again. To reduce this complication in using ``wifi_prov_scheme_ble``, the scheme specific handlers have been defined, and depending upon the chosen handler, the BLE / classic BT / BTDM memory will be freed automatically when the provisioning manager is de-initialized. The available options are:
* ``WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM`` - Free both classic BT and BLE (BTDM) memory. Used when main application doesn't require Bluetooth at all.
* ``WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BLE`` - Free only BLE memory. Used when main application requires classic BT.
* ``WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BT`` - Free only classic BT. Used when main application requires BLE. In this case freeing happens right when the manager is initialized.
* ``WIFI_PROV_EVENT_HANDLER_NONE`` - Don't use any scheme specific handler. Used when provisioning scheme is not BLE (i.e. SoftAP or Console), or when main application wants to handle the memory reclaiming on its own, or needs both BLE and classic BT to function.
* `app_event_handler` : Application specific event handler which can be used to execute specific calls depending on the state of the provisioning service. This is to be set to a function of the form ``void app_event_handler(void *user_data, wifi_prov_cb_event_t event, void *event_data)`` along with any user data to be made available at the time of handling. This can also be set to ``WIFI_PROV_EVENT_HANDLER_NONE`` if not used. See definition of ``wifi_prov_cb_event_t`` for the list of events that are generated by the provisioning service. Following is a snippet showing a typical application specific provisioning event handler along with usage of the ``event_data`` parameter :
.. highlight:: c
::
void prov_event_handler(void *user_data,
wifi_prov_cb_event_t event,
void *event_data)
{
switch (event) {
case WIFI_PROV_INIT:
ESP_LOGI(TAG, "Manager initialized");
break;
case WIFI_PROV_START:
ESP_LOGI(TAG, "Provisioning started");
break;
case WIFI_PROV_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 WIFI_PROV_CRED_FAIL: {
wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data;
ESP_LOGE(TAG, "Provisioning failed : %s",
(*reason == WIFI_PROV_STA_AUTH_ERROR) ?
"Wi-Fi AP password incorrect" :
"Wi-Fi AP not found");
break;
}
case WIFI_PROV_CRED_SUCCESS:
ESP_LOGI(TAG, "Provisioning successful");
break;
case WIFI_PROV_END:
ESP_LOGI(TAG, "Provisioning stopped");
break;
case WIFI_PROV_DEINIT:
ESP_LOGI(TAG, "Manager de-initialized");
break;
default:
break;
}
}
.. _wifi-prov-check-state:
Check Provisioning State
^^^^^^^^^^^^^^^^^^^^^^^^
Whether device is provisioned or not can be checked at runtime by calling :cpp:func:`wifi_prov_mgr_is_provisioned()`. This internally checks if the Wi-Fi credentials are stored in NVS.
Note that presently manager does not have its own NVS namespace for storage of Wi-Fi credentials, instead it relies on the ``esp_wifi_`` APIs to set and get the credentials stored in NVS from the default location.
If provisioning state needs to be reset, any of the following approaches may be taken :
* the associated part of NVS partition has to be erased manually
* main application must implement some logic to call ``esp_wifi_`` APIs for erasing the credentials at runtime
* main application must implement some logic to force start the provisioning irrespective of the provisioning state
.. highlight:: c
::
bool provisioned = false;
ESP_ERR_CHECK( wifi_prov_mgr_is_provisioned(&provisioned) );
Event Loop Handling
^^^^^^^^^^^^^^^^^^^
Presently Wi-Fi provisioning manager cannot directly catch external system events, hence it is necessary to explicitly call :cpp:func:`wifi_prov_mgr_event_handler()` from inside the global event loop handler. See the following snippet :
.. highlight:: c
::
static esp_err_t global_event_loop_handler(void *ctx, system_event_t *event)
{
/* Pass event information to provisioning manager so that it can
* maintain its internal state depending upon the system event */
wifi_prov_mgr_event_handler(ctx, event);
/* Event handling logic for main application */
switch (event->event_id) {
.....
.....
.....
}
return ESP_OK;
}
Start Provisioning Service
^^^^^^^^^^^^^^^^^^^^^^^^^^
At the time of starting provisioning we need to specify a service name and the corresponding key. These translate to :
* Wi-Fi SoftAP SSID and passphrase, respectively, when scheme is ``wifi_prov_scheme_softap``
* BLE Device name (service key is ignored) when scheme is ``wifi_prov_scheme_ble``
Also, since internally the manager uses `protocomm`, we have the option of choosing one of the security features provided by it :
* Security 1 is secure communication which consists of a prior handshake involving X25519 key exchange along with authentication using a proof of possession (`pop`), followed by AES-CTR for encryption/decryption of subsequent messages
* Security 0 is simply plain text communication. In this case the `pop` is simply ignored
See :doc:`Provisioning<provisioning>` for details about the security features.
.. highlight:: c
::
const char *service_name = "my_device";
const char *service_key = "password";
wifi_prov_security_t security = WIFI_PROV_SECURITY_1;
const char *pop = "abcd1234";
ESP_ERR_CHECK( wifi_prov_mgr_start_provisioning(security, pop, service_name, service_key) );
The provisioning service will automatically finish only if it receives valid Wi-Fi AP credentials followed by successfully connection of device to the AP (IP obtained). Regardless of that, the provisioning service can be stopped at any moment by making a call to :cpp:func:`wifi_prov_mgr_stop_provisioning()`.
.. note::
If the device fails to connect with the provided credentials, it won't accept new credentials anymore, but the provisioning service will keep on running (only to convey failure to the client), until the device is restarted. Upon restart the provisioning state will turn out to be true this time (as credentials will be found in NVS), but device will again fail to connect with those same credentials (unless an AP with the matching credentials somehow does become available). This situation can be fixed by resetting the credentials in NVS or force starting the provisioning service. This has been explained above in :ref:`wifi-prov-check-state`.
Waiting For Completion
^^^^^^^^^^^^^^^^^^^^^^
Typically, the main application will wait for the provisioning to finish, then de-initialize the manager to free up resources and finally start executing its own logic.
There are two ways for making this possible. The simpler way is to use a blocking call to :cpp:func:`wifi_prov_mgr_wait()`.
.. highlight:: c
::
// Start provisioning service
ESP_ERR_CHECK( wifi_prov_mgr_start_provisioning(security, pop, service_name, service_key) );
// Wait for service to complete
wifi_prov_mgr_wait();
// Finally de-initialize the manager
wifi_prov_mgr_deinit();
The other way is to use the application specific event handler which is to be configured during initialization, as explained above in :ref:`wifi-prov-mgr-init`.
.. highlight:: c
::
void prov_event_handler(void *user_data, wifi_prov_cb_event_t event, void *event_data)
{
switch (event) {
case WIFI_PROV_END:
// De-initialize manager once provisioning is finished
wifi_prov_mgr_deinit();
break;
default:
break;
}
}
User Side Implementation
^^^^^^^^^^^^^^^^^^^^^^^^
When the service is started, the device to be provisioned is identified by the advertised service name which, depending upon the selected transport, is either the BLE device name or the SoftAP SSID.
When using SoftAP transport, for allowing service discovery, mDNS must be initialized before starting provisioning. In this case the hostname set by the main application is used, and the service type is internally set to `_esp_wifi_prov`.
When using BLE transport, a custom 128 bit UUID should be set using :cpp:func:`wifi_prov_scheme_ble_set_service_uuid()`. This UUID 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). Since, an endpoint characteristic UUID is auto assigned, it shouldn't be used to identify the endpoint. Instead, client side applications should identify the endpoints by reading the User Characteristic Description (0x2901) descriptor for each characteristic, which contains the endpoint name of the characteristic. For example, if the service UUID is set to `55cc035e-fb27-4f80-be02-3c60828b7451`, each endpoint characteristic will be assigned a UUID like `55cc____-fb27-4f80-be02-3c60828b7451`, with unique values at the 12th and 13th bytes.
Once connected to the device, the provisioning related protocomm endpoints can be identified as follows :
.. list-table:: Endpoints provided by Provisioning Service
:widths: 10 25 50
:header-rows: 1
* - Endpoint Name (BLE + GATT Server)
- URI (SoftAP + HTTP Server + mDNS)
- Description
* - prov-session
- http://<mdns-hostname>.local/prov-session
- Security endpoint used for session establishment
* - prov-scan
- http://wifi-prov.local/prov-scan
- Endpoint used for starting Wi-Fi scan and receiving scan results
* - prov-config
- http://<mdns-hostname>.local/prov-config
- Endpoint used for configuring Wi-Fi credentials on device
* - proto-ver
- http://<mdns-hostname>.local/proto-ver
- Endpoint for retrieving version info
Immediately after connecting, the client application may fetch the version / capabilities information from the `proto-ver` endpoint. All communications to this endpoint are un-encrypted, hence necessary information (that may be relevant for deciding compatibility) can be retrieved before establishing a secure session. The response is in JSON format and looks like : ``prov: { ver: v1.1, cap: [no_pop] }, my_app: { ver: 1.345, cap: [cloud, local_ctrl] },....``. Here label `prov` provides provisioning service version (`ver`) and capabilities (`cap`). For now, only `no_pop` capability is supported, which indicates that the service doesn't require proof of possession for authentication. Any application related version / capabilities will be given by other labels (like `my_app` in this example). These additional fields are set using :cpp:func:`wifi_prov_mgr_set_app_info()`.
User side applications need to implement the signature handshaking required for establishing and authenticating secure protocomm sessions as per the security scheme configured for use (this is not needed when manager is configured to use protocomm security 0).
See Unified Provisioning for more details about the secure handshake and encryption used. Applications must use the `.proto` files found under `components/protocomm/proto <https://github.com/espressif/esp-idf/components/protocomm/proto>`_, which define the Protobuf message structures supported by `prov-session` endpoint.
Once a session is established, Wi-Fi credentials are configured using the following set of `wifi_config` commands, serialized as Protobuf messages (the corresponding `.proto` files can be found under `components/wifi_provisioning/proto <https://github.com/espressif/esp-idf/components/wifi_provisioning/proto>`_) :
* `get_status` - For querying the Wi-Fi connection status. The device will respond with a status which will be one of connecting / connected / disconnected. If status is disconnected, a disconnection reason will also be included in the status response.
* `set_config` - For setting the Wi-Fi connection credentials
* `apply_config` - For applying the credentials saved during `set_config` and start the Wi-Fi station
After session establishment, client can also request Wi-Fi scan results from the device. The results returned is a list of AP SSIDs, sorted in descending order of signal strength. This allows client applications to display APs nearby to the device at the time of provisioning, and users can select one of the SSIDs and provide the password which is then sent using the `wifi_config` commands described above. The `wifi_scan` endpoint supports the following protobuf commands :
* `scan_start` - For starting Wi-Fi scan with various options :
* `blocking` (input) - If true, the command returns only when the scanning is finished
* `passive` (input) - If true scan is 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 atleast 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
* `scan_status` - Gives the status of scanning process :
* `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
* `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
Additional Endpoints
^^^^^^^^^^^^^^^^^^^^
In case users want to have some additional protocomm endpoints customized to their requirements, this is done in two steps. First is creation of an endpoint with a specific name, and the second step is the registration of a handler for this endpoint. See :doc:`protocomm<protocomm>` for the function signature of an endpoint handler. A custom endpoint must be created after initialization and before starting the provisioning service. Whereas, the protocomm handler is registered for this endpoint only after starting the provisioning service.
.. highlight:: c
::
wifi_prov_mgr_init(config);
wifi_prov_mgr_endpoint_create("custom-endpoint");
wifi_prov_mgr_start_provisioning(security, pop, service_name, service_key);
wifi_prov_mgr_endpoint_register("custom-endpoint", custom_ep_handler, custom_ep_data);
When the provisioning service stops, the endpoint is unregistered automatically.
One can also choose to call :cpp:func:`wifi_prov_mgr_endpoint_unregister()` to manually deactivate an endpoint at runtime. This can also be used to deactivate the internal endpoints used by the provisioning service.
When / How To Stop Provisioning Service?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The default behavior is that once the device successfully connects using the Wi-Fi credentials set by the `apply_config` command, the provisioning service will be stopped (and BLE / SoftAP turned off) automatically after responding to the next `get_status` command. If `get_status` command is not received by the device, the service will be stopped after a 30s timeout.
On the other hand, if device was not able to connect using the provided Wi-Fi credentials, due to incorrect SSID / passphrase, the service will keep running, and `get_status` will keep responding with disconnected status and reason for disconnection. Any further attempts to provide another set of Wi-Fi credentials, will be rejected. These credentials will be preserved, unless the provisioning service is force started, or NVS erased.
If this default behavior is not desired, it can be disabled by calling :cpp:func:`wifi_prov_mgr_disable_auto_stop()`. Now the provisioning service will only be stopped after an explicit call to :cpp:func:`wifi_prov_mgr_stop_provisioning()`, which returns immediately after scheduling a task for stopping the service. The service stops after a certain delay and WIFI_PROV_END event gets emitted. This delay is specified by the argument to :cpp:func:`wifi_prov_mgr_disable_auto_stop()`.
The customized behavior is useful for applications which want the provisioning service to be stopped some time after the Wi-Fi connection is successfully established. For example, if the application requires the device to connect to some cloud service and obtain another set of credentials, and exchange this credentials over a custom protocomm endpoint, then after sucessfully doing so stop the provisioning service by calling :cpp:func:`wifi_prov_mgr_stop_provisioning()` inside the protocomm handler itself. The right amount of delay ensures that the transport resources are freed only after the response from the protocomm handler reaches the client side application.
Application Examples
--------------------
For complete example implementation see :example:`provisioning/manager`
API Reference
-------------
.. include:: /_build/inc/manager.inc
.. include:: /_build/inc/scheme_ble.inc
.. include:: /_build/inc/scheme_softap.inc
.. include:: /_build/inc/scheme_console.inc
.. include:: /_build/inc/wifi_config.inc

View file

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

View file

@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := wifi_prov_mgr
include $(IDF_PATH)/make/project.mk

View file

@ -0,0 +1,217 @@
# Wi-Fi Provisioning Manager Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
`wifi_prov_mgr` example demonstrates the usage of `wifi_provisioning` manager component for building a provisioning application.
For this example BLE is chosen as the mode of transport, over which the provisioning related communication is to take place, between the device (to be provisioned) and the client (owner of the device).
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, BLE is turned off and disabled to free the memory used by the BLE stack. Though, that is specific to this example, and the user can choose to keep BLE stack intact in their own application.
`wifi_prov_mgr` uses the following components :
* `wifi_provisioning` : provides 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` : ESP32 BLE 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.
## How to use example
### Hardware Required
Example should be able to run on any commonly available ESP32 development board.
### Application Required
Provisioning applications are available for various platforms. See below
#### Platform : Android
For Android, a provisioning application along with source code is available on GitHub : [esp-idf-provisioning-android](https://github.com/espressif/esp-idf-provisioning-android)
#### Platform : iOS
For iOS, a provisioning application along with source code is available on GitHub : [esp-idf-provisioning-ios](https://github.com/espressif/esp-idf-provisioning-ios)
#### Platform : Linux / Windows / macOS
To provision the device running this example, the `esp_prov.py` script needs to be run (found under `$IDF_PATH/tools/esp_prov`). Make sure to satisfy all the dependencies prior to running the script.
Presently, `esp_prov` supports BLE transport only for Linux platform. For Windows/macOS it falls back to console mode and requires another application (for BLE) through which the communication can take place.
There are various applications, specific to Windows and macOS platform which can be used. The `esp_prov` console will guide you through the provisioning process of locating the correct BLE GATT services and characteristics, the values to write, and input read values.
### Configure the project
```
make menuconfig
```
* Set serial port under Serial Flasher Options.
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
make -j4 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) wifi_prov_mgr: Provisioning started with service name : PROV_261FCC
```
Make sure to note down the BLE device name (starting with `PROV_`) displayed in the serial monitor log (eg. PROV_261FCC). 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 `$IDP_PATH/tools/esp_prov` directory (please 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 :
```
python esp_prov.py --ssid myssid --passphrase mypassword --sec_ver 1 --pop abcd1234 --transport ble --ble_devname PROV_261FCC
```
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) tcpip_adapter: 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) wifi_prov_mgr: Provisioning stopped
.
.
.
I (52355) app: Hello World!
I (53355) app: Hello World!
I (54355) app: Hello World!
I (55355) app: Hello World!
```
## 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) wifi_prov_mgr: Found Wi-Fi SSID : myssid
D (465) wifi_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
```
### 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_261FCC` 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.

View file

@ -0,0 +1,4 @@
set(COMPONENT_SRCS "app_main.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
register_component()

View file

@ -0,0 +1,244 @@
/* 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_loop.h>
#include <nvs_flash.h>
#include <wifi_provisioning/manager.h>
#include <wifi_provisioning/scheme_ble.h>
#include <wifi_provisioning/scheme_softap.h>
static const char *TAG = "app";
/* Signal Wi-Fi events on this event-group */
const int WIFI_CONNECTED_EVENT = BIT0;
static EventGroupHandle_t wifi_event_group;
/* Event handler for catching system events */
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
/* Pass event information to provisioning manager so that it can
* maintain its internal state depending upon the system event */
wifi_prov_mgr_event_handler(ctx, event);
/* Global event handling */
switch (event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
ESP_LOGI(TAG, "Connected with IP Address:%s",
ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_EVENT);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
ESP_LOGI(TAG, "Disconnected. Connecting to the AP again...");
esp_wifi_connect();
break;
default:
break;
}
return ESP_OK;
}
/* Event handler for catching provisioning manager events */
static void prov_event_handler(void *user_data,
wifi_prov_cb_event_t event, void *event_data)
{
switch (event) {
case WIFI_PROV_START:
ESP_LOGI(TAG, "Provisioning started");
break;
case WIFI_PROV_CRED_RECV: {
wifi_sta_config_t *wifi_sta_cfg = (wifi_sta_config_t *)event_data;
/* If SSID length is exactly 32 bytes, null termination
* will not be present, so explicitly obtain the length */
size_t ssid_len = strnlen((const char *)wifi_sta_cfg->ssid, sizeof(wifi_sta_cfg->ssid));
ESP_LOGI(TAG, "Received Wi-Fi credentials"
"\n\tSSID : %.*s\n\tPassword : %s",
ssid_len, (const char *) wifi_sta_cfg->ssid,
(const char *) wifi_sta_cfg->password);
break;
}
case WIFI_PROV_CRED_FAIL: {
wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data;
ESP_LOGE(TAG, "Provisioning failed!\n\tReason : %s"
"\n\tPlease reset to factory and retry provisioning",
(*reason == WIFI_PROV_STA_AUTH_ERROR) ?
"Wi-Fi AP password incorrect" : "Wi-Fi AP not found");
break;
}
case WIFI_PROV_CRED_SUCCESS:
ESP_LOGI(TAG, "Provisioning successful");
break;
case WIFI_PROV_END:
/* De-initialize manager once provisioning is finished */
wifi_prov_mgr_deinit();
break;
default:
break;
}
}
static void wifi_init_sta()
{
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]);
}
void app_main()
{
/* 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 and the event loop */
tcpip_adapter_init();
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
wifi_event_group = xEventGroupCreate();
/* Initialize Wi-Fi */
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
/* Configuration for the provisioning manager */
wifi_prov_mgr_config_t config = {
/* What is the Provisioning Scheme that we want ?
* wifi_prov_scheme_softap or wifi_prov_scheme_ble */
.scheme = wifi_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. This can be set to
* WIFI_PROV_EVENT_HANDLER_NONE when using wifi_prov_scheme_softap*/
.scheme_event_handler = WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM,
/* Do we want an application specific handler be executed on
* various provisioning related events */
.app_event_handler = {
.event_cb = prov_event_handler,
.user_data = NULL
}
};
/* Initialize provisioning manager with the
* configuration parameters set above */
ESP_ERROR_CHECK(wifi_prov_mgr_init(config));
bool provisioned = false;
/* Let's find out if the device is provisioned */
ESP_ERROR_CHECK(wifi_prov_mgr_is_provisioned(&provisioned));
/* 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 wifi_prov_scheme_softap
* - device name when scheme is wifi_prov_scheme_ble
*/
char service_name[12];
get_device_service_name(service_name, sizeof(service_name));
/* What is the security level that we want (0 or 1):
* - WIFI_PROV_SECURITY_0 is simply plain text communication.
* - WIFI_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.
*/
wifi_prov_security_t security = WIFI_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";
/* What is the service key (could be NULL)
* This translates to :
* - Wi-Fi password when scheme is wifi_prov_scheme_softap
* - simply ignored when scheme is wifi_prov_scheme_ble
*/
const char *service_key = NULL;
/* This step is only useful when scheme is wifi_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 */
0x21, 0x43, 0x65, 0x87, 0x09, 0xba, 0xdc, 0xfe,
0xef, 0xcd, 0xab, 0x90, 0x78, 0x56, 0x34, 0x12
};
wifi_prov_scheme_ble_set_service_uuid(custom_service_uuid);
/* Start provisioning service */
ESP_ERROR_CHECK(wifi_prov_mgr_start_provisioning(security, pop, service_name, service_key));
/* 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 configured prov_event_handler(), we don't need to call the following */
// wifi_prov_mgr_wait();
// wifi_prov_mgr_deinit();
} 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 */
wifi_prov_mgr_deinit();
/* Start Wi-Fi station */
wifi_init_sta();
}
/* Wait for Wi-Fi connection */
xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_EVENT, false, true, portMAX_DELAY);
/* Start main application now */
while (1) {
ESP_LOGI(TAG, "Hello World!");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}

View file

@ -0,0 +1,8 @@
#
# Main component makefile.
#
# This Makefile can be left empty. By default, it will take the sources in the
# src/ directory, compile them and link them into lib(subdirectory_name).a
# in the build directory. This behaviour is entirely configurable,
# please read the ESP-IDF documents if you need to do this.
#

View file

@ -0,0 +1,5 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1200000,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1200000,

View file

@ -0,0 +1,10 @@
# Override some defaults so BT stack is enabled and
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CTRL_MODE_BTDM=
# Binary is larger than default size
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"

View file

@ -0,0 +1,123 @@
#!/usr/bin/env python
#
# Copyright 2018 Espressif Systems (Shanghai) PTE LTD
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import print_function
import re
import os
import sys
import time
try:
import IDF
except ImportError:
test_fw_path = os.getenv("TEST_FW_PATH")
if test_fw_path and test_fw_path not in sys.path:
sys.path.insert(0, test_fw_path)
import IDF
try:
import esp_prov
except ImportError:
esp_prov_path = os.getenv("IDF_PATH") + "/tools/esp_prov"
if esp_prov_path and esp_prov_path not in sys.path:
sys.path.insert(0, esp_prov_path)
import esp_prov
# Have esp_prov throw exception
esp_prov.config_throw_except = True
@IDF.idf_example_test(env_tag="Example_WIFI_BT")
def test_examples_wifi_prov_mgr(env, extra_data):
# Acquire DUT
dut1 = env.get_dut("wifi_prov_mgr", "examples/provisioning/manager")
# Get binary file
binary_file = os.path.join(dut1.app.binary_path, "wifi_prov_mgr.bin")
bin_size = os.path.getsize(binary_file)
IDF.log_performance("wifi_prov_mgr_bin_size", "{}KB".format(bin_size // 1024))
IDF.check_performance("wifi_prov_mgr_bin_size", bin_size // 1024)
# Upload binary and start testing
dut1.start_app()
# Check if BT memory is released before provisioning starts
dut1.expect("wifi_prov_scheme_ble: BT memory released", timeout=60)
# Parse BLE devname
devname = dut1.expect(re.compile(r"Provisioning started with service name : (PROV_\S\S\S\S\S\S)"), timeout=30)[0]
print("BLE Device Alias for DUT :", devname)
print("Starting Provisioning")
verbose = False
protover = "v1.1"
secver = 1
pop = "abcd1234"
provmode = "ble"
ap_ssid = "myssid"
ap_password = "mypassword"
print("Getting security")
security = esp_prov.get_security(secver, pop, verbose)
if security is None:
raise RuntimeError("Failed to get security")
print("Getting transport")
transport = esp_prov.get_transport(provmode, None, devname)
if transport is None:
raise RuntimeError("Failed to get transport")
print("Verifying protocol version")
if not esp_prov.version_match(transport, protover):
raise RuntimeError("Mismatch in protocol version")
print("Verifying scan list capability")
if not esp_prov.has_capability(transport, 'wifi_scan'):
raise RuntimeError("Capability not present")
print("Starting Session")
if not esp_prov.establish_session(transport, security):
raise RuntimeError("Failed to start session")
print("Sending Wifi credential to DUT")
if not esp_prov.send_wifi_config(transport, security, ap_ssid, ap_password):
raise RuntimeError("Failed to send Wi-Fi config")
print("Applying config")
if not esp_prov.apply_wifi_config(transport, security):
raise RuntimeError("Failed to send apply config")
success = False
while True:
time.sleep(5)
print("Wi-Fi connection state")
ret = esp_prov.get_wifi_config(transport, security)
if (ret == 1):
continue
elif (ret == 0):
print("Provisioning was successful")
success = True
break
if not success:
raise RuntimeError("Provisioning failed")
# Check if BTDM memory is released after provisioning finishes
dut1.expect("wifi_prov_scheme_ble: BTDM memory released", timeout=30)
if __name__ == '__main__':
test_examples_wifi_prov_mgr()

View file

@ -6,7 +6,7 @@
# SYNOPSIS
```
python esp_prov.py --transport < mode of provisioning : softap \ ble \ console > --ssid < AP SSID > --passphrase < AP Password > --sec_ver < Security version 0 / 1 > [ Optional parameters... ]
python esp_prov.py --transport < mode of provisioning : softap \ ble \ console > --sec_ver < Security version 0 / 1 > [ Optional parameters... ]
```
# DESCRIPTION
@ -18,8 +18,10 @@ Usage of `esp-prov` assumes that the provisioning app has specific protocomm end
| 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 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 |
| custom-config | http://ip:port/custom-config | Optional endpoint for configuring custom credentials |
# PARAMETERS
* `--help`
@ -37,11 +39,11 @@ Usage of `esp-prov` assumes that the provisioning app has specific protocomm end
* `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 device is accepting provisioning commands on UART console.
* `--ssid <AP SSID>`
For specifying the SSID of the Wi-Fi AP to which the device is to connect after provisioning
* `--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>`
For specifying the password of the Wi-Fi AP to which the device is to connect after provisioning
* `--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 `--ssid`
* `--sec_ver <Security version number>`
For specifying version of protocomm endpoint security to use. For now two versions are supported:
@ -51,9 +53,6 @@ Usage of `esp-prov` assumes that the provisioning app has specific protocomm end
* `--pop <Proof of possession string>` (Optional)
For specifying optional Proof of Possession string to use for protocomm endpoint security version 1. This option is ignored when security version 0 is in use
* `--proto_ver <Provisioning application version string>` (Optional) (Default `V0.1`)
For specifying version string for checking compatibility with provisioning app prior to starting provisioning process
* `--softap_endpoint <softap_ip:port>` (Optional) (Default `192.168.4.1:80`)
For specifying the IP and port of the HTTP server on which provisioning app is running. The client must connect to the device SoftAP prior to running `esp_prov`

View file

@ -16,10 +16,13 @@
#
from __future__ import print_function
from builtins import input
import argparse
import time
import os
import sys
import json
from getpass import getpass
try:
import security
@ -67,12 +70,10 @@ def get_transport(sel_transport, softap_endpoint=None, ble_devname=None):
# 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(devname=ble_devname,
service_uuid='0000ffff-0000-1000-8000-00805f9b34fb',
nu_lookup={'prov-session': 'ff51',
'prov-config': 'ff52',
'proto-ver': 'ff53'
})
nu_lookup=nu_lookup)
elif (sel_transport == 'console'):
tp = transport.Transport_Console()
return tp
@ -81,17 +82,57 @@ def get_transport(sel_transport, softap_endpoint=None, ble_devname=None):
return None
def version_match(tp, protover):
def version_match(tp, protover, verbose=False):
try:
response = tp.send_data('proto-ver', protover)
if response != protover:
return False
return True
except RuntimeError as e:
if verbose:
print("proto-ver response : ", response)
# First assume this to be a simple version string
if response.lower() == protover.lower():
return True
# 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
return False
except Exception as e:
on_except(e)
return None
def has_capability(tp, capability, verbose=False):
try:
response = tp.send_data('proto-ver', capability)
if verbose:
print("proto-ver response : ", response)
info = json.loads(response)
if capability in info['prov']['cap']:
return True
except Exception as e:
on_except(e)
return False
def get_version(tp):
response = None
try:
response = tp.send_data('proto-ver', '---')
except RuntimeError as e:
on_except(e)
response = ''
return response
def establish_session(tp, sec):
try:
response = None
@ -118,6 +159,56 @@ def custom_config(tp, sec, custom_info, custom_ver):
return None
def scan_wifi_APs(sel_transport, tp, sec):
APs = []
group_channels = 0
readlen = 100
if sel_transport == 'softap':
# In case of softAP 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(sec, blocking=True, group_channels=group_channels)
start_time = time.time()
response = 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(sec)
response = 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(sec, index, count)
response = 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
def send_wifi_config(tp, sec, ssid, passphrase):
try:
message = prov.config_set_config_request(sec, ssid, passphrase)
@ -132,7 +223,7 @@ def apply_wifi_config(tp, sec):
try:
message = prov.config_apply_config_request(sec)
response = tp.send_data('prov-config', message)
return (prov.config_set_config_response(sec, response) == 0)
return (prov.config_apply_config_response(sec, response) == 0)
except RuntimeError as e:
on_except(e)
return None
@ -152,14 +243,14 @@ if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Generate ESP prov payload")
parser.add_argument("--ssid", dest='ssid', type=str,
help="SSID of Wi-Fi Network", required=True)
help="SSID of Wi-Fi Network", default='')
parser.add_argument("--passphrase", dest='passphrase', type=str,
help="Passphrase of Wi-Fi network", default='')
parser.add_argument("--sec_ver", dest='secver', type=int,
help="Security scheme version", default=1)
help="Security scheme version", default=None)
parser.add_argument("--proto_ver", dest='protover', type=str,
help="Protocol version", default='V0.1')
help="Protocol version", default='')
parser.add_argument("--pop", dest='pop', type=str,
help="Proof of possession", default='')
@ -182,23 +273,38 @@ if __name__ == '__main__':
parser.add_argument("-v","--verbose", help="increase output verbosity", action="store_true")
args = parser.parse_args()
print("==== Esp_Prov Version: " + args.protover + " ====")
obj_security = get_security(args.secver, args.pop, args.verbose)
if obj_security is None:
print("---- Invalid Security Version ----")
exit(1)
if args.protover != '':
print("==== Esp_Prov Version: " + args.protover + " ====")
obj_transport = get_transport(args.provmode, args.softap_endpoint, args.ble_devname)
if obj_transport is None:
print("---- Invalid provisioning mode ----")
exit(1)
# If security version not specified check in capabilities
if args.secver is None:
# When no_sec is present, use security 0, else security 1
args.secver = int(not has_capability(obj_transport, 'no_sec'))
if (args.secver != 0) and not has_capability(obj_transport, 'no_pop'):
if len(args.pop) == 0:
print("---- Proof of Possession argument not provided ----")
exit(2)
elif len(args.pop) != 0:
print("---- Proof of Possession will be ignored ----")
args.pop = ''
obj_security = get_security(args.secver, args.pop, args.verbose)
if obj_security is None:
print("---- Invalid Security Version ----")
exit(2)
print("\n==== Verifying protocol version ====")
if not version_match(obj_transport, args.protover):
print("---- Error in protocol version matching ----")
exit(3)
print("==== Verified protocol version successfully ====")
if args.protover != '':
print("\n==== Verifying protocol version ====")
if not version_match(obj_transport, args.protover, args.verbose):
print("---- Error in protocol version matching ----")
exit(3)
print("==== Verified protocol version successfully ====")
print("\n==== Starting Session ====")
if not establish_session(obj_transport, obj_security):
@ -213,6 +319,49 @@ if __name__ == '__main__':
exit(5)
print("==== Custom config sent successfully ====")
if args.ssid == '':
if not has_capability(obj_transport, 'wifi_scan'):
print("---- Wi-Fi Scan List is not supported by provisioning service ----")
print("---- Rerun esp_prov with SSID and Passphrase as argument ----")
exit(3)
while True:
print("\n==== Scanning Wi-Fi APs ====")
start_time = time.time()
APs = scan_wifi_APs(args.provmode, obj_transport, obj_security)
end_time = time.time()
print("\n++++ Scan finished in " + str(end_time - start_time) + " sec")
if APs is None:
print("---- Error in scanning Wi-Fi APs ----")
exit(8)
if len(APs) == 0:
print("No APs found!")
exit(9)
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"]
prompt_str = "Enter passphrase for {0} : ".format(args.ssid)
args.passphrase = getpass(prompt_str)
print("\n==== Sending Wi-Fi credential to esp32 ====")
if not send_wifi_config(obj_transport, obj_security, args.ssid, args.passphrase):
print("---- Error in send Wi-Fi config ----")

View file

@ -37,6 +37,7 @@ session_pb2 = _load_source("session_pb2", idf_path + "/components/protocomm/
# wifi_provisioning component related python files generated from .proto files
wifi_constants_pb2 = _load_source("wifi_constants_pb2", idf_path + "/components/wifi_provisioning/python/wifi_constants_pb2.py")
wifi_config_pb2 = _load_source("wifi_config_pb2", idf_path + "/components/wifi_provisioning/python/wifi_config_pb2.py")
wifi_scan_pb2 = _load_source("wifi_scan_pb2", idf_path + "/components/wifi_provisioning/python/wifi_scan_pb2.py")
# custom_provisioning component related python files generated from .proto files
custom_config_pb2 = _load_source("custom_config_pb2", idf_path +

View file

@ -15,3 +15,4 @@
from .wifi_prov import * # noqa F403
from .custom_prov import * # noqa F403
from .wifi_scan import * # noqa F403

View file

@ -0,0 +1,105 @@
# Copyright 2018 Espressif Systems (Shanghai) PTE LTD
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# APIs for interpreting and creating protobuf packets for Wi-Fi Scanning
from __future__ import print_function
from future.utils import tobytes
import utils
import proto
def print_verbose(security_ctx, data):
if (security_ctx.verbose):
print("++++ " + data + " ++++")
def scan_start_request(security_ctx, blocking=True, passive=False, group_channels=5, period_ms=120):
# Form protobuf request packet for ScanStart command
cmd = proto.wifi_scan_pb2.WiFiScanPayload()
cmd.msg = proto.wifi_scan_pb2.TypeCmdScanStart
cmd.cmd_scan_start.blocking = blocking
cmd.cmd_scan_start.passive = passive
cmd.cmd_scan_start.group_channels = group_channels
cmd.cmd_scan_start.period_ms = period_ms
enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString()).decode('latin-1')
print_verbose(security_ctx, "Client -> Device (Encrypted CmdScanStart) " + utils.str_to_hexstr(enc_cmd))
return enc_cmd
def scan_start_response(security_ctx, response_data):
# Interpret protobuf response packet from ScanStart command
dec_resp = security_ctx.decrypt_data(tobytes(response_data))
resp = proto.wifi_scan_pb2.WiFiScanPayload()
resp.ParseFromString(dec_resp)
print_verbose(security_ctx, "ScanStart status " + str(resp.status))
if resp.status != 0:
raise RuntimeError
def scan_status_request(security_ctx):
# Form protobuf request packet for ScanStatus command
cmd = proto.wifi_scan_pb2.WiFiScanPayload()
cmd.msg = proto.wifi_scan_pb2.TypeCmdScanStatus
enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString()).decode('latin-1')
print_verbose(security_ctx, "Client -> Device (Encrypted CmdScanStatus) " + utils.str_to_hexstr(enc_cmd))
return enc_cmd
def scan_status_response(security_ctx, response_data):
# Interpret protobuf response packet from ScanStatus command
dec_resp = security_ctx.decrypt_data(tobytes(response_data))
resp = proto.wifi_scan_pb2.WiFiScanPayload()
resp.ParseFromString(dec_resp)
print_verbose(security_ctx, "ScanStatus status " + str(resp.status))
if resp.status != 0:
raise RuntimeError
return {"finished": resp.resp_scan_status.scan_finished, "count": resp.resp_scan_status.result_count}
def scan_result_request(security_ctx, index, count):
# Form protobuf request packet for ScanResult command
cmd = proto.wifi_scan_pb2.WiFiScanPayload()
cmd.msg = proto.wifi_scan_pb2.TypeCmdScanResult
cmd.cmd_scan_result.start_index = index
cmd.cmd_scan_result.count = count
enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString()).decode('latin-1')
print_verbose(security_ctx, "Client -> Device (Encrypted CmdScanResult) " + utils.str_to_hexstr(enc_cmd))
return enc_cmd
def scan_result_response(security_ctx, response_data):
# Interpret protobuf response packet from ScanResult command
dec_resp = security_ctx.decrypt_data(tobytes(response_data))
resp = proto.wifi_scan_pb2.WiFiScanPayload()
resp.ParseFromString(dec_resp)
print_verbose(security_ctx, "ScanResult status " + str(resp.status))
if resp.status != 0:
raise RuntimeError
authmode_str = ["Open", "WEP", "WPA_PSK", "WPA2_PSK", "WPA_WPA2_PSK", "WPA2_ENTERPRISE"]
results = []
for entry in resp.resp_scan_result.entries:
results += [{"ssid": entry.ssid.decode('latin-1').rstrip('\x00'),
"bssid": utils.str_to_hexstr(entry.bssid.decode('latin-1')),
"channel": entry.channel,
"rssi": entry.rssi,
"auth": authmode_str[entry.auth]}]
print_verbose(security_ctx, "ScanResult SSID : " + str(results[-1]["ssid"]))
print_verbose(security_ctx, "ScanResult BSSID : " + str(results[-1]["bssid"]))
print_verbose(security_ctx, "ScanResult Channel : " + str(results[-1]["channel"]))
print_verbose(security_ctx, "ScanResult RSSI : " + str(results[-1]["rssi"]))
print_verbose(security_ctx, "ScanResult AUTH : " + str(results[-1]["auth"]))
return results