1 /* Mesh Manual Networking Example
2
3 This example code is in the Public Domain (or CC0 licensed, at your option.)
4
5 Unless required by applicable law or agreed to in writing, this
6 software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
7 CONDITIONS OF ANY KIND, either express or implied.
8 */
9 #include <string.h>
10 #include "esp_wifi.h"
11 #include "esp_system.h"
12 #include "esp_event.h"
13 #include "esp_log.h"
14 #include "esp_mesh.h"
15 #include "esp_mesh_internal.h"
16 #include "mesh_light.h"
17 #include "nvs_flash.h"
18
19 /*******************************************************
20 * Macros
21 *******************************************************/
22
23 /*******************************************************
24 * Constants
25 *******************************************************/
26
27 /*******************************************************
28 * Variable Definitions
29 *******************************************************/
30 static const char *MESH_TAG = "mesh_main";
31 static const uint8_t MESH_ID[6] = { 0x77, 0x77, 0x77, 0x77, 0x77, 0x77};
32 static mesh_addr_t mesh_parent_addr;
33 static int mesh_layer = -1;
34 static esp_netif_t *netif_sta = NULL;
35
36 /*******************************************************
37 * Function Declarations
38 *******************************************************/
39 void mesh_scan_done_handler(int num);
40
41 /*******************************************************
42 * Function Definitions
43 *******************************************************/
mesh_scan_done_handler(int num)44 void mesh_scan_done_handler(int num)
45 {
46 int i;
47 int ie_len = 0;
48 mesh_assoc_t assoc;
49 mesh_assoc_t parent_assoc = { .layer = CONFIG_MESH_MAX_LAYER, .rssi = -120 };
50 wifi_ap_record_t record;
51 wifi_ap_record_t parent_record = { 0, };
52 bool parent_found = false;
53 mesh_type_t my_type = MESH_IDLE;
54 int my_layer = -1;
55 wifi_config_t parent = { 0, };
56 wifi_scan_config_t scan_config = { 0 };
57
58 for (i = 0; i < num; i++) {
59 esp_mesh_scan_get_ap_ie_len(&ie_len);
60 esp_mesh_scan_get_ap_record(&record, &assoc);
61 if (ie_len == sizeof(assoc)) {
62 ESP_LOGW(MESH_TAG,
63 "<MESH>[%d]%s, layer:%d/%d, assoc:%d/%d, %d, "MACSTR", channel:%u, rssi:%d, ID<"MACSTR"><%s>",
64 i, record.ssid, assoc.layer, assoc.layer_cap, assoc.assoc,
65 assoc.assoc_cap, assoc.layer2_cap, MAC2STR(record.bssid),
66 record.primary, record.rssi, MAC2STR(assoc.mesh_id), assoc.encrypted ? "IE Encrypted" : "IE Unencrypted");
67
68 #if CONFIG_MESH_SET_NODE
69 if (assoc.mesh_type != MESH_IDLE && assoc.layer_cap
70 && assoc.assoc < assoc.assoc_cap && record.rssi > -70) {
71 if (assoc.layer < parent_assoc.layer || assoc.layer2_cap < parent_assoc.layer2_cap) {
72 parent_found = true;
73 memcpy(&parent_record, &record, sizeof(record));
74 memcpy(&parent_assoc, &assoc, sizeof(assoc));
75 if (parent_assoc.layer_cap != 1) {
76 my_type = MESH_NODE;
77 } else {
78 my_type = MESH_LEAF;
79 }
80 my_layer = parent_assoc.layer + 1;
81 break;
82 }
83 }
84 #endif
85 } else {
86 ESP_LOGI(MESH_TAG, "[%d]%s, "MACSTR", channel:%u, rssi:%d", i,
87 record.ssid, MAC2STR(record.bssid), record.primary,
88 record.rssi);
89 #if CONFIG_MESH_SET_ROOT
90 if (!strcmp(CONFIG_MESH_ROUTER_SSID, (char *) record.ssid)) {
91 parent_found = true;
92 memcpy(&parent_record, &record, sizeof(record));
93 my_type = MESH_ROOT;
94 my_layer = MESH_ROOT_LAYER;
95 }
96 #endif
97 }
98 }
99 esp_mesh_flush_scan_result();
100 if (parent_found) {
101 /*
102 * parent
103 * Both channel and SSID of the parent are mandatory.
104 */
105 parent.sta.channel = parent_record.primary;
106 memcpy(&parent.sta.ssid, &parent_record.ssid,
107 sizeof(parent_record.ssid));
108 parent.sta.bssid_set = 1;
109 memcpy(&parent.sta.bssid, parent_record.bssid, 6);
110 if (my_type == MESH_ROOT) {
111 if (parent_record.authmode != WIFI_AUTH_OPEN) {
112 memcpy(&parent.sta.password, CONFIG_MESH_ROUTER_PASSWD,
113 strlen(CONFIG_MESH_ROUTER_PASSWD));
114 }
115 ESP_LOGW(MESH_TAG, "<PARENT>%s, "MACSTR", channel:%u, rssi:%d",
116 parent_record.ssid, MAC2STR(parent_record.bssid),
117 parent_record.primary, parent_record.rssi);
118 ESP_ERROR_CHECK(esp_mesh_set_parent(&parent, NULL, my_type, my_layer));
119 } else {
120 ESP_ERROR_CHECK(esp_mesh_set_ap_authmode(parent_record.authmode));
121 if (parent_record.authmode != WIFI_AUTH_OPEN) {
122 memcpy(&parent.sta.password, CONFIG_MESH_AP_PASSWD,
123 strlen(CONFIG_MESH_AP_PASSWD));
124 }
125 ESP_LOGW(MESH_TAG,
126 "<PARENT>%s, layer:%d/%d, assoc:%d/%d, %d, "MACSTR", channel:%u, rssi:%d",
127 parent_record.ssid, parent_assoc.layer,
128 parent_assoc.layer_cap, parent_assoc.assoc,
129 parent_assoc.assoc_cap, parent_assoc.layer2_cap,
130 MAC2STR(parent_record.bssid), parent_record.primary,
131 parent_record.rssi);
132 ESP_ERROR_CHECK(esp_mesh_set_parent(&parent, (mesh_addr_t *)&parent_assoc.mesh_id, my_type, my_layer));
133 }
134
135 } else {
136 esp_wifi_scan_stop();
137 scan_config.show_hidden = 1;
138 scan_config.scan_type = WIFI_SCAN_TYPE_PASSIVE;
139 esp_wifi_scan_start(&scan_config, 0);
140 }
141 }
142
mesh_event_handler(void * arg,esp_event_base_t event_base,int32_t event_id,void * event_data)143 void mesh_event_handler(void *arg, esp_event_base_t event_base,
144 int32_t event_id, void *event_data)
145 {
146 mesh_addr_t id = {0,};
147 static int last_layer = 0;
148 wifi_scan_config_t scan_config = { 0 };
149
150 switch (event_id) {
151 case MESH_EVENT_STARTED: {
152 esp_mesh_get_id(&id);
153 ESP_LOGI(MESH_TAG, "<MESH_EVENT_STARTED>ID:"MACSTR"", MAC2STR(id.addr));
154 mesh_layer = esp_mesh_get_layer();
155 ESP_ERROR_CHECK(esp_mesh_set_self_organized(0, 0));
156 esp_wifi_scan_stop();
157 /* mesh softAP is hidden */
158 scan_config.show_hidden = 1;
159 scan_config.scan_type = WIFI_SCAN_TYPE_PASSIVE;
160 esp_wifi_scan_start(&scan_config, 0);
161 }
162 break;
163 case MESH_EVENT_STOPPED: {
164 ESP_LOGI(MESH_TAG, "<MESH_EVENT_STOPPED>");
165 mesh_layer = esp_mesh_get_layer();
166 }
167 break;
168 case MESH_EVENT_CHILD_CONNECTED: {
169 mesh_event_child_connected_t *child_connected = (mesh_event_child_connected_t *)event_data;
170 ESP_LOGI(MESH_TAG, "<MESH_EVENT_CHILD_CONNECTED>aid:%d, "MACSTR"",
171 child_connected->aid,
172 MAC2STR(child_connected->mac));
173 }
174 break;
175 case MESH_EVENT_CHILD_DISCONNECTED: {
176 mesh_event_child_disconnected_t *child_disconnected = (mesh_event_child_disconnected_t *)event_data;
177 ESP_LOGI(MESH_TAG, "<MESH_EVENT_CHILD_DISCONNECTED>aid:%d, "MACSTR"",
178 child_disconnected->aid,
179 MAC2STR(child_disconnected->mac));
180 }
181 break;
182 case MESH_EVENT_ROUTING_TABLE_ADD: {
183 mesh_event_routing_table_change_t *routing_table = (mesh_event_routing_table_change_t *)event_data;
184 ESP_LOGW(MESH_TAG, "<MESH_EVENT_ROUTING_TABLE_ADD>add %d, new:%d",
185 routing_table->rt_size_change,
186 routing_table->rt_size_new);
187 }
188 break;
189 case MESH_EVENT_ROUTING_TABLE_REMOVE: {
190 mesh_event_routing_table_change_t *routing_table = (mesh_event_routing_table_change_t *)event_data;
191 ESP_LOGW(MESH_TAG, "<MESH_EVENT_ROUTING_TABLE_REMOVE>remove %d, new:%d",
192 routing_table->rt_size_change,
193 routing_table->rt_size_new);
194 }
195 break;
196 case MESH_EVENT_NO_PARENT_FOUND: {
197 mesh_event_no_parent_found_t *no_parent = (mesh_event_no_parent_found_t *)event_data;
198 ESP_LOGI(MESH_TAG, "<MESH_EVENT_NO_PARENT_FOUND>scan times:%d",
199 no_parent->scan_times);
200 }
201 /* TODO handler for the failure */
202 break;
203 case MESH_EVENT_PARENT_CONNECTED: {
204 mesh_event_connected_t *connected = (mesh_event_connected_t *)event_data;
205 esp_mesh_get_id(&id);
206 mesh_layer = connected->self_layer;
207 memcpy(&mesh_parent_addr.addr, connected->connected.bssid, 6);
208 ESP_LOGI(MESH_TAG,
209 "<MESH_EVENT_PARENT_CONNECTED>layer:%d-->%d, parent:"MACSTR"%s, ID:"MACSTR"",
210 last_layer, mesh_layer, MAC2STR(mesh_parent_addr.addr),
211 esp_mesh_is_root() ? "<ROOT>" :
212 (mesh_layer == 2) ? "<layer2>" : "", MAC2STR(id.addr));
213 last_layer = mesh_layer;
214 mesh_connected_indicator(mesh_layer);
215 if (esp_mesh_is_root()) {
216 esp_netif_dhcpc_stop(netif_sta);
217 esp_netif_dhcpc_start(netif_sta);
218 }
219 }
220 break;
221 case MESH_EVENT_PARENT_DISCONNECTED: {
222 mesh_event_disconnected_t *disconnected = (mesh_event_disconnected_t *)event_data;
223 ESP_LOGI(MESH_TAG,
224 "<MESH_EVENT_PARENT_DISCONNECTED>reason:%d",
225 disconnected->reason);
226 mesh_disconnected_indicator();
227 mesh_layer = esp_mesh_get_layer();
228 if (disconnected->reason == WIFI_REASON_ASSOC_TOOMANY) {
229 esp_wifi_scan_stop();
230 scan_config.show_hidden = 1;
231 scan_config.scan_type = WIFI_SCAN_TYPE_PASSIVE;
232 esp_wifi_scan_start(&scan_config, 0);
233 }
234 }
235 break;
236 case MESH_EVENT_LAYER_CHANGE: {
237 mesh_event_layer_change_t *layer_change = (mesh_event_layer_change_t *)event_data;
238 mesh_layer = layer_change->new_layer;
239 ESP_LOGI(MESH_TAG, "<MESH_EVENT_LAYER_CHANGE>layer:%d-->%d%s",
240 last_layer, mesh_layer,
241 esp_mesh_is_root() ? "<ROOT>" :
242 (mesh_layer == 2) ? "<layer2>" : "");
243 last_layer = mesh_layer;
244 mesh_connected_indicator(mesh_layer);
245 }
246 break;
247 case MESH_EVENT_ROOT_ADDRESS: {
248 mesh_event_root_address_t *root_addr = (mesh_event_root_address_t *)event_data;
249 ESP_LOGI(MESH_TAG, "<MESH_EVENT_ROOT_ADDRESS>root address:"MACSTR"",
250 MAC2STR(root_addr->addr));
251 }
252 break;
253 case MESH_EVENT_TODS_STATE: {
254 mesh_event_toDS_state_t *toDs_state = (mesh_event_toDS_state_t *)event_data;
255 ESP_LOGI(MESH_TAG, "<MESH_EVENT_TODS_REACHABLE>state:%d", *toDs_state);
256 }
257 break;
258 case MESH_EVENT_ROOT_FIXED: {
259 mesh_event_root_fixed_t *root_fixed = (mesh_event_root_fixed_t *)event_data;
260 ESP_LOGI(MESH_TAG, "<MESH_EVENT_ROOT_FIXED>%s",
261 root_fixed->is_fixed ? "fixed" : "not fixed");
262 }
263 break;
264 case MESH_EVENT_SCAN_DONE: {
265 mesh_event_scan_done_t *scan_done = (mesh_event_scan_done_t *)event_data;
266 ESP_LOGI(MESH_TAG, "<MESH_EVENT_SCAN_DONE>number:%d",
267 scan_done->number);
268 mesh_scan_done_handler(scan_done->number);
269 }
270 break;
271 default:
272 ESP_LOGD(MESH_TAG, "event id:%d", event_id);
273 break;
274 }
275 }
276
ip_event_handler(void * arg,esp_event_base_t event_base,int32_t event_id,void * event_data)277 void ip_event_handler(void *arg, esp_event_base_t event_base,
278 int32_t event_id, void *event_data)
279 {
280 ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
281 ESP_LOGI(MESH_TAG, "<IP_EVENT_STA_GOT_IP>IP:" IPSTR, IP2STR(&event->ip_info.ip));
282 }
283
app_main(void)284 void app_main(void)
285 {
286 ESP_ERROR_CHECK(mesh_light_init());
287 ESP_ERROR_CHECK(nvs_flash_init());
288 /* tcpip initialization */
289 ESP_ERROR_CHECK(esp_netif_init());
290 /* event initialization */
291 ESP_ERROR_CHECK(esp_event_loop_create_default());
292 /* crete network interfaces for mesh (only station instance saved for further manipulation, soft AP instance ignored */
293 ESP_ERROR_CHECK(esp_netif_create_default_wifi_mesh_netifs(&netif_sta, NULL));
294 /* wifi initialization */
295 wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();
296 ESP_ERROR_CHECK(esp_wifi_init(&config));
297 ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &ip_event_handler, NULL));
298 ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH));
299 ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
300 ESP_ERROR_CHECK(esp_wifi_start());
301 /* mesh initialization */
302 ESP_ERROR_CHECK(esp_mesh_init());
303 ESP_ERROR_CHECK(esp_event_handler_register(MESH_EVENT, ESP_EVENT_ANY_ID, &mesh_event_handler, NULL));
304 /* mesh enable IE crypto */
305 mesh_cfg_t cfg = MESH_INIT_CONFIG_DEFAULT();
306 #if CONFIG_MESH_IE_CRYPTO_FUNCS
307 /* modify IE crypto key */
308 ESP_ERROR_CHECK(esp_mesh_set_ie_crypto_funcs(&g_wifi_default_mesh_crypto_funcs));
309 ESP_ERROR_CHECK(esp_mesh_set_ie_crypto_key(CONFIG_MESH_IE_CRYPTO_KEY, strlen(CONFIG_MESH_IE_CRYPTO_KEY)));
310 #else
311 /* disable IE crypto */
312 ESP_LOGI(MESH_TAG, "<Config>disable IE crypto");
313 ESP_ERROR_CHECK(esp_mesh_set_ie_crypto_funcs(NULL));
314 #endif
315 /* mesh ID */
316 memcpy((uint8_t *) &cfg.mesh_id, MESH_ID, 6);
317 /* router */
318 cfg.channel = CONFIG_MESH_CHANNEL;
319 cfg.router.ssid_len = strlen(CONFIG_MESH_ROUTER_SSID);
320 memcpy((uint8_t *) &cfg.router.ssid, CONFIG_MESH_ROUTER_SSID, cfg.router.ssid_len);
321 memcpy((uint8_t *) &cfg.router.password, CONFIG_MESH_ROUTER_PASSWD,
322 strlen(CONFIG_MESH_ROUTER_PASSWD));
323 /* mesh softAP */
324 ESP_ERROR_CHECK(esp_mesh_set_ap_authmode(CONFIG_MESH_AP_AUTHMODE));
325 cfg.mesh_ap.max_connection = CONFIG_MESH_AP_CONNECTIONS;
326 cfg.mesh_ap.nonmesh_max_connection = CONFIG_MESH_NON_MESH_AP_CONNECTIONS;
327 memcpy((uint8_t *) &cfg.mesh_ap.password, CONFIG_MESH_AP_PASSWD,
328 strlen(CONFIG_MESH_AP_PASSWD));
329 ESP_ERROR_CHECK(esp_mesh_set_config(&cfg));
330 /* mesh start */
331 ESP_ERROR_CHECK(esp_mesh_start());
332 ESP_LOGI(MESH_TAG, "mesh starts successfully, heap:%d\n", esp_get_free_heap_size());
333 }
334