wifi_provisioning : Wi-Fi Provisioning Manager added

This commit is contained in:
Anurag Kar 2019-04-16 17:14:10 +05:30
parent 550b1897c8
commit 4ef6c85f0c
12 changed files with 2555 additions and 4 deletions

View File

@ -1,10 +1,21 @@
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/manager.c"
"src/handlers.c"
"src/scheme_softap.c"
"src/scheme_console.c"
"proto-c/wifi_config.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_BT_BLUEDROID_ENABLED)
list(APPEND COMPONENT_SRCS
"src/scheme_ble.c")
endif()
endif()
register_component()

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_BT_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,146 @@
// 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/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;
}
wifi_prov_config_handlers_t get_wifi_prov_handlers(void)
{
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
};
return wifi_prov_handlers;
}

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,202 @@
// 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;
}
/* Start Wi-Fi in AP mode with configuration built above */
esp_err_t err = esp_wifi_set_mode(WIFI_MODE_AP);
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;
}
err = esp_wifi_start();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to start Wi-Fi : %d", err);
return err;
}
ESP_LOGD(TAG, "Wi-Fi SoftAP started");
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,44 @@
// 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"
/**
* @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 Get protocomm handlers for wifi_config provisioning endpoint
*
* @return wifi_prov_config_handlers_t structure
*/
wifi_prov_config_handlers_t get_wifi_prov_handlers(void);