1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
35
36
37
38
39
40
41
50
51
54
55
59
60
61
62
63
64
65
66
68
69
70
71
75
79
80
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
185
186
187
191
192
196
197
198
199
202
203
204
205
206
207
208
209
210
213
214
218
219
220
221
222
223
226
227
228
229
230
231
232
233
234
235
236
241
242
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
294
295
296
301
302
303
304
309
310
311
312
313
314
315
316
322
323
324
352
358
359
360
361
367
368
369
370
371
372
379
380
381
382
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
481
482
483
484
485
486
491
496
497
498
499
500
501
502
506
507
508
509
510
511
512
515
516
517
520
521
522
523
524
525
529
530
531
532
533
536
537
538
539
540
541
542
543
544
549
550
551
552
553
554
555
556
558
563
564
565
566
567
568
569
570
571
572
573
574
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
596
597
598
599
600
603
604
605
606
609
612
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
658
659
663
664
665
670
671
676
677
678
679
680
681
690
691
692
696
697
700
701
702
703
704
705
706
707
725
726
727
728
729
733
734
741
742
743
744
748
749
750
751
752
759
760
761
762
763
764
765
766
767
771
772
773
774
777
778
779
780
783
784
785
786
787
788
791
792
793
794
795
796
797
802
803
807
808
813
814
815
816
821
825
826
827
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
866
867
868
869
870
876
877
878
882
883
886
887
888
889
890
895
896
897
898
899
900
901
902
903
904
905
909
910
911
912
915
919
920
921
922
923
926
927
929
933
934
942
943
944
945
946
947
949
954
955
956
957
958
975
976
978
979
980
981
982
983
984
985
1005
1009
1010
1013
1014
1015
1016
1017
1018
1019
1020
1024
1025
1026
1031
1032
1037
1038
1039
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1055
1056
1057
1058
1059
1066
1067
1072
1073
1074
1075
1076
1077
1078
1079
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1103
1104
1105
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1123
1124
1125
1130
1131
1137
1138
1139
1140
1141
1142
1143
1144
1148
1149
1150
1155
1156
1159
1160
1161
1162
1163
1164
1165
1169
1170
1171
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1188
1189
1190
1194
1195
1196
1197
1198
1199
1200
1201
1202
1206
1207
1208
1212
1213
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1234
1235
1236
1237
1238
1241
1242
1243
1244
1245
1246
1249
1250
1254
1255
1256
1257
1261
1262
1268
1269
1270
1271
1275
1276
1277
1282
1283
1284
1285
1290
1291
1292
1293
1298
1299
1303
1304
1306
1311
1313
1318
1320
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1366
1367
1368
1373
1374
1375
1376
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1395
1396
1397
1401
1402
1403
1407
1408
1409
1413
1414
1415
1419
1420
1421
1425
1426
1428
1429
1430
1432
1433
1434
1435
1443
1444
1445
1446
1447
1448
1449
1453
1454
1464
1465
1466
1467
1468
1469
1473
1474
1475
1476
1482
1483
1484
1486
1487
1488
1489
1490
1491
1492
1493
1494
1497
1498
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1516
1528
1529
1530
1531
1532
1535
1538
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1555
1556
1557
1562
1563
1568
1569
1570
1573
1574
1575
1577
1578
1582
1583
1587
1588
1592
1593
1594
1595
1596
1600
1601
1602
1603
1606
1607
1611
1612
1613
1614
1615
1619
1620
1621
1626
1627
1628
1629
1630
1631
1632
1637
1638
1639
1640
1643
1644
1645
1646
1652
1653
1654
1655
1661
1662
1666
1667
1668
1683
1684
1690
1691
1697
1698
1699
1703
1704
1705
1706
1707
1712
1713
1719
1720
1721
1722
1726
1727
1731
1732
1733
1734
1735
1736
1737
1741
1742
1743
1744
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1763
1764
1765
1766
1767
1768
1769
1773
1774
1775
1776
1777
1782
1783
1784
1785
1786
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1804
1805
1806
1807
1808
1809
1810
1811
1816
1817
1818
1822
1823
1824
1825
1829
1830
1831
1835
1836
1837
1838
1839
1840
1843
1844
1845
/* ... */
#include <string.h>
#include <sys/param.h>
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#include <freertos/task.h>
#include <cJSON.h>
#include <esp_log.h>
#include <esp_err.h>
#include <esp_wifi.h>
#include <esp_timer.h>
#include <protocomm.h>
#include <protocomm_security0.h>
#include <protocomm_security1.h>
#include <protocomm_security2.h>
#include "wifi_provisioning_priv.h"15 includes
#define WIFI_PROV_MGR_VERSION "v1.1"
#define WIFI_PROV_STORAGE_BIT BIT0
#define WIFI_PROV_SETTING_BIT BIT1
#define MAX_SCAN_RESULTS CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES
#define ACQUIRE_LOCK(mux) assert(xSemaphoreTake(mux, portMAX_DELAY) == pdTRUE)
#define RELEASE_LOCK(mux) assert(xSemaphoreGive(mux) == pdTRUE)6 defines
static const char *TAG = "wifi_prov_mgr";
ESP_EVENT_DEFINE_BASE(WIFI_PROV_EVENT);
ESP_EVENT_DEFINE_BASE(WIFI_PROV_MGR_PVT_EVENT);
typedef enum {
WIFI_PROV_STATE_IDLE,
WIFI_PROV_STATE_STARTING,
WIFI_PROV_STATE_STARTED,
WIFI_PROV_STATE_CRED_RECV,
WIFI_PROV_STATE_FAIL,
WIFI_PROV_STATE_SUCCESS,
WIFI_PROV_STATE_STOPPING
}{ ... } wifi_prov_mgr_state_t;
typedef enum {
WIFI_PROV_MGR_STOP,
}{ ... } wifi_prov_mgr_pvt_event_t;
/* ... */
struct wifi_prov_capabilities {
bool no_sec;
bool no_pop;
/* ... */
bool no_auto_stop;
}{ ... };
/* ... */
struct wifi_prov_info {
const char *version;
struct wifi_prov_capabilities capabilities;
}{ ... };
/* ... */
struct wifi_prov_mgr_ctx {
wifi_prov_mgr_config_t mgr_config;
wifi_prov_mgr_state_t prov_state;
void *prov_scheme_config;
protocomm_t *pc;
int security;
const void* protocomm_sec_params;
esp_timer_handle_t autostop_timer;
esp_timer_handle_t wifi_connect_timer;
esp_timer_handle_t cleanup_delay_timer;
wifi_prov_sta_state_t wifi_state;
wifi_prov_sta_fail_reason_t wifi_disconnect_reason;
wifi_prov_config_handlers_t *wifi_prov_handlers;
wifi_prov_scan_handlers_t *wifi_scan_handlers;
wifi_ctrl_handlers_t *wifi_ctrl_handlers;
unsigned int endpoint_uuid_used;
struct wifi_prov_info mgr_info;
cJSON *app_info_json;
/* ... */
uint32_t cleanup_delay;
bool scanning;
uint8_t channels_per_group;
uint16_t curr_channel;
uint16_t ap_list_len[14];
wifi_ap_record_t *ap_list[14];
wifi_ap_record_t *ap_list_sorted[MAX_SCAN_RESULTS];
wifi_scan_config_t scan_cfg;
uint32_t connection_attempts_completed;
}{ ... };
/* ... */
static SemaphoreHandle_t prov_ctx_lock = NULL;
static struct wifi_prov_mgr_ctx *prov_ctx;
/* ... */
static void execute_event_cb(wifi_prov_cb_event_t event_id, void *event_data, size_t event_data_size)
{
ESP_LOGD(TAG, "execute_event_cb : %d", event_id);
if (prov_ctx) {
wifi_prov_cb_func_t app_cb = prov_ctx->mgr_config.app_event_handler.event_cb;
void *app_data = prov_ctx->mgr_config.app_event_handler.user_data;
wifi_prov_cb_func_t scheme_cb = prov_ctx->mgr_config.scheme_event_handler.event_cb;
void *scheme_data = prov_ctx->mgr_config.scheme_event_handler.user_data;
/* ... */
RELEASE_LOCK(prov_ctx_lock);
if (scheme_cb) {
scheme_cb(scheme_data, event_id, event_data);
}{...}
if (app_cb) {
app_cb(app_data, event_id, event_data);
}{...}
if (esp_event_post(WIFI_PROV_EVENT, event_id,
event_data, event_data_size,
portMAX_DELAY) != ESP_OK) {
ESP_LOGE(TAG, "Failed to post event %d to default event loop", event_id);
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
}{...}
}{ ... }
esp_err_t wifi_prov_mgr_set_app_info(const char *label, const char *version,
const char**capabilities, size_t total_capabilities)
{
if (!label || !version || !capabilities) {
return ESP_ERR_INVALID_ARG;
}{...}
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return ESP_ERR_INVALID_STATE;
}{...}
esp_err_t ret = ESP_FAIL;
ACQUIRE_LOCK(prov_ctx_lock);
if (prov_ctx && prov_ctx->prov_state == WIFI_PROV_STATE_IDLE) {
if (!prov_ctx->app_info_json) {
prov_ctx->app_info_json = cJSON_CreateObject();
}{...}
cJSON *new_entry_json = cJSON_CreateObject();
cJSON *capabilities_json = cJSON_CreateArray();
cJSON_AddItemToObject(prov_ctx->app_info_json, label, new_entry_json);
cJSON_AddStringToObject(new_entry_json, "ver", version);
cJSON_AddItemToObject(new_entry_json, "cap", capabilities_json);
for (unsigned int i = 0; i < total_capabilities; i++) {
if (capabilities[i]) {
cJSON_AddItemToArray(capabilities_json, cJSON_CreateString(capabilities[i]));
}{...}
}{...}
ret = ESP_OK;
}{...} else {
ret = ESP_ERR_INVALID_STATE;
}{...}
RELEASE_LOCK(prov_ctx_lock);
return ret;
}{ ... }
static cJSON* wifi_prov_get_info_json(void)
{
cJSON *full_info_json = prov_ctx->app_info_json ?
cJSON_Duplicate(prov_ctx->app_info_json, 1) : cJSON_CreateObject();
cJSON *prov_info_json = cJSON_CreateObject();
cJSON *prov_capabilities = cJSON_CreateArray();
cJSON_AddItemToObject(full_info_json, "prov", prov_info_json);
cJSON_AddStringToObject(prov_info_json, "ver", prov_ctx->mgr_info.version);
cJSON_AddNumberToObject(prov_info_json, "sec_ver", prov_ctx->security);
cJSON_AddItemToObject(prov_info_json, "cap", prov_capabilities);
if (prov_ctx->mgr_info.capabilities.no_sec) {
cJSON_AddItemToArray(prov_capabilities, cJSON_CreateString("no_sec"));
}{...} else if (prov_ctx->mgr_info.capabilities.no_pop) {
cJSON_AddItemToArray(prov_capabilities, cJSON_CreateString("no_pop"));
}{...}
cJSON_AddItemToArray(prov_capabilities, cJSON_CreateString("wifi_scan"));
return full_info_json;
}{ ... }
static void wifi_prov_mgr_event_handler_internal(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data);
static esp_err_t wifi_prov_mgr_start_service(const char *service_name, const char *service_key)
{
const wifi_prov_scheme_t *scheme = &prov_ctx->mgr_config.scheme;
esp_err_t ret;
prov_ctx->pc = protocomm_new();
if (prov_ctx->pc == NULL) {
ESP_LOGE(TAG, "Failed to create new protocomm instance");
return ESP_FAIL;
}{...}
ret = scheme->set_config_service(prov_ctx->prov_scheme_config, service_name, service_key);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to configure service");
protocomm_delete(prov_ctx->pc);
return ret;
}{...}
ret = scheme->prov_start(prov_ctx->pc, prov_ctx->prov_scheme_config);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to start service");
protocomm_delete(prov_ctx->pc);
return ret;
}{...}
cJSON *version_json = wifi_prov_get_info_json();
char *version_str = cJSON_Print(version_json);
ret = protocomm_set_version(prov_ctx->pc, "proto-ver", version_str);
free(version_str);
cJSON_Delete(version_json);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set version endpoint");
scheme->prov_stop(prov_ctx->pc);
protocomm_delete(prov_ctx->pc);
return ret;
}{...}
if (prov_ctx->security == 0) {
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0
ret = protocomm_set_security(prov_ctx->pc, "prov-session",
&protocomm_security0, NULL);/* ... */
#else
return ESP_ERR_NOT_SUPPORTED;/* ... */
#endif
}{...} else if (prov_ctx->security == 1) {
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1
ret = protocomm_set_security(prov_ctx->pc, "prov-session",
&protocomm_security1, prov_ctx->protocomm_sec_params);/* ... */
#else
return ESP_ERR_NOT_SUPPORTED;/* ... */
#endif
}{...} else if (prov_ctx->security == 2) {
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2
ret = protocomm_set_security(prov_ctx->pc, "prov-session",
&protocomm_security2, prov_ctx->protocomm_sec_params);/* ... */
#else
return ESP_ERR_NOT_SUPPORTED;/* ... */
#endif
}{...} else {
ESP_LOGE(TAG, "Unsupported protocomm security version %d", prov_ctx->security);
ret = ESP_ERR_INVALID_ARG;
}{...}
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set security endpoint");
scheme->prov_stop(prov_ctx->pc);
protocomm_delete(prov_ctx->pc);
return ret;
}{...}
prov_ctx->wifi_prov_handlers = malloc(sizeof(wifi_prov_config_handlers_t));
ret = get_wifi_prov_handlers(prov_ctx->wifi_prov_handlers);
if (ret != ESP_OK) {
ESP_LOGD(TAG, "Failed to allocate memory for provisioning handlers");
scheme->prov_stop(prov_ctx->pc);
protocomm_delete(prov_ctx->pc);
return ESP_ERR_NO_MEM;
}{...}
ret = protocomm_add_endpoint(prov_ctx->pc, "prov-config",
wifi_prov_config_data_handler,
prov_ctx->wifi_prov_handlers);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set provisioning endpoint");
free(prov_ctx->wifi_prov_handlers);
scheme->prov_stop(prov_ctx->pc);
protocomm_delete(prov_ctx->pc);
return ret;
}{...}
prov_ctx->wifi_scan_handlers = malloc(sizeof(wifi_prov_scan_handlers_t));
ret = get_wifi_scan_handlers(prov_ctx->wifi_scan_handlers);
if (ret != ESP_OK) {
ESP_LOGD(TAG, "Failed to allocate memory for Wi-Fi scan handlers");
free(prov_ctx->wifi_prov_handlers);
scheme->prov_stop(prov_ctx->pc);
protocomm_delete(prov_ctx->pc);
return ESP_ERR_NO_MEM;
}{...}
ret = protocomm_add_endpoint(prov_ctx->pc, "prov-scan",
wifi_prov_scan_handler,
prov_ctx->wifi_scan_handlers);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set Wi-Fi scan endpoint");
free(prov_ctx->wifi_scan_handlers);
free(prov_ctx->wifi_prov_handlers);
scheme->prov_stop(prov_ctx->pc);
protocomm_delete(prov_ctx->pc);
return ret;
}{...}
prov_ctx->wifi_ctrl_handlers = malloc(sizeof(wifi_ctrl_handlers_t));
ret = get_wifi_ctrl_handlers(prov_ctx->wifi_ctrl_handlers);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to allocate memory for Wi-Fi ctrl handlers");
free(prov_ctx->wifi_prov_handlers);
scheme->prov_stop(prov_ctx->pc);
protocomm_delete(prov_ctx->pc);
return ESP_ERR_NO_MEM;
}{...}
ret = protocomm_add_endpoint(prov_ctx->pc, "prov-ctrl",
wifi_ctrl_handler,
prov_ctx->wifi_ctrl_handlers);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set Wi-Fi ctrl endpoint");
free(prov_ctx->wifi_ctrl_handlers);
free(prov_ctx->wifi_prov_handlers);
scheme->prov_stop(prov_ctx->pc);
protocomm_delete(prov_ctx->pc);
return ret;
}{...}
ret = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID,
wifi_prov_mgr_event_handler_internal, NULL);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to register WiFi event handler");
free(prov_ctx->wifi_scan_handlers);
free(prov_ctx->wifi_ctrl_handlers);
free(prov_ctx->wifi_prov_handlers);
scheme->prov_stop(prov_ctx->pc);
protocomm_delete(prov_ctx->pc);
return ret;
}{...}
ret = esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
wifi_prov_mgr_event_handler_internal, NULL);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to register IP event handler");
esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID,
wifi_prov_mgr_event_handler_internal);
free(prov_ctx->wifi_scan_handlers);
free(prov_ctx->wifi_ctrl_handlers);
free(prov_ctx->wifi_prov_handlers);
scheme->prov_stop(prov_ctx->pc);
protocomm_delete(prov_ctx->pc);
return ret;
}{...}
ret = esp_event_handler_register(WIFI_PROV_MGR_PVT_EVENT, WIFI_PROV_MGR_STOP,
wifi_prov_mgr_event_handler_internal, NULL);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to register provisioning event handler");
esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID,
wifi_prov_mgr_event_handler_internal);
esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP,
wifi_prov_mgr_event_handler_internal);
free(prov_ctx->wifi_scan_handlers);
free(prov_ctx->wifi_ctrl_handlers);
free(prov_ctx->wifi_prov_handlers);
scheme->prov_stop(prov_ctx->pc);
protocomm_delete(prov_ctx->pc);
return ret;
}{...}
ESP_LOGI(TAG, "Provisioning started with service name : %s ",
service_name ? service_name : "<NULL>");
return ESP_OK;
}{ ... }
esp_err_t wifi_prov_mgr_endpoint_create(const char *ep_name)
{
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return ESP_ERR_INVALID_STATE;
}{...}
esp_err_t err = ESP_FAIL;
ACQUIRE_LOCK(prov_ctx_lock);
if (prov_ctx &&
prov_ctx->prov_state == WIFI_PROV_STATE_IDLE) {
err = prov_ctx->mgr_config.scheme.set_config_endpoint(
prov_ctx->prov_scheme_config, ep_name,
prov_ctx->endpoint_uuid_used + 1);
}{...}
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to create additional endpoint");
}{...} else {
prov_ctx->endpoint_uuid_used++;
}{...}
RELEASE_LOCK(prov_ctx_lock);
return err;
}{ ... }
esp_err_t wifi_prov_mgr_endpoint_register(const char *ep_name, protocomm_req_handler_t handler, void *user_ctx)
{
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return ESP_ERR_INVALID_STATE;
}{...}
esp_err_t err = ESP_FAIL;
ACQUIRE_LOCK(prov_ctx_lock);
if (prov_ctx &&
prov_ctx->prov_state > WIFI_PROV_STATE_STARTING &&
prov_ctx->prov_state < WIFI_PROV_STATE_STOPPING) {
err = protocomm_add_endpoint(prov_ctx->pc, ep_name, handler, user_ctx);
}{...}
RELEASE_LOCK(prov_ctx_lock);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to register handler for endpoint");
}{...}
return err;
}{ ... }
void wifi_prov_mgr_endpoint_unregister(const char *ep_name)
{
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return;
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
if (prov_ctx &&
prov_ctx->prov_state > WIFI_PROV_STATE_STARTING &&
prov_ctx->prov_state < WIFI_PROV_STATE_STOPPING) {
protocomm_remove_endpoint(prov_ctx->pc, ep_name);
}{...}
RELEASE_LOCK(prov_ctx_lock);
}{ ... }
static void prov_stop_and_notify(bool is_async)
{
esp_event_handler_unregister(WIFI_PROV_MGR_PVT_EVENT, WIFI_PROV_MGR_STOP,
wifi_prov_mgr_event_handler_internal);
if (prov_ctx->cleanup_delay_timer) {
esp_timer_stop(prov_ctx->cleanup_delay_timer);
esp_timer_delete(prov_ctx->cleanup_delay_timer);
prov_ctx->cleanup_delay_timer = NULL;
}{...}
wifi_prov_cb_func_t app_cb = prov_ctx->mgr_config.app_event_handler.event_cb;
void *app_data = prov_ctx->mgr_config.app_event_handler.user_data;
wifi_prov_cb_func_t scheme_cb = prov_ctx->mgr_config.scheme_event_handler.event_cb;
void *scheme_data = prov_ctx->mgr_config.scheme_event_handler.user_data;
/* ... */
if (!is_async)
{
uint32_t cleanup_delay = prov_ctx->cleanup_delay > 100 ? prov_ctx->cleanup_delay : 100;
vTaskDelay(cleanup_delay / portTICK_PERIOD_MS);
}{...}
protocomm_remove_endpoint(prov_ctx->pc, "prov-ctrl");
protocomm_remove_endpoint(prov_ctx->pc, "prov-scan");
protocomm_remove_endpoint(prov_ctx->pc, "prov-config");
protocomm_unset_security(prov_ctx->pc, "prov-session");
protocomm_unset_version(prov_ctx->pc, "proto-ver");
/* ... */
prov_ctx->mgr_config.scheme.prov_stop(prov_ctx->pc);
protocomm_delete(prov_ctx->pc);
prov_ctx->pc = NULL;
free(prov_ctx->wifi_prov_handlers->ctx);
free(prov_ctx->wifi_prov_handlers);
prov_ctx->wifi_prov_handlers = NULL;
free(prov_ctx->wifi_scan_handlers->ctx);
free(prov_ctx->wifi_scan_handlers);
prov_ctx->wifi_scan_handlers = NULL;
free(prov_ctx->wifi_ctrl_handlers);
prov_ctx->wifi_ctrl_handlers = NULL;
/* ... */
esp_wifi_set_mode(WIFI_MODE_STA);
ESP_LOGI(TAG, "Provisioning stopped");
if (is_async) {
/* ... */
prov_ctx->prov_state = WIFI_PROV_STATE_IDLE;
ESP_LOGD(TAG, "execute_event_cb : %d", WIFI_PROV_END);
if (scheme_cb) {
scheme_cb(scheme_data, WIFI_PROV_END, NULL);
}{...}
if (app_cb) {
app_cb(app_data, WIFI_PROV_END, NULL);
}{...}
if (esp_event_post(WIFI_PROV_EVENT, WIFI_PROV_END, NULL, 0, portMAX_DELAY) != ESP_OK) {
ESP_LOGE(TAG, "Failed to post event WIFI_PROV_END");
}{...}
}{...}
}{ ... }
/* ... */
static bool wifi_prov_mgr_stop_service(bool blocking)
{
if (blocking) {
/* ... */
while (prov_ctx && (
prov_ctx->prov_state == WIFI_PROV_STATE_STARTING ||
prov_ctx->prov_state == WIFI_PROV_STATE_STOPPING)) {
RELEASE_LOCK(prov_ctx_lock);
vTaskDelay(100 / portTICK_PERIOD_MS);
ACQUIRE_LOCK(prov_ctx_lock);
}{...}
}{...} else {
/* ... */
while (prov_ctx &&
prov_ctx->prov_state == WIFI_PROV_STATE_STARTING) {
RELEASE_LOCK(prov_ctx_lock);
vTaskDelay(100 / portTICK_PERIOD_MS);
ACQUIRE_LOCK(prov_ctx_lock);
}{...}
if (prov_ctx && prov_ctx->prov_state == WIFI_PROV_STATE_STOPPING) {
ESP_LOGD(TAG, "Provisioning is already stopping");
return false;
}{...}
}{...}
if (!prov_ctx || prov_ctx->prov_state == WIFI_PROV_STATE_IDLE) {
ESP_LOGD(TAG, "Provisioning not running");
return false;
}{...}
if (prov_ctx->autostop_timer) {
esp_timer_stop(prov_ctx->autostop_timer);
esp_timer_delete(prov_ctx->autostop_timer);
prov_ctx->autostop_timer = NULL;
}{...}
if (prov_ctx->wifi_connect_timer) {
esp_timer_stop(prov_ctx->wifi_connect_timer);
esp_timer_delete(prov_ctx->wifi_connect_timer);
prov_ctx->wifi_connect_timer = NULL;
}{...}
ESP_LOGD(TAG, "Stopping provisioning");
prov_ctx->prov_state = WIFI_PROV_STATE_STOPPING;
if (prov_ctx->protocomm_sec_params) {
if (prov_ctx->security == 1) {
uint8_t *pop = (uint8_t *)((protocomm_security1_params_t *) prov_ctx->protocomm_sec_params)->data;
free(pop);
}{...}
prov_ctx->protocomm_sec_params = NULL;
}{...}
for (uint16_t channel = 0; channel < 14; channel++) {
free(prov_ctx->ap_list[channel]);
prov_ctx->ap_list[channel] = NULL;
}{...}
prov_ctx->scanning = false;
for (uint8_t i = 0; i < MAX_SCAN_RESULTS; i++) {
prov_ctx->ap_list_sorted[i] = NULL;
}{...}
esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID,
wifi_prov_mgr_event_handler_internal);
esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP,
wifi_prov_mgr_event_handler_internal);
if (blocking) {
/* ... */
RELEASE_LOCK(prov_ctx_lock);
prov_stop_and_notify(false);
ACQUIRE_LOCK(prov_ctx_lock);
prov_ctx->prov_state = WIFI_PROV_STATE_IDLE;
}{...} else {
/* ... */
uint64_t cleanup_delay_ms = prov_ctx->cleanup_delay > 100 ? prov_ctx->cleanup_delay : 100;
esp_timer_start_once(prov_ctx->cleanup_delay_timer, cleanup_delay_ms * 1000U);
ESP_LOGD(TAG, "Provisioning scheduled for stopping");
}{...}
return true;
}{ ... }
static void stop_prov_timer_cb(void *arg)
{
wifi_prov_mgr_stop_provisioning();
}{ ... }
static void cleanup_delay_timer_cb(void *arg)
{
esp_err_t ret = esp_event_post(WIFI_PROV_MGR_PVT_EVENT, WIFI_PROV_MGR_STOP, NULL, 0, pdMS_TO_TICKS(100));
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to post WIFI_PROV_MGR_STOP event! %d %s", ret, esp_err_to_name(ret));
}{...}
}{ ... }
esp_err_t wifi_prov_mgr_disable_auto_stop(uint32_t cleanup_delay)
{
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return ESP_ERR_INVALID_STATE;
}{...}
esp_err_t ret = ESP_FAIL;
ACQUIRE_LOCK(prov_ctx_lock);
if (prov_ctx && prov_ctx->prov_state == WIFI_PROV_STATE_IDLE) {
prov_ctx->mgr_info.capabilities.no_auto_stop = true;
prov_ctx->cleanup_delay = cleanup_delay;
ret = ESP_OK;
}{...} else {
ret = ESP_ERR_INVALID_STATE;
}{...}
RELEASE_LOCK(prov_ctx_lock);
return ret;
}{ ... }
esp_err_t wifi_prov_mgr_done(void)
{
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return ESP_ERR_INVALID_STATE;
}{...}
bool auto_stop_enabled = false;
ACQUIRE_LOCK(prov_ctx_lock);
if (prov_ctx && !prov_ctx->mgr_info.capabilities.no_auto_stop) {
auto_stop_enabled = true;
}{...}
RELEASE_LOCK(prov_ctx_lock);
if (auto_stop_enabled) {
wifi_prov_mgr_stop_provisioning();
}{...}
return ESP_OK;
}{ ... }
static esp_err_t update_wifi_scan_results(void)
{
if (!prov_ctx->scanning) {
return ESP_ERR_INVALID_STATE;
}{...}
ESP_LOGD(TAG, "Scan finished");
esp_err_t ret = ESP_FAIL;
uint16_t count = 0;
uint16_t curr_channel = prov_ctx->curr_channel;
if (prov_ctx->ap_list[curr_channel]) {
free(prov_ctx->ap_list[curr_channel]);
prov_ctx->ap_list[curr_channel] = NULL;
prov_ctx->ap_list_len[curr_channel] = 0;
}{...}
if (esp_wifi_scan_get_ap_num(&count) != ESP_OK) {
ESP_LOGE(TAG, "Failed to get count of scanned APs");
goto exit;
}{...}
if (!count) {
ESP_LOGD(TAG, "Scan result empty");
ret = ESP_OK;
goto exit;
}{...}
uint16_t get_count = MIN(count, MAX_SCAN_RESULTS);
prov_ctx->ap_list[curr_channel] = (wifi_ap_record_t *) calloc(get_count, sizeof(wifi_ap_record_t));
if (!prov_ctx->ap_list[curr_channel]) {
ESP_LOGE(TAG, "Failed to allocate memory for AP list");
esp_wifi_clear_ap_list();
goto exit;
}{...}
if (esp_wifi_scan_get_ap_records(&get_count, prov_ctx->ap_list[curr_channel]) != ESP_OK) {
ESP_LOGE(TAG, "Failed to get scanned AP records");
goto exit;
}{...}
prov_ctx->ap_list_len[curr_channel] = get_count;
if (prov_ctx->channels_per_group) {
ESP_LOGD(TAG, "Scan results for channel %d :", curr_channel);
}{...} else {
ESP_LOGD(TAG, "Scan results :");
}{...}
ESP_LOGD(TAG, "\tS.N. %-32s %-12s %s %s", "SSID", "BSSID", "RSSI", "AUTH");
for (uint8_t i = 0; i < prov_ctx->ap_list_len[curr_channel]; i++) {
ESP_LOGD(TAG, "\t[%2d] %-32s %02x%02x%02x%02x%02x%02x %4d %4d", i,
prov_ctx->ap_list[curr_channel][i].ssid,
prov_ctx->ap_list[curr_channel][i].bssid[0],
prov_ctx->ap_list[curr_channel][i].bssid[1],
prov_ctx->ap_list[curr_channel][i].bssid[2],
prov_ctx->ap_list[curr_channel][i].bssid[3],
prov_ctx->ap_list[curr_channel][i].bssid[4],
prov_ctx->ap_list[curr_channel][i].bssid[5],
prov_ctx->ap_list[curr_channel][i].rssi,
prov_ctx->ap_list[curr_channel][i].authmode);
}{...}
{
int rc = get_count;
int is = MAX_SCAN_RESULTS - rc - 1;
while (rc > 0 && is >= 0) {
if (prov_ctx->ap_list_sorted[is]) {
if (prov_ctx->ap_list_sorted[is]->rssi > prov_ctx->ap_list[curr_channel][rc - 1].rssi) {
prov_ctx->ap_list_sorted[is + rc] = &prov_ctx->ap_list[curr_channel][rc - 1];
rc--;
continue;
}{...}
prov_ctx->ap_list_sorted[is + rc] = prov_ctx->ap_list_sorted[is];
}{...}
is--;
}{...}
while (rc > 0) {
prov_ctx->ap_list_sorted[rc - 1] = &prov_ctx->ap_list[curr_channel][rc - 1];
rc--;
}{...}
}{...}
ret = ESP_OK;
exit:
if (!prov_ctx->channels_per_group) {
/* ... */
prov_ctx->scanning = false;
goto final;
}{...}
curr_channel = prov_ctx->curr_channel = (prov_ctx->curr_channel + 1) % 14;
if (ret != ESP_OK || curr_channel == 0) {
prov_ctx->scanning = false;
goto final;
}{...}
if ((curr_channel % prov_ctx->channels_per_group) == 0) {
vTaskDelay(120 / portTICK_PERIOD_MS);
}{...}
ESP_LOGD(TAG, "Scan starting on channel %u...", curr_channel);
prov_ctx->scan_cfg.channel = curr_channel;
ret = esp_wifi_scan_start(&prov_ctx->scan_cfg, false);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to start scan");
prov_ctx->scanning = false;
goto final;
}{...}
ESP_LOGD(TAG, "Scan started");
final:
return ret;
}{ ... }
static void wifi_prov_mgr_event_handler_internal(
void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return;
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
/* ... */
if (!prov_ctx) {
RELEASE_LOCK(prov_ctx_lock);
return;
}{...}
if (prov_ctx->prov_state == WIFI_PROV_STATE_STARTED &&
event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_SCAN_DONE) {
update_wifi_scan_results();
}{...}
/* ... */
if (prov_ctx->prov_state < WIFI_PROV_STATE_CRED_RECV) {
RELEASE_LOCK(prov_ctx_lock);
return;
}{...}
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
ESP_LOGI(TAG, "STA Start");
/* ... */
prov_ctx->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");
prov_ctx->wifi_state = WIFI_PROV_STA_CONNECTED;
prov_ctx->prov_state = WIFI_PROV_STATE_SUCCESS;
/* ... */
if (!prov_ctx->mgr_info.capabilities.no_auto_stop) {
ESP_LOGD(TAG, "Starting %d sec timer for stop_prov_timer_cb()",
CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT);
esp_timer_start_once(prov_ctx->autostop_timer, CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT * 1000000U);
}{...}
execute_event_cb(WIFI_PROV_CRED_SUCCESS, NULL, 0);
}{...} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (prov_ctx->mgr_config.wifi_prov_conn_cfg.wifi_conn_attempts > 0) {
prov_ctx->connection_attempts_completed += 1;
if (prov_ctx->connection_attempts_completed < prov_ctx->mgr_config.wifi_prov_conn_cfg.wifi_conn_attempts) {
/* ... */
prov_ctx->wifi_state = WIFI_PROV_STA_CONN_ATTEMPT_FAILED;
esp_wifi_connect();
}{...} else {
ESP_LOGE(TAG, "STA Disconnected");
prov_ctx->wifi_state = WIFI_PROV_STA_DISCONNECTED;
}{...}
}{...} else {
ESP_LOGE(TAG, "STA Disconnected");
prov_ctx->wifi_state = WIFI_PROV_STA_DISCONNECTED;
}{...}
/* ... */
if (prov_ctx->wifi_state == WIFI_PROV_STA_DISCONNECTED) {
prov_ctx->prov_state = WIFI_PROV_STATE_FAIL;
wifi_prov_sta_fail_reason_t reason = prov_ctx->wifi_disconnect_reason;
wifi_event_sta_disconnected_t* disconnected = (wifi_event_sta_disconnected_t*) event_data;
ESP_LOGE(TAG, "Disconnect reason : %d", disconnected->reason);
switch (disconnected->reason) {
case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT:
case WIFI_REASON_AUTH_FAIL:
case WIFI_REASON_HANDSHAKE_TIMEOUT:
case WIFI_REASON_MIC_FAILURE:
ESP_LOGE(TAG, "STA Auth Error");
prov_ctx->wifi_disconnect_reason = WIFI_PROV_STA_AUTH_ERROR;
break;...
case WIFI_REASON_NO_AP_FOUND:
ESP_LOGE(TAG, "STA AP Not found");
prov_ctx->wifi_disconnect_reason = WIFI_PROV_STA_AP_NOT_FOUND;
break;...
default:
if (prov_ctx->mgr_config.wifi_prov_conn_cfg.wifi_conn_attempts == 0) {
/* ... */
prov_ctx->wifi_state = WIFI_PROV_STA_CONNECTING;
esp_wifi_connect();
}{...}
...}{...}
if (prov_ctx->wifi_state == WIFI_PROV_STA_DISCONNECTED) {
execute_event_cb(WIFI_PROV_CRED_FAIL, (void *)&reason, sizeof(reason));
}{...}
}{...}
}{...} else if (event_base == WIFI_PROV_MGR_PVT_EVENT && event_id == WIFI_PROV_MGR_STOP) {
prov_stop_and_notify(true);
}{...}
RELEASE_LOCK(prov_ctx_lock);
}{ ... }
esp_err_t wifi_prov_mgr_wifi_scan_start(bool blocking, bool passive,
uint8_t group_channels, uint32_t period_ms)
{
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return ESP_ERR_INVALID_STATE;
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
if (!prov_ctx) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
RELEASE_LOCK(prov_ctx_lock);
return ESP_ERR_INVALID_STATE;
}{...}
if (prov_ctx->scanning) {
ESP_LOGD(TAG, "Scan already running");
RELEASE_LOCK(prov_ctx_lock);
return ESP_OK;
}{...}
for (uint8_t i = 0; i < MAX_SCAN_RESULTS; i++) {
prov_ctx->ap_list_sorted[i] = NULL;
}{...}
if (passive) {
prov_ctx->scan_cfg.scan_type = WIFI_SCAN_TYPE_PASSIVE;
#if !CONFIG_BT_ENABLED
prov_ctx->scan_cfg.scan_time.passive = period_ms;
#endif
}{...} else {
prov_ctx->scan_cfg.scan_type = WIFI_SCAN_TYPE_ACTIVE;
#if !CONFIG_BT_ENABLED
prov_ctx->scan_cfg.scan_time.active.min = period_ms;
prov_ctx->scan_cfg.scan_time.active.max = period_ms;/* ... */
#endif
}{...}
prov_ctx->channels_per_group = group_channels;
if (prov_ctx->channels_per_group) {
ESP_LOGD(TAG, "Scan starting on channel 1...");
prov_ctx->scan_cfg.channel = 1;
}{...} else {
ESP_LOGD(TAG, "Scan starting...");
prov_ctx->scan_cfg.channel = 0;
}{...}
if (esp_wifi_scan_start(&prov_ctx->scan_cfg, false) != ESP_OK) {
ESP_LOGE(TAG, "Failed to start scan");
RELEASE_LOCK(prov_ctx_lock);
return ESP_FAIL;
}{...}
ESP_LOGD(TAG, "Scan started");
prov_ctx->scanning = true;
prov_ctx->curr_channel = prov_ctx->scan_cfg.channel;
RELEASE_LOCK(prov_ctx_lock);
if (!blocking) {
return ESP_OK;
}{...}
bool scanning = true;
while (scanning) {
ACQUIRE_LOCK(prov_ctx_lock);
scanning = (prov_ctx && prov_ctx->scanning);
RELEASE_LOCK(prov_ctx_lock);
vTaskDelay(120 / portTICK_PERIOD_MS);
}{...}
return ESP_OK;
}{ ... }
bool wifi_prov_mgr_wifi_scan_finished(void)
{
bool scan_finished = true;
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return scan_finished;
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
if (!prov_ctx) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
RELEASE_LOCK(prov_ctx_lock);
return scan_finished;
}{...}
scan_finished = !prov_ctx->scanning;
RELEASE_LOCK(prov_ctx_lock);
return scan_finished;
}{ ... }
uint16_t wifi_prov_mgr_wifi_scan_result_count(void)
{
uint16_t rval = 0;
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return rval;
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
if (!prov_ctx) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
RELEASE_LOCK(prov_ctx_lock);
return rval;
}{...}
while (rval < MAX_SCAN_RESULTS) {
if (!prov_ctx->ap_list_sorted[rval]) {
break;
}{...}
rval++;
}{...}
RELEASE_LOCK(prov_ctx_lock);
return rval;
}{ ... }
const wifi_ap_record_t *wifi_prov_mgr_wifi_scan_result(uint16_t index)
{
const wifi_ap_record_t *rval = NULL;
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return rval;
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
if (!prov_ctx) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
RELEASE_LOCK(prov_ctx_lock);
return rval;
}{...}
if (index < MAX_SCAN_RESULTS) {
rval = prov_ctx->ap_list_sorted[index];
}{...}
RELEASE_LOCK(prov_ctx_lock);
return rval;
}{ ... }
esp_err_t wifi_prov_mgr_get_wifi_state(wifi_prov_sta_state_t *state)
{
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return ESP_ERR_INVALID_STATE;
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
if (prov_ctx == NULL || state == NULL) {
RELEASE_LOCK(prov_ctx_lock);
return ESP_FAIL;
}{...}
*state = prov_ctx->wifi_state;
RELEASE_LOCK(prov_ctx_lock);
return ESP_OK;
}{ ... }
esp_err_t wifi_prov_mgr_get_remaining_conn_attempts(uint32_t *attempts_remaining)
{
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return ESP_ERR_INVALID_STATE;
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
if (prov_ctx == NULL || attempts_remaining == NULL) {
RELEASE_LOCK(prov_ctx_lock);
return ESP_FAIL;
}{...}
*attempts_remaining = prov_ctx->mgr_config.wifi_prov_conn_cfg.wifi_conn_attempts - prov_ctx->connection_attempts_completed;
RELEASE_LOCK(prov_ctx_lock);
return ESP_OK;
}{ ... }
esp_err_t wifi_prov_mgr_get_wifi_disconnect_reason(wifi_prov_sta_fail_reason_t *reason)
{
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return ESP_ERR_INVALID_STATE;
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
if (prov_ctx == NULL || reason == NULL) {
RELEASE_LOCK(prov_ctx_lock);
return ESP_FAIL;
}{...}
if (prov_ctx->wifi_state != WIFI_PROV_STA_DISCONNECTED) {
RELEASE_LOCK(prov_ctx_lock);
return ESP_FAIL;
}{...}
*reason = prov_ctx->wifi_disconnect_reason;
RELEASE_LOCK(prov_ctx_lock);
return ESP_OK;
}{ ... }
static void debug_print_wifi_credentials(wifi_sta_config_t sta, const char* pretext)
{
size_t passlen = strlen((const char*) sta.password);
ESP_LOGD(TAG, "%s Wi-Fi SSID : %.*s", pretext,
strnlen((const char *) sta.ssid, sizeof(sta.ssid)), (const char *) sta.ssid);
if (passlen) {
memset(sta.password + (passlen > 3), '*', passlen - 2*(passlen > 3));
ESP_LOGD(TAG, "%s Wi-Fi Password : %s", pretext, (const char *) sta.password);
}{...}
}{ ... }
esp_err_t wifi_prov_mgr_is_provisioned(bool *provisioned)
{
if (!provisioned) {
return ESP_ERR_INVALID_ARG;
}{...}
*provisioned = false;
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;
debug_print_wifi_credentials(wifi_cfg.sta, "Found");
}{...}
return ESP_OK;
}{ ... }
bool wifi_prov_mgr_is_sm_idle(void)
{
return (prov_ctx->prov_state == WIFI_PROV_STATE_IDLE);
}{ ... }
static void wifi_connect_timer_cb(void *arg)
{
if (esp_wifi_connect() != ESP_OK) {
ESP_LOGE(TAG, "Failed to connect Wi-Fi");
}{...}
}{ ... }
esp_err_t wifi_prov_mgr_configure_sta(wifi_config_t *wifi_cfg)
{
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return ESP_ERR_INVALID_STATE;
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
if (!prov_ctx) {
ESP_LOGE(TAG, "Invalid state of Provisioning app");
RELEASE_LOCK(prov_ctx_lock);
return ESP_FAIL;
}{...}
execute_event_cb(WIFI_PROV_SET_STA_CONFIG, (void *)wifi_cfg, sizeof(wifi_config_t));
if (prov_ctx->prov_state >= WIFI_PROV_STATE_CRED_RECV) {
ESP_LOGE(TAG, "Wi-Fi credentials already received by provisioning app");
RELEASE_LOCK(prov_ctx_lock);
return ESP_FAIL;
}{...}
debug_print_wifi_credentials(wifi_cfg->sta, "Received");
if (esp_wifi_set_mode(prov_ctx->mgr_config.scheme.wifi_mode) != ESP_OK) {
ESP_LOGE(TAG, "Failed to set Wi-Fi mode");
RELEASE_LOCK(prov_ctx_lock);
return ESP_FAIL;
}{...}
/* ... */
/* ... */
if (esp_wifi_set_storage(WIFI_STORAGE_FLASH) != ESP_OK) {
ESP_LOGE(TAG, "Failed to set storage Wi-Fi");
RELEASE_LOCK(prov_ctx_lock);
return ESP_FAIL;
}{...}
/* ... */
if (esp_wifi_set_config(WIFI_IF_STA, wifi_cfg) != ESP_OK) {
ESP_LOGE(TAG, "Failed to set Wi-Fi configuration");
RELEASE_LOCK(prov_ctx_lock);
return ESP_FAIL;
}{...}
/* ... */
if (esp_timer_start_once(prov_ctx->wifi_connect_timer, 1000 * 1000U) != ESP_OK) {
ESP_LOGE(TAG, "Failed to start Wi-Fi connect timer");
RELEASE_LOCK(prov_ctx_lock);
return ESP_FAIL;
}{...}
prov_ctx->wifi_state = WIFI_PROV_STA_CONNECTING;
prov_ctx->prov_state = WIFI_PROV_STATE_CRED_RECV;
execute_event_cb(WIFI_PROV_CRED_RECV, (void *)&wifi_cfg->sta, sizeof(wifi_cfg->sta));
RELEASE_LOCK(prov_ctx_lock);
return ESP_OK;
}{ ... }
esp_err_t wifi_prov_mgr_init(wifi_prov_mgr_config_t config)
{
if (!prov_ctx_lock) {
/* ... */
prov_ctx_lock = xSemaphoreCreateMutex();
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Failed to create mutex");
return ESP_ERR_NO_MEM;
}{...}
}{...}
void *fn_ptrs[] = {
config.scheme.prov_stop,
config.scheme.prov_start,
config.scheme.new_config,
config.scheme.delete_config,
config.scheme.set_config_service,
config.scheme.set_config_endpoint
}{...};
for (size_t i = 0; i < sizeof(fn_ptrs)/sizeof(fn_ptrs[0]); i++) {
if (!fn_ptrs[i]) {
return ESP_ERR_INVALID_ARG;
}{...}
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
if (prov_ctx) {
ESP_LOGE(TAG, "Provisioning manager already initialized");
RELEASE_LOCK(prov_ctx_lock);
return ESP_ERR_INVALID_STATE;
}{...}
prov_ctx = (struct wifi_prov_mgr_ctx *) calloc(1, sizeof(struct wifi_prov_mgr_ctx));
if (!prov_ctx) {
ESP_LOGE(TAG, "Error allocating memory for singleton instance");
RELEASE_LOCK(prov_ctx_lock);
return ESP_ERR_NO_MEM;
}{...}
prov_ctx->mgr_config = config;
prov_ctx->prov_state = WIFI_PROV_STATE_IDLE;
prov_ctx->mgr_info.version = WIFI_PROV_MGR_VERSION;
const wifi_prov_scheme_t *scheme = &prov_ctx->mgr_config.scheme;
esp_err_t ret = ESP_OK;
prov_ctx->prov_scheme_config = scheme->new_config();
if (!prov_ctx->prov_scheme_config) {
ESP_LOGE(TAG, "failed to allocate provisioning scheme configuration");
ret = ESP_ERR_NO_MEM;
goto exit;
}{...}
ret = scheme->set_config_endpoint(prov_ctx->prov_scheme_config, "prov-ctrl", 0xFF4F);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "failed to configure Wi-Fi state control endpoint");
goto exit;
}{...}
ret = scheme->set_config_endpoint(prov_ctx->prov_scheme_config, "prov-scan", 0xFF50);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "failed to configure Wi-Fi scanning endpoint");
goto exit;
}{...}
ret = scheme->set_config_endpoint(prov_ctx->prov_scheme_config, "prov-session", 0xFF51);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "failed to configure security endpoint");
goto exit;
}{...}
ret = scheme->set_config_endpoint(prov_ctx->prov_scheme_config, "prov-config", 0xFF52);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "failed to configure Wi-Fi configuration endpoint");
goto exit;
}{...}
ret = scheme->set_config_endpoint(prov_ctx->prov_scheme_config, "proto-ver", 0xFF53);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "failed to configure version endpoint");
goto exit;
}{...}
/* ... */
prov_ctx->endpoint_uuid_used = 0xFF53;
/* ... */
prov_ctx->cleanup_delay = 1000;
exit:
if (ret != ESP_OK) {
if (prov_ctx->prov_scheme_config) {
config.scheme.delete_config(prov_ctx->prov_scheme_config);
}{...}
free(prov_ctx);
}{...} else {
execute_event_cb(WIFI_PROV_INIT, NULL, 0);
}{...}
RELEASE_LOCK(prov_ctx_lock);
return ret;
}{ ... }
void wifi_prov_mgr_wait(void)
{
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return;
}{...}
while (1) {
ACQUIRE_LOCK(prov_ctx_lock);
if (prov_ctx &&
prov_ctx->prov_state != WIFI_PROV_STATE_IDLE) {
RELEASE_LOCK(prov_ctx_lock);
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}{...}
break;
}{...}
RELEASE_LOCK(prov_ctx_lock);
}{ ... }
void wifi_prov_mgr_deinit(void)
{
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return;
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
/* ... */
bool service_was_running = wifi_prov_mgr_stop_service(1);
/* ... */
if (!service_was_running && !prov_ctx) {
ESP_LOGD(TAG, "Manager already de-initialized");
RELEASE_LOCK(prov_ctx_lock);
vSemaphoreDelete(prov_ctx_lock);
prov_ctx_lock = NULL;
return;
}{...}
if (prov_ctx->app_info_json) {
cJSON_Delete(prov_ctx->app_info_json);
}{...}
if (prov_ctx->prov_scheme_config) {
prov_ctx->mgr_config.scheme.delete_config(prov_ctx->prov_scheme_config);
}{...}
wifi_prov_cb_func_t app_cb = prov_ctx->mgr_config.app_event_handler.event_cb;
void *app_data = prov_ctx->mgr_config.app_event_handler.user_data;
wifi_prov_cb_func_t scheme_cb = prov_ctx->mgr_config.scheme_event_handler.event_cb;
void *scheme_data = prov_ctx->mgr_config.scheme_event_handler.user_data;
free(prov_ctx);
prov_ctx = NULL;
RELEASE_LOCK(prov_ctx_lock);
/* ... */
if (service_was_running) {
ESP_LOGD(TAG, "execute_event_cb : %d", WIFI_PROV_END);
if (scheme_cb) {
scheme_cb(scheme_data, WIFI_PROV_END, NULL);
}{...}
if (app_cb) {
app_cb(app_data, WIFI_PROV_END, NULL);
}{...}
if (esp_event_post(WIFI_PROV_EVENT, WIFI_PROV_END, NULL, 0, portMAX_DELAY) != ESP_OK) {
ESP_LOGE(TAG, "Failed to post event WIFI_PROV_END");
}{...}
}{...}
ESP_LOGD(TAG, "execute_event_cb : %d", WIFI_PROV_DEINIT);
if (scheme_cb) {
scheme_cb(scheme_data, WIFI_PROV_DEINIT, NULL);
}{...}
if (app_cb) {
app_cb(app_data, WIFI_PROV_DEINIT, NULL);
}{...}
if (esp_event_post(WIFI_PROV_EVENT, WIFI_PROV_DEINIT, NULL, 0, portMAX_DELAY) != ESP_OK) {
ESP_LOGE(TAG, "Failed to post event WIFI_PROV_DEINIT");
}{...}
vSemaphoreDelete(prov_ctx_lock);
prov_ctx_lock = NULL;
}{ ... }
esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const void *wifi_prov_sec_params,
const char *service_name, const char *service_key)
{
uint8_t restore_wifi_flag = 0;
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return ESP_ERR_INVALID_STATE;
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
if (!prov_ctx) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
RELEASE_LOCK(prov_ctx_lock);
return ESP_ERR_INVALID_STATE;
}{...}
if (prov_ctx->prov_state != WIFI_PROV_STATE_IDLE) {
ESP_LOGE(TAG, "Provisioning service already started");
RELEASE_LOCK(prov_ctx_lock);
return ESP_ERR_INVALID_STATE;
}{...}
esp_err_t ret = ESP_OK;
/* ... */
prov_ctx->prov_state = WIFI_PROV_STATE_STARTING;
/* ... */
ret = esp_wifi_set_mode(WIFI_MODE_STA);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set Wi-Fi mode to STA");
goto err;
}{...}
ret = esp_wifi_start();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to start Wi-Fi");
goto err;
}{...}
/* ... */
wifi_config_t wifi_cfg_empty, wifi_cfg_old;
memset(&wifi_cfg_empty, 0, sizeof(wifi_config_t));
esp_wifi_get_config(WIFI_IF_STA, &wifi_cfg_old);
ret = esp_wifi_set_storage(WIFI_STORAGE_RAM);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set Wi-Fi storage to RAM");
goto err;
}{...}
restore_wifi_flag |= WIFI_PROV_STORAGE_BIT;
/* ... */
ret = esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg_empty);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set empty Wi-Fi credentials");
goto err;
}{...}
restore_wifi_flag |= WIFI_PROV_SETTING_BIT;
ret = esp_wifi_disconnect();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to disconnect");
goto err;
}{...}
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0
if (security == WIFI_PROV_SECURITY_0) {
prov_ctx->mgr_info.capabilities.no_sec = true;
}{...}
#endif/* ... */
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1
if (security == WIFI_PROV_SECURITY_1) {
if (wifi_prov_sec_params) {
static protocomm_security1_params_t sec1_params;
char *pop = strdup(wifi_prov_sec_params);
if (pop == NULL) {
ESP_LOGE(TAG, "Failed to allocate memory for pop");
ret = ESP_ERR_NO_MEM;
goto err;
}{...}
sec1_params.data = (const uint8_t *)pop;
sec1_params.len = strlen(pop);
prov_ctx->protocomm_sec_params = (const void *) &sec1_params;
}{...} else {
prov_ctx->mgr_info.capabilities.no_pop = true;
}{...}
}{...}
#endif/* ... */
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2
if (security == WIFI_PROV_SECURITY_2) {
if (wifi_prov_sec_params) {
prov_ctx->protocomm_sec_params = wifi_prov_sec_params;
}{...}
}{...}
#endif/* ... */
prov_ctx->security = security;
esp_timer_create_args_t wifi_connect_timer_conf = {
.callback = wifi_connect_timer_cb,
.arg = NULL,
.dispatch_method = ESP_TIMER_TASK,
.name = "wifi_prov_connect_tm"
}{...};
ret = esp_timer_create(&wifi_connect_timer_conf, &prov_ctx->wifi_connect_timer);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to create Wi-Fi connect timer");
goto err;
}{...}
if (!prov_ctx->mgr_info.capabilities.no_auto_stop) {
esp_timer_create_args_t autostop_timer_conf = {
.callback = stop_prov_timer_cb,
.arg = NULL,
.dispatch_method = ESP_TIMER_TASK,
.name = "wifi_prov_autostop_tm"
}{...};
ret = esp_timer_create(&autostop_timer_conf, &prov_ctx->autostop_timer);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to create auto-stop timer");
esp_timer_delete(prov_ctx->wifi_connect_timer);
goto err;
}{...}
}{...}
esp_timer_create_args_t cleanup_delay_timer = {
.callback = cleanup_delay_timer_cb,
.arg = NULL,
.dispatch_method = ESP_TIMER_TASK,
.name = "cleanup_delay_tm"
}{...};
ret = esp_timer_create(&cleanup_delay_timer, &prov_ctx->cleanup_delay_timer);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to create cleanup delay timer");
esp_timer_delete(prov_ctx->wifi_connect_timer);
esp_timer_delete(prov_ctx->autostop_timer);
goto err;
}{...}
/* ... */
RELEASE_LOCK(prov_ctx_lock);
ret = wifi_prov_mgr_start_service(service_name, service_key);
if (ret != ESP_OK) {
esp_timer_delete(prov_ctx->autostop_timer);
esp_timer_delete(prov_ctx->wifi_connect_timer);
esp_timer_delete(prov_ctx->cleanup_delay_timer);
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
if (ret == ESP_OK) {
prov_ctx->prov_state = WIFI_PROV_STATE_STARTED;
execute_event_cb(WIFI_PROV_START, NULL, 0);
goto exit;
}{...}
err:
prov_ctx->prov_state = WIFI_PROV_STATE_IDLE;
if (restore_wifi_flag & WIFI_PROV_SETTING_BIT) {
esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg_old);
}{...}
exit:
if (restore_wifi_flag & WIFI_PROV_STORAGE_BIT) {
esp_wifi_set_storage(WIFI_STORAGE_FLASH);
}{...}
RELEASE_LOCK(prov_ctx_lock);
return ret;
}{ ... }
void wifi_prov_mgr_stop_provisioning(void)
{
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return;
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
/* ... */
wifi_prov_mgr_stop_service(0);
RELEASE_LOCK(prov_ctx_lock);
}{ ... }
esp_err_t wifi_prov_mgr_reset_provisioning(void)
{
esp_err_t ret = esp_wifi_restore();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "esp_wifi_restore fail, ret is %d", ret);
ret = ESP_FAIL;
}{...}
return ret;
}{ ... }
esp_err_t wifi_prov_mgr_reset_sm_state_on_failure(void)
{
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return ESP_ERR_INVALID_STATE;
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
esp_err_t err = ESP_OK;
if (prov_ctx->prov_state != WIFI_PROV_STATE_FAIL) {
ESP_LOGE(TAG, "Trying reset when not in failure state. Current state: %d", prov_ctx->prov_state);
err = ESP_ERR_INVALID_STATE;
goto exit;
}{...}
wifi_config_t wifi_cfg = {0};
err = esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to set wifi config, 0x%x", err);
goto exit;
}{...}
prov_ctx->prov_state = WIFI_PROV_STATE_STARTED;
exit:
RELEASE_LOCK(prov_ctx_lock);
return err;
}{ ... }
esp_err_t wifi_prov_mgr_reset_sm_state_for_reprovision(void)
{
if (!prov_ctx_lock) {
ESP_LOGE(TAG, "Provisioning manager not initialized");
return ESP_ERR_INVALID_STATE;
}{...}
ACQUIRE_LOCK(prov_ctx_lock);
esp_err_t ret = ESP_OK;
wifi_config_t wifi_cfg_empty = {0};
uint8_t restore_wifi_flag = 0;
if (!prov_ctx->mgr_info.capabilities.no_auto_stop) {
ESP_LOGE(TAG, "Execute wifi_prov_mgr_disable_auto_stop() before calling this API");
ret = ESP_ERR_INVALID_STATE;
goto exit;
}{...}
ret = esp_wifi_set_storage(WIFI_STORAGE_RAM);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set Wi-Fi storage to RAM");
goto exit;
}{...}
restore_wifi_flag |= WIFI_PROV_STORAGE_BIT;
ret = esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg_empty);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set empty Wi-Fi credentials, 0x%x", ret);
goto exit;
}{...}
ret = esp_wifi_disconnect();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to disconnect wifi, 0x%x", ret);
goto exit;
}{...}
prov_ctx->prov_state = WIFI_PROV_STATE_STARTED;
execute_event_cb(WIFI_PROV_START, NULL, 0);
exit:
if (restore_wifi_flag & WIFI_PROV_STORAGE_BIT) {
esp_wifi_set_storage(WIFI_STORAGE_FLASH);
}{...}
RELEASE_LOCK(prov_ctx_lock);
return ret;
}{ ... }