1 /* Mesh Internal Communication Example
3 This example code is in the Public Domain (or CC0 licensed, at your option.)
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.
11 #include "esp_system.h"
12 #include "esp_event_loop.h"
15 #include "esp_mesh_internal.h"
16 #include "mesh_light.h"
17 #include "nvs_flash.h"
19 /*******************************************************
21 *******************************************************/
22 //#define MESH_P2P_TOS_OFF
24 /*******************************************************
26 *******************************************************/
27 #define RX_SIZE (1500)
28 #define TX_SIZE (1460)
30 /*******************************************************
31 * Variable Definitions
32 *******************************************************/
33 static const char *MESH_TAG = "mesh_main";
34 static const uint8_t MESH_ID[6] = { 0x77, 0x77, 0x77, 0x77, 0x77, 0x77};
35 static uint8_t tx_buf[TX_SIZE] = { 0, };
36 static uint8_t rx_buf[RX_SIZE] = { 0, };
37 static bool is_running = true;
38 static bool is_mesh_connected = false;
39 static mesh_addr_t mesh_parent_addr;
40 static int mesh_layer = -1;
42 mesh_light_ctl_t light_on = {
43 .cmd = MESH_CONTROL_CMD,
45 .token_id = MESH_TOKEN_ID,
46 .token_value = MESH_TOKEN_VALUE,
49 mesh_light_ctl_t light_off = {
50 .cmd = MESH_CONTROL_CMD,
52 .token_id = MESH_TOKEN_ID,
53 .token_value = MESH_TOKEN_VALUE,
56 /*******************************************************
57 * Function Declarations
58 *******************************************************/
60 /*******************************************************
61 * Function Definitions
62 *******************************************************/
63 void esp_mesh_p2p_tx_main(void *arg)
68 mesh_addr_t route_table[CONFIG_MESH_ROUTE_TABLE_SIZE];
69 int route_table_size = 0;
72 data.size = sizeof(tx_buf);
73 data.proto = MESH_PROTO_BIN;
74 #ifdef MESH_P2P_TOS_OFF
75 data.tos = MESH_TOS_DEF;
76 #endif /* MESH_P2P_TOS_OFF */
80 /* non-root do nothing but print */
81 if (!esp_mesh_is_root()) {
82 ESP_LOGI(MESH_TAG, "layer:%d, rtableSize:%d, %s", mesh_layer,
83 esp_mesh_get_routing_table_size(),
84 (is_mesh_connected && esp_mesh_is_root()) ? "ROOT" : is_mesh_connected ? "NODE" : "DISCONNECT");
85 vTaskDelay(10 * 1000 / portTICK_RATE_MS);
89 esp_mesh_get_routing_table((mesh_addr_t *) &route_table,
90 CONFIG_MESH_ROUTE_TABLE_SIZE * 6, &route_table_size);
91 if (send_count && !(send_count % 100)) {
92 ESP_LOGI(MESH_TAG, "size:%d/%d,send_count:%d", route_table_size,
93 esp_mesh_get_routing_table_size(), send_count);
96 tx_buf[25] = (send_count >> 24) & 0xff;
97 tx_buf[24] = (send_count >> 16) & 0xff;
98 tx_buf[23] = (send_count >> 8) & 0xff;
99 tx_buf[22] = (send_count >> 0) & 0xff;
100 if (send_count % 2) {
101 memcpy(tx_buf, (uint8_t *)&light_on, sizeof(light_on));
103 memcpy(tx_buf, (uint8_t *)&light_off, sizeof(light_off));
106 for (i = 0; i < route_table_size; i++) {
107 err = esp_mesh_send(&route_table[i], &data, MESH_DATA_P2P, NULL, 0);
110 "[ROOT-2-UNICAST:%d][L:%d]parent:"MACSTR" to "MACSTR", heap:%d[err:0x%x, proto:%d, tos:%d]",
111 send_count, mesh_layer, MAC2STR(mesh_parent_addr.addr),
112 MAC2STR(route_table[i].addr), esp_get_free_heap_size(),
113 err, data.proto, data.tos);
114 } else if (!(send_count % 100)) {
116 "[ROOT-2-UNICAST:%d][L:%d][rtableSize:%d]parent:"MACSTR" to "MACSTR", heap:%d[err:0x%x, proto:%d, tos:%d]",
117 send_count, mesh_layer,
118 esp_mesh_get_routing_table_size(),
119 MAC2STR(mesh_parent_addr.addr),
120 MAC2STR(route_table[i].addr), esp_get_free_heap_size(),
121 err, data.proto, data.tos);
124 /* if route_table_size is less than 10, add delay to avoid watchdog in this task. */
125 if (route_table_size < 10) {
126 vTaskDelay(1 * 1000 / portTICK_RATE_MS);
132 void esp_mesh_p2p_rx_main(void *arg)
146 err = esp_mesh_recv(&from, &data, portMAX_DELAY, &flag, NULL, 0);
147 if (err != ESP_OK || !data.size) {
148 ESP_LOGE(MESH_TAG, "err:0x%x, size:%d", err, data.size);
151 /* extract send count */
152 if (data.size >= sizeof(send_count)) {
153 send_count = (data.data[25] << 24) | (data.data[24] << 16)
154 | (data.data[23] << 8) | data.data[22];
157 /* process light control */
158 mesh_light_process(&from, data.data, data.size);
159 if (!(recv_count % 1)) {
161 "[#RX:%d/%d][L:%d] parent:"MACSTR", receive from "MACSTR", size:%d, heap:%d, flag:%d[err:0x%x, proto:%d, tos:%d]",
162 recv_count, send_count, mesh_layer,
163 MAC2STR(mesh_parent_addr.addr), MAC2STR(from.addr),
164 data.size, esp_get_free_heap_size(), flag, err, data.proto,
171 esp_err_t esp_mesh_comm_p2p_start(void)
173 static bool is_comm_p2p_started = false;
174 if (!is_comm_p2p_started) {
175 is_comm_p2p_started = true;
176 xTaskCreate(esp_mesh_p2p_tx_main, "MPTX", 3072, NULL, 5, NULL);
177 xTaskCreate(esp_mesh_p2p_rx_main, "MPRX", 3072, NULL, 5, NULL);
182 void mesh_event_handler(mesh_event_t event)
184 mesh_addr_t id = {0,};
185 static uint8_t last_layer = 0;
186 ESP_LOGD(MESH_TAG, "esp_event_handler:%d", event.id);
189 case MESH_EVENT_STARTED:
190 esp_mesh_get_id(&id);
191 ESP_LOGI(MESH_TAG, "<MESH_EVENT_STARTED>ID:"MACSTR"", MAC2STR(id.addr));
192 is_mesh_connected = false;
193 mesh_layer = esp_mesh_get_layer();
195 case MESH_EVENT_STOPPED:
196 ESP_LOGI(MESH_TAG, "<MESH_EVENT_STOPPED>");
197 is_mesh_connected = false;
198 mesh_layer = esp_mesh_get_layer();
200 case MESH_EVENT_CHILD_CONNECTED:
201 ESP_LOGI(MESH_TAG, "<MESH_EVENT_CHILD_CONNECTED>aid:%d, "MACSTR"",
202 event.info.child_connected.aid,
203 MAC2STR(event.info.child_connected.mac));
205 case MESH_EVENT_CHILD_DISCONNECTED:
206 ESP_LOGI(MESH_TAG, "<MESH_EVENT_CHILD_DISCONNECTED>aid:%d, "MACSTR"",
207 event.info.child_disconnected.aid,
208 MAC2STR(event.info.child_disconnected.mac));
210 case MESH_EVENT_ROUTING_TABLE_ADD:
211 ESP_LOGW(MESH_TAG, "<MESH_EVENT_ROUTING_TABLE_ADD>add %d, new:%d",
212 event.info.routing_table.rt_size_change,
213 event.info.routing_table.rt_size_new);
215 case MESH_EVENT_ROUTING_TABLE_REMOVE:
216 ESP_LOGW(MESH_TAG, "<MESH_EVENT_ROUTING_TABLE_REMOVE>remove %d, new:%d",
217 event.info.routing_table.rt_size_change,
218 event.info.routing_table.rt_size_new);
220 case MESH_EVENT_NO_PARNET_FOUND:
221 ESP_LOGI(MESH_TAG, "<MESH_EVENT_NO_PARNET_FOUND>scan times:%d",
222 event.info.no_parent.scan_times);
223 /* TODO handler for the failure */
225 case MESH_EVENT_PARENT_CONNECTED:
226 esp_mesh_get_id(&id);
227 mesh_layer = event.info.connected.self_layer;
228 memcpy(&mesh_parent_addr.addr, event.info.connected.connected.bssid, 6);
230 "<MESH_EVENT_PARENT_CONNECTED>layer:%d-->%d, parent:"MACSTR"%s, ID:"MACSTR"",
231 last_layer, mesh_layer, MAC2STR(mesh_parent_addr.addr),
232 esp_mesh_is_root() ? "<ROOT>" :
233 (mesh_layer == 2) ? "<layer2>" : "", MAC2STR(id.addr));
234 last_layer = mesh_layer;
235 mesh_connected_indicator(mesh_layer);
236 is_mesh_connected = true;
237 if (esp_mesh_is_root()) {
238 tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA);
240 esp_mesh_comm_p2p_start();
242 case MESH_EVENT_PARENT_DISCONNECTED:
244 "<MESH_EVENT_PARENT_DISCONNECTED>reason:%d",
245 event.info.disconnected.reason);
246 is_mesh_connected = false;
247 mesh_disconnected_indicator();
248 mesh_layer = esp_mesh_get_layer();
250 case MESH_EVENT_LAYER_CHANGE:
251 mesh_layer = event.info.layer_change.new_layer;
252 ESP_LOGI(MESH_TAG, "<MESH_EVENT_LAYER_CHANGE>layer:%d-->%d%s",
253 last_layer, mesh_layer,
254 esp_mesh_is_root() ? "<ROOT>" :
255 (mesh_layer == 2) ? "<layer2>" : "");
256 last_layer = mesh_layer;
257 mesh_connected_indicator(mesh_layer);
259 case MESH_EVENT_ROOT_ADDRESS:
260 ESP_LOGI(MESH_TAG, "<MESH_EVENT_ROOT_ADDRESS>root address:"MACSTR"",
261 MAC2STR(event.info.root_addr.addr));
263 case MESH_EVENT_ROOT_GOT_IP:
264 /* root starts to connect to server */
266 "<MESH_EVENT_ROOT_GOT_IP>sta ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR,
267 IP2STR(&event.info.got_ip.ip_info.ip),
268 IP2STR(&event.info.got_ip.ip_info.netmask),
269 IP2STR(&event.info.got_ip.ip_info.gw));
271 case MESH_EVENT_ROOT_LOST_IP:
272 ESP_LOGI(MESH_TAG, "<MESH_EVENT_ROOT_LOST_IP>");
274 case MESH_EVENT_VOTE_STARTED:
276 "<MESH_EVENT_VOTE_STARTED>attempts:%d, reason:%d, rc_addr:"MACSTR"",
277 event.info.vote_started.attempts,
278 event.info.vote_started.reason,
279 MAC2STR(event.info.vote_started.rc_addr.addr));
281 case MESH_EVENT_VOTE_STOPPED:
282 ESP_LOGI(MESH_TAG, "<MESH_EVENT_VOTE_STOPPED>");
284 case MESH_EVENT_ROOT_SWITCH_REQ:
286 "<MESH_EVENT_ROOT_SWITCH_REQ>reason:%d, rc_addr:"MACSTR"",
287 event.info.switch_req.reason,
288 MAC2STR( event.info.switch_req.rc_addr.addr));
290 case MESH_EVENT_ROOT_SWITCH_ACK:
292 mesh_layer = esp_mesh_get_layer();
293 esp_mesh_get_parent_bssid(&mesh_parent_addr);
294 ESP_LOGI(MESH_TAG, "<MESH_EVENT_ROOT_SWITCH_ACK>layer:%d, parent:"MACSTR"", mesh_layer, MAC2STR(mesh_parent_addr.addr));
296 case MESH_EVENT_TODS_STATE:
297 ESP_LOGI(MESH_TAG, "<MESH_EVENT_TODS_REACHABLE>state:%d",
298 event.info.toDS_state);
300 case MESH_EVENT_ROOT_FIXED:
301 ESP_LOGI(MESH_TAG, "<MESH_EVENT_ROOT_FIXED>%s",
302 event.info.root_fixed.is_fixed ? "fixed" : "not fixed");
304 case MESH_EVENT_ROOT_ASKED_YIELD:
306 "<MESH_EVENT_ROOT_ASKED_YIELD>"MACSTR", rssi:%d, capacity:%d",
307 MAC2STR(event.info.root_conflict.addr),
308 event.info.root_conflict.rssi,
309 event.info.root_conflict.capacity);
311 case MESH_EVENT_CHANNEL_SWITCH:
312 ESP_LOGI(MESH_TAG, "<MESH_EVENT_CHANNEL_SWITCH>");
314 case MESH_EVENT_SCAN_DONE:
315 ESP_LOGI(MESH_TAG, "<MESH_EVENT_SCAN_DONE>number:%d",
316 event.info.scan_done.number);
319 ESP_LOGI(MESH_TAG, "unknown id:%d", event.id);
326 ESP_ERROR_CHECK(mesh_light_init());
327 ESP_ERROR_CHECK(nvs_flash_init());
328 /* tcpip initialization */
329 tcpip_adapter_init();
331 * stop DHCP server on softAP interface by default
332 * stop DHCP client on station interface by default
334 ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP));
335 ESP_ERROR_CHECK(tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA));
337 /* static ip settings */
338 tcpip_adapter_ip_info_t sta_ip;
339 sta_ip.ip.addr = ipaddr_addr("192.168.1.102");
340 sta_ip.gw.addr = ipaddr_addr("192.168.1.1");
341 sta_ip.netmask.addr = ipaddr_addr("255.255.255.0");
342 tcpip_adapter_set_ip_info(WIFI_IF_STA, &sta_ip);
344 /* wifi initialization */
345 ESP_ERROR_CHECK(esp_event_loop_init(NULL, NULL));
346 wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();
347 ESP_ERROR_CHECK(esp_wifi_init(&config));
348 ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH));
349 ESP_ERROR_CHECK(esp_wifi_start());
350 /* mesh initialization */
351 ESP_ERROR_CHECK(esp_mesh_init());
352 ESP_ERROR_CHECK(esp_mesh_set_max_layer(CONFIG_MESH_MAX_LAYER));
353 ESP_ERROR_CHECK(esp_mesh_set_ap_authmode(CONFIG_MESH_AP_AUTHMODE));
354 ESP_ERROR_CHECK(esp_mesh_set_vote_percentage(1));
355 ESP_ERROR_CHECK(esp_mesh_set_ap_assoc_expire(10));
357 ESP_ERROR_CHECK(esp_mesh_fix_root(1));
359 mesh_cfg_t cfg = MESH_INIT_CONFIG_DEFAULT();
361 memcpy((uint8_t *) &cfg.mesh_id, MESH_ID, 6);
362 /* mesh event callback */
363 cfg.event_cb = &mesh_event_handler;
365 cfg.channel = CONFIG_MESH_CHANNEL;
366 cfg.router.ssid_len = strlen(CONFIG_MESH_ROUTER_SSID);
367 memcpy((uint8_t *) &cfg.router.ssid, CONFIG_MESH_ROUTER_SSID, cfg.router.ssid_len);
368 memcpy((uint8_t *) &cfg.router.password, CONFIG_MESH_ROUTER_PASSWD,
369 strlen(CONFIG_MESH_ROUTER_PASSWD));
371 cfg.mesh_ap.max_connection = CONFIG_MESH_AP_CONNECTIONS;
372 memcpy((uint8_t *) &cfg.mesh_ap.password, CONFIG_MESH_AP_PASSWD,
373 strlen(CONFIG_MESH_AP_PASSWD));
374 ESP_ERROR_CHECK(esp_mesh_set_config(&cfg));
375 /* set RSSI threshold for connecting to the root */
376 mesh_switch_parent_t switch_paras ;
377 ESP_ERROR_CHECK(esp_mesh_get_switch_parent_paras(&switch_paras));
378 switch_paras.select_rssi = -55;
379 switch_paras.cnx_rssi = -65;
380 switch_paras.duration_ms = 120 * 1000;
381 switch_paras.switch_rssi = -65;
382 ESP_ERROR_CHECK(esp_mesh_set_switch_parent_paras(&switch_paras));
384 ESP_ERROR_CHECK(esp_mesh_start());
385 ESP_LOGI(MESH_TAG, "mesh starts successfully, heap:%d, %s\n", esp_get_free_heap_size(),
386 esp_mesh_is_root_fixed() ? "root fixed" : "root not fixed");