|
|
@@ -1,389 +0,0 @@
|
|
|
-/* BLE based Provisioning 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 <string.h>
|
|
|
-#include <esp_log.h>
|
|
|
-#include <esp_err.h>
|
|
|
-#include <esp_wifi.h>
|
|
|
-#include <nvs_flash.h>
|
|
|
-#include <nvs.h>
|
|
|
-#include <esp_bt.h>
|
|
|
-#include <esp_event.h>
|
|
|
-#include <esp_timer.h>
|
|
|
-
|
|
|
-#ifdef CONFIG_BT_NIMBLE_ENABLED
|
|
|
-#include "esp_nimble_hci.h"
|
|
|
-#include "nimble/nimble_port.h"
|
|
|
-#include "nimble/nimble_port_freertos.h"
|
|
|
-#include "host/ble_hs.h"
|
|
|
-#endif
|
|
|
-
|
|
|
-#include <protocomm.h>
|
|
|
-#include <protocomm_ble.h>
|
|
|
-#include <protocomm_security0.h>
|
|
|
-#include <protocomm_security1.h>
|
|
|
-#include <wifi_provisioning/wifi_config.h>
|
|
|
-
|
|
|
-#include "app_prov.h"
|
|
|
-
|
|
|
-static const char *TAG = "app_prov";
|
|
|
-static const char *ssid_prefix = "PROV_";
|
|
|
-
|
|
|
-/* Handler for catching WiFi events */
|
|
|
-static void app_prov_event_handler(void* handler_arg, esp_event_base_t base, int32_t id, void* data);
|
|
|
-
|
|
|
-/* Handlers for wifi_config provisioning endpoint */
|
|
|
-extern wifi_prov_config_handlers_t wifi_prov_handlers;
|
|
|
-
|
|
|
-/**
|
|
|
- * @brief Data relevant to provisioning application
|
|
|
- */
|
|
|
-struct app_prov_data {
|
|
|
- protocomm_t *pc; /*!< Protocomm handler */
|
|
|
- int security; /*!< Type of security to use with protocomm */
|
|
|
- const protocomm_security_pop_t *pop; /*!< Pointer to proof of possession */
|
|
|
- esp_timer_handle_t timer; /*!< Handle to timer */
|
|
|
-
|
|
|
- /* State of WiFi Station */
|
|
|
- wifi_prov_sta_state_t wifi_state;
|
|
|
-
|
|
|
- /* Code for WiFi station disconnection (if disconnected) */
|
|
|
- wifi_prov_sta_fail_reason_t wifi_disconnect_reason;
|
|
|
-};
|
|
|
-
|
|
|
-/* Pointer to provisioning application data */
|
|
|
-static struct app_prov_data *g_prov;
|
|
|
-
|
|
|
-static esp_err_t app_prov_start_service(void)
|
|
|
-{
|
|
|
- /* Create new protocomm instance */
|
|
|
- g_prov->pc = protocomm_new();
|
|
|
- if (g_prov->pc == NULL) {
|
|
|
- ESP_LOGE(TAG, "Failed to create new protocomm instance");
|
|
|
- return ESP_FAIL;
|
|
|
- }
|
|
|
-
|
|
|
- /* Endpoint UUIDs */
|
|
|
- protocomm_ble_name_uuid_t nu_lookup_table[] = {
|
|
|
- {"prov-session", 0x0001},
|
|
|
- {"prov-config", 0x0002},
|
|
|
- {"proto-ver", 0x0003},
|
|
|
- };
|
|
|
-
|
|
|
- /* Config for protocomm_ble_start() */
|
|
|
- protocomm_ble_config_t config = {
|
|
|
- .service_uuid = {
|
|
|
- /* LSB <---------------------------------------
|
|
|
- * ---------------------------------------> MSB */
|
|
|
- 0xb4, 0xdf, 0x5a, 0x1c, 0x3f, 0x6b, 0xf4, 0xbf,
|
|
|
- 0xea, 0x4a, 0x82, 0x03, 0x04, 0x90, 0x1a, 0x02,
|
|
|
- },
|
|
|
- .nu_lookup_count = sizeof(nu_lookup_table)/sizeof(nu_lookup_table[0]),
|
|
|
- .nu_lookup = nu_lookup_table
|
|
|
- };
|
|
|
-
|
|
|
- /* With the above selection of 128bit primary service UUID and
|
|
|
- * 16bit endpoint UUIDs, the 128bit characteristic UUIDs will be
|
|
|
- * formed by replacing the 12th and 13th bytes of the service UUID
|
|
|
- * with the 16bit endpoint UUID, i.e. :
|
|
|
- * service UUID : 021a9004-0382-4aea-bff4-6b3f1c5adfb4
|
|
|
- * masked base : 021a____-0382-4aea-bff4-6b3f1c5adfb4
|
|
|
- * ------------------------------------------------------
|
|
|
- * resulting characteristic UUIDs :
|
|
|
- * 1) prov-session : 021a0001-0382-4aea-bff4-6b3f1c5adfb4
|
|
|
- * 2) prov-config : 021a0002-0382-4aea-bff4-6b3f1c5adfb4
|
|
|
- * 3) proto-ver : 021a0003-0382-4aea-bff4-6b3f1c5adfb4
|
|
|
- *
|
|
|
- * Also, note that each endpoint (characteristic) will have
|
|
|
- * an associated "Characteristic User Description" descriptor
|
|
|
- * with 16bit UUID 0x2901, each containing the corresponding
|
|
|
- * endpoint name. These descriptors can be used by a client
|
|
|
- * side application to figure out which characteristic is
|
|
|
- * mapped to which endpoint, without having to hardcode the
|
|
|
- * UUIDs */
|
|
|
-
|
|
|
- uint8_t eth_mac[6];
|
|
|
- esp_wifi_get_mac(WIFI_IF_STA, eth_mac);
|
|
|
- snprintf(config.device_name, sizeof(config.device_name), "%s%02X%02X%02X",
|
|
|
- ssid_prefix, eth_mac[3], eth_mac[4], eth_mac[5]);
|
|
|
-
|
|
|
- /* Release BT memory, as we need only BLE */
|
|
|
- esp_err_t err = esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
|
|
- if (err) {
|
|
|
- ESP_LOGE(TAG, "bt_controller_mem_release failed %d", err);
|
|
|
- if (err != ESP_ERR_INVALID_STATE) {
|
|
|
- return err;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* Start protocomm layer on top of BLE */
|
|
|
- if (protocomm_ble_start(g_prov->pc, &config) != ESP_OK) {
|
|
|
- ESP_LOGE(TAG, "Failed to start BLE provisioning");
|
|
|
- return ESP_FAIL;
|
|
|
- }
|
|
|
-
|
|
|
- /* Set protocomm version verification endpoint for protocol */
|
|
|
- protocomm_set_version(g_prov->pc, "proto-ver", "V0.1");
|
|
|
-
|
|
|
- /* Set protocomm security type for endpoint */
|
|
|
- if (g_prov->security == 0) {
|
|
|
- protocomm_set_security(g_prov->pc, "prov-session", &protocomm_security0, NULL);
|
|
|
- } else if (g_prov->security == 1) {
|
|
|
- protocomm_set_security(g_prov->pc, "prov-session", &protocomm_security1, g_prov->pop);
|
|
|
- }
|
|
|
-
|
|
|
- /* Add endpoint for provisioning to set wifi station config */
|
|
|
- if (protocomm_add_endpoint(g_prov->pc, "prov-config",
|
|
|
- wifi_prov_config_data_handler,
|
|
|
- (void *) &wifi_prov_handlers) != ESP_OK) {
|
|
|
- ESP_LOGE(TAG, "Failed to set provisioning endpoint");
|
|
|
- protocomm_ble_stop(g_prov->pc);
|
|
|
- return ESP_FAIL;
|
|
|
- }
|
|
|
-
|
|
|
- ESP_LOGI(TAG, "Provisioning started with BLE devname : '%s'", config.device_name);
|
|
|
- return ESP_OK;
|
|
|
-}
|
|
|
-
|
|
|
-static void app_prov_stop_service(void)
|
|
|
-{
|
|
|
- /* Remove provisioning endpoint */
|
|
|
- protocomm_remove_endpoint(g_prov->pc, "prov-config");
|
|
|
- /* Unset provisioning security */
|
|
|
- protocomm_unset_security(g_prov->pc, "prov-session");
|
|
|
- /* Unset provisioning version endpoint */
|
|
|
- protocomm_unset_version(g_prov->pc, "proto-ver");
|
|
|
- /* Stop protocomm ble service */
|
|
|
- protocomm_ble_stop(g_prov->pc);
|
|
|
- /* Delete protocomm instance */
|
|
|
- protocomm_delete(g_prov->pc);
|
|
|
-
|
|
|
- /* Remove event handler */
|
|
|
- esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, app_prov_event_handler);
|
|
|
- esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, app_prov_event_handler);
|
|
|
-
|
|
|
- /* Release memory used by BT stack */
|
|
|
- esp_bt_mem_release(ESP_BT_MODE_BTDM);
|
|
|
-}
|
|
|
-
|
|
|
-/* Task spawned by timer callback */
|
|
|
-static void stop_prov_task(void * arg)
|
|
|
-{
|
|
|
- ESP_LOGI(TAG, "Stopping provisioning");
|
|
|
- app_prov_stop_service();
|
|
|
-
|
|
|
- /* Timer not needed anymore */
|
|
|
- esp_timer_handle_t timer = g_prov->timer;
|
|
|
- esp_timer_delete(timer);
|
|
|
- g_prov->timer = NULL;
|
|
|
-
|
|
|
- /* Free provisioning process data */
|
|
|
- free(g_prov);
|
|
|
- g_prov = NULL;
|
|
|
- ESP_LOGI(TAG, "Provisioning stopped");
|
|
|
-
|
|
|
- vTaskDelete(NULL);
|
|
|
-}
|
|
|
-
|
|
|
-/* Callback to be invoked by timer */
|
|
|
-static void _stop_prov_cb(void * arg)
|
|
|
-{
|
|
|
- xTaskCreate(&stop_prov_task, "stop_prov", 2048, NULL, tskIDLE_PRIORITY, NULL);
|
|
|
-}
|
|
|
-
|
|
|
-/* Event handler for starting/stopping provisioning */
|
|
|
-static void app_prov_event_handler(void* handler_arg, esp_event_base_t event_base,
|
|
|
- int32_t event_id, void* event_data)
|
|
|
-{
|
|
|
- /* If pointer to provisioning application data is NULL
|
|
|
- * then provisioning is not running */
|
|
|
- if (!g_prov) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
|
|
- ESP_LOGI(TAG, "STA Start");
|
|
|
- /* Once configuration is received through protocomm,
|
|
|
- * device is started as station. Once station starts,
|
|
|
- * wait for connection to establish with configured
|
|
|
- * host SSID and password */
|
|
|
- g_prov->wifi_state = WIFI_PROV_STA_CONNECTING;
|
|
|
- } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
|
|
- ESP_LOGI(TAG, "STA Got IP");
|
|
|
- /* Station got IP. That means configuration is successful.
|
|
|
- * Schedule timer to stop provisioning app after 30 seconds. */
|
|
|
- g_prov->wifi_state = WIFI_PROV_STA_CONNECTED;
|
|
|
- if (g_prov && g_prov->timer) {
|
|
|
- esp_timer_start_once(g_prov->timer, 30000*1000U);
|
|
|
- }
|
|
|
- } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
|
|
- ESP_LOGE(TAG, "STA Disconnected");
|
|
|
- /* Station couldn't connect to configured host SSID */
|
|
|
- g_prov->wifi_state = WIFI_PROV_STA_DISCONNECTED;
|
|
|
-
|
|
|
- wifi_event_sta_disconnected_t* disconnected = (wifi_event_sta_disconnected_t*) event_data;
|
|
|
- ESP_LOGE(TAG, "Disconnect reason : %d", disconnected->reason);
|
|
|
-
|
|
|
- /* Set code corresponding to the reason for disconnection */
|
|
|
- switch (disconnected->reason) {
|
|
|
- case WIFI_REASON_AUTH_EXPIRE:
|
|
|
- case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT:
|
|
|
- case WIFI_REASON_BEACON_TIMEOUT:
|
|
|
- case WIFI_REASON_AUTH_FAIL:
|
|
|
- case WIFI_REASON_ASSOC_FAIL:
|
|
|
- case WIFI_REASON_HANDSHAKE_TIMEOUT:
|
|
|
- ESP_LOGI(TAG, "STA Auth Error");
|
|
|
- g_prov->wifi_disconnect_reason = WIFI_PROV_STA_AUTH_ERROR;
|
|
|
- break;
|
|
|
- case WIFI_REASON_NO_AP_FOUND:
|
|
|
- ESP_LOGI(TAG, "STA AP Not found");
|
|
|
- g_prov->wifi_disconnect_reason = WIFI_PROV_STA_AP_NOT_FOUND;
|
|
|
- break;
|
|
|
- default:
|
|
|
- /* If none of the expected reasons,
|
|
|
- * retry connecting to host SSID */
|
|
|
- g_prov->wifi_state = WIFI_PROV_STA_CONNECTING;
|
|
|
- }
|
|
|
- esp_wifi_connect();
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-esp_err_t app_prov_get_wifi_state(wifi_prov_sta_state_t* state)
|
|
|
-{
|
|
|
- if (g_prov == NULL || state == NULL) {
|
|
|
- return ESP_FAIL;
|
|
|
- }
|
|
|
-
|
|
|
- *state = g_prov->wifi_state;
|
|
|
- return ESP_OK;
|
|
|
-}
|
|
|
-
|
|
|
-esp_err_t app_prov_get_wifi_disconnect_reason(wifi_prov_sta_fail_reason_t* reason)
|
|
|
-{
|
|
|
- if (g_prov == NULL || reason == NULL) {
|
|
|
- return ESP_FAIL;
|
|
|
- }
|
|
|
-
|
|
|
- if (g_prov->wifi_state != WIFI_PROV_STA_DISCONNECTED) {
|
|
|
- return ESP_FAIL;
|
|
|
- }
|
|
|
-
|
|
|
- *reason = g_prov->wifi_disconnect_reason;
|
|
|
- return ESP_OK;
|
|
|
-}
|
|
|
-
|
|
|
-esp_err_t app_prov_is_provisioned(bool *provisioned)
|
|
|
-{
|
|
|
- *provisioned = false;
|
|
|
-
|
|
|
-#ifdef CONFIG_EXAMPLE_RESET_PROVISIONED
|
|
|
- esp_wifi_restore();
|
|
|
- return ESP_OK;
|
|
|
-#endif
|
|
|
-
|
|
|
- /* Get WiFi Station configuration */
|
|
|
- wifi_config_t wifi_cfg;
|
|
|
- if (esp_wifi_get_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK) {
|
|
|
- return ESP_FAIL;
|
|
|
- }
|
|
|
-
|
|
|
- if (strlen((const char*) wifi_cfg.sta.ssid)) {
|
|
|
- *provisioned = true;
|
|
|
- ESP_LOGI(TAG, "Found ssid %s", (const char*) wifi_cfg.sta.ssid);
|
|
|
- ESP_LOGI(TAG, "Found password %s", (const char*) wifi_cfg.sta.password);
|
|
|
- }
|
|
|
- return ESP_OK;
|
|
|
-}
|
|
|
-
|
|
|
-esp_err_t app_prov_configure_sta(wifi_config_t *wifi_cfg)
|
|
|
-{
|
|
|
- /* Configure WiFi as station */
|
|
|
- if (esp_wifi_set_mode(WIFI_MODE_STA) != ESP_OK) {
|
|
|
- ESP_LOGE(TAG, "Failed to set WiFi mode");
|
|
|
- return ESP_FAIL;
|
|
|
- }
|
|
|
- /* Configure WiFi station with host credentials
|
|
|
- * provided during provisioning */
|
|
|
- if (esp_wifi_set_config(WIFI_IF_STA, wifi_cfg) != ESP_OK) {
|
|
|
- ESP_LOGE(TAG, "Failed to set WiFi configuration");
|
|
|
- return ESP_FAIL;
|
|
|
- }
|
|
|
- /* Start WiFi */
|
|
|
- if (esp_wifi_start() != ESP_OK) {
|
|
|
- ESP_LOGE(TAG, "Failed to set WiFi configuration");
|
|
|
- return ESP_FAIL;
|
|
|
- }
|
|
|
- /* Connect to AP */
|
|
|
- if (esp_wifi_connect() != ESP_OK) {
|
|
|
- ESP_LOGE(TAG, "Failed to connect WiFi");
|
|
|
- return ESP_FAIL;
|
|
|
- }
|
|
|
-
|
|
|
- if (g_prov) {
|
|
|
- /* Reset wifi station state for provisioning app */
|
|
|
- g_prov->wifi_state = WIFI_PROV_STA_CONNECTING;
|
|
|
- }
|
|
|
- return ESP_OK;
|
|
|
-}
|
|
|
-
|
|
|
-esp_err_t app_prov_start_ble_provisioning(int security, const protocomm_security_pop_t *pop)
|
|
|
-{
|
|
|
- /* If provisioning app data present,
|
|
|
- * means provisioning app is already running */
|
|
|
- if (g_prov) {
|
|
|
- ESP_LOGI(TAG, "Invalid provisioning state");
|
|
|
- return ESP_FAIL;
|
|
|
- }
|
|
|
-
|
|
|
- /* Allocate memory for provisioning app data */
|
|
|
- g_prov = (struct app_prov_data *) calloc(1, sizeof(struct app_prov_data));
|
|
|
- if (!g_prov) {
|
|
|
- ESP_LOGI(TAG, "Unable to allocate prov data");
|
|
|
- return ESP_ERR_NO_MEM;
|
|
|
- }
|
|
|
-
|
|
|
- /* Initialize app data */
|
|
|
- g_prov->pop = pop;
|
|
|
- g_prov->security = security;
|
|
|
-
|
|
|
- /* Create timer object as a member of app data */
|
|
|
- esp_timer_create_args_t timer_conf = {
|
|
|
- .callback = _stop_prov_cb,
|
|
|
- .arg = NULL,
|
|
|
- .dispatch_method = ESP_TIMER_TASK,
|
|
|
- .name = "stop_ble_tm"
|
|
|
- };
|
|
|
- esp_err_t err = esp_timer_create(&timer_conf, &g_prov->timer);
|
|
|
- if (err != ESP_OK) {
|
|
|
- ESP_LOGE(TAG, "Failed to create timer");
|
|
|
- return err;
|
|
|
- }
|
|
|
-
|
|
|
- err = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, app_prov_event_handler, NULL);
|
|
|
- if (err != ESP_OK) {
|
|
|
- ESP_LOGE(TAG, "Failed to register WiFi event handler");
|
|
|
- return err;
|
|
|
- }
|
|
|
-
|
|
|
- err = esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, app_prov_event_handler, NULL);
|
|
|
- if (err != ESP_OK) {
|
|
|
- ESP_LOGE(TAG, "Failed to register IP event handler");
|
|
|
- return err;
|
|
|
- }
|
|
|
-
|
|
|
- /* Start provisioning service through BLE */
|
|
|
- err = app_prov_start_service();
|
|
|
- if (err != ESP_OK) {
|
|
|
- ESP_LOGE(TAG, "Provisioning failed to start");
|
|
|
- return err;
|
|
|
- }
|
|
|
-
|
|
|
- ESP_LOGI(TAG, "BLE Provisioning started");
|
|
|
- return ESP_OK;
|
|
|
-}
|