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