diff --git a/internal_communication/.devcontainer/Dockerfile b/internal_communication/.devcontainer/Dockerfile new file mode 100644 index 000000000..dafb8adbb --- /dev/null +++ b/internal_communication/.devcontainer/Dockerfile @@ -0,0 +1,13 @@ +ARG DOCKER_TAG=latest +FROM espressif/idf:${DOCKER_TAG} + +ENV LC_ALL=C.UTF-8 +ENV LANG=C.UTF-8 + +RUN apt-get update -y && apt-get install udev -y + +RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc + +ENTRYPOINT [ "/opt/esp/entrypoint.sh" ] + +CMD ["/bin/bash", "-c"] \ No newline at end of file diff --git a/internal_communication/.devcontainer/devcontainer.json b/internal_communication/.devcontainer/devcontainer.json new file mode 100644 index 000000000..b80178618 --- /dev/null +++ b/internal_communication/.devcontainer/devcontainer.json @@ -0,0 +1,21 @@ +{ + "name": "ESP-IDF QEMU", + "build": { + "dockerfile": "Dockerfile" + }, + "customizations": { + "vscode": { + "settings": { + "terminal.integrated.defaultProfile.linux": "bash", + "idf.espIdfPath": "/opt/esp/idf", + "idf.toolsPath": "/opt/esp", + "idf.gitPath": "/usr/bin/git" + }, + "extensions": [ + "espressif.esp-idf-extension", + "espressif.esp-idf-web" + ] + } + }, + "runArgs": ["--privileged"] +} \ No newline at end of file diff --git a/internal_communication/.vscode/c_cpp_properties.json b/internal_communication/.vscode/c_cpp_properties.json new file mode 100644 index 000000000..75ad88aad --- /dev/null +++ b/internal_communication/.vscode/c_cpp_properties.json @@ -0,0 +1,23 @@ +{ + "configurations": [ + { + "name": "ESP-IDF", + "compilerPath": "${default}", + "compileCommands": "${config:idf.buildPath}/compile_commands.json", + "includePath": [ + "${config:idf.espIdfPath}/components/**", + "${config:idf.espIdfPathWin}/components/**", + "${workspaceFolder}/**" + ], + "browse": { + "path": [ + "${config:idf.espIdfPath}/components", + "${config:idf.espIdfPathWin}/components", + "${workspaceFolder}" + ], + "limitSymbolsToIncludedHeaders": true + } + } + ], + "version": 4 +} \ No newline at end of file diff --git a/internal_communication/.vscode/launch.json b/internal_communication/.vscode/launch.json new file mode 100644 index 000000000..2511a38aa --- /dev/null +++ b/internal_communication/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "gdbtarget", + "request": "attach", + "name": "Eclipse CDT GDB Adapter" + }, + { + "type": "espidf", + "name": "Launch", + "request": "launch" + } + ] +} \ No newline at end of file diff --git a/internal_communication/.vscode/settings.json b/internal_communication/.vscode/settings.json new file mode 100644 index 000000000..40c3f58b7 --- /dev/null +++ b/internal_communication/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "C_Cpp.intelliSenseEngine": "default", + "idf.espIdfPath": "/home/abobkov/esp/esp-idf", + "idf.toolsPath": "/home/abobkov/.espressif" +} diff --git a/internal_communication/CMakeLists.txt b/internal_communication/CMakeLists.txt new file mode 100644 index 000000000..71de1a1f0 --- /dev/null +++ b/internal_communication/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(internal_communication) diff --git a/internal_communication/README.md b/internal_communication/README.md new file mode 100644 index 000000000..a7179b9b9 --- /dev/null +++ b/internal_communication/README.md @@ -0,0 +1,26 @@ +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | + +# Mesh Internal Communication Example + +This example demonstrates how to use the mesh APIs to set up a mesh network, send and receive messages over the mesh network and etc. + +Features Demonstrated + +- mesh initialization + +- mesh configuration + +- mesh start + +- mesh event handler + +- root send and receive + +- other nodes receive + +Open project configuration menu (`idf.py menuconfig`) to configure the mesh network channel, router SSID, router password and mesh softAP settings. + +When the mesh network is established and if you happen to run this example on ESP-WROVER-KIT boards, the RGB light indicator will show you on which layer devices are. +The pink reprents root; the yellow reprents layer 2; the red reprents layer 3; the blue reprents layer 4; the green reprents layer 5; the white reprents layer greater than 5. +Root continuously sends an On / Off control message to all devices in its routing table. Devices including root itself receive this message and do the On / Off. diff --git a/internal_communication/main/CMakeLists.txt b/internal_communication/main/CMakeLists.txt new file mode 100644 index 000000000..686ab05ac --- /dev/null +++ b/internal_communication/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "mesh_light.c" + "mesh_main.c" + INCLUDE_DIRS "." "include") diff --git a/internal_communication/main/Kconfig.projbuild b/internal_communication/main/Kconfig.projbuild new file mode 100644 index 000000000..b3c530c04 --- /dev/null +++ b/internal_communication/main/Kconfig.projbuild @@ -0,0 +1,172 @@ +menu "Example Configuration" + + choice + bool "Mesh Topology" + default MESH_TOPO_TREE + help + Mesh Network Topology. + + config MESH_TOPO_TREE + bool "MESH_TOPO_TREE" + config MESH_TOPO_CHAIN + bool "MESH_TOPO_CHAIN" + endchoice + + config MESH_TOPOLOGY + int + default 0 if MESH_TOPO_TREE + default 1 if MESH_TOPO_CHAIN + help + Mesh Network Topology. + + config MESH_ENABLE_PS + bool "Enable mesh PS (power save) function" + default y + help + Enable/Disable Power Save function. + + choice + bool "Mesh PS device duty cycle type" + depends on MESH_ENABLE_PS + default MESH_PS_DEV_DUTY_TYPE_REQUEST + help + Mesh PS device duty cycle type. + + config MESH_PS_DEV_DUTY_TYPE_REQUEST + bool "MESH_PS_DEV_DUTY_TYPE_REQUEST" + config MESH_PS_DEV_DUTY_TYPE_DEMAND + bool "MESH_PS_DEV_DUTY_TYPE_DEMAND" + endchoice + + config MESH_PS_DEV_DUTY_TYPE + int + depends on MESH_ENABLE_PS + default 1 if MESH_PS_DEV_DUTY_TYPE_REQUEST + default 4 if MESH_PS_DEV_DUTY_TYPE_DEMAND + help + Mesh PS device duty cycle type. + + config MESH_PS_DEV_DUTY + int "Mesh PS device duty cycle" + depends on MESH_ENABLE_PS + range 1 100 + default 10 + help + Mesh PS device duty cycle. + + config MESH_PS_NWK_DUTY + int "Mesh PS network duty cycle" + depends on MESH_ENABLE_PS + range 1 100 + default 10 + help + Mesh PS network duty cycle. + + config MESH_PS_NWK_DUTY_DURATION + int "Mesh PS network duty cycle duration (unit: minutes)" + depends on MESH_ENABLE_PS + range -1 100 + default -1 + help + Mesh PS network duty cycle duration. + + choice + bool "Mesh PS network duty cycle rule" + depends on MESH_ENABLE_PS + default MESH_PS_NETWORK_DUTY_APPLIED_ENTIRE + help + Mesh PS network duty cycle rule. + + config MESH_PS_NETWORK_DUTY_APPLIED_ENTIRE + bool "MESH_PS_NETWORK_DUTY_APPLIED_ENTIRE" + config MESH_PS_NETWORK_DUTY_APPLIED_UPLINK + bool "MESH_PS_NETWORK_DUTY_APPLIED_UPLINK" + endchoice + + config MESH_PS_NWK_DUTY_RULE + int + depends on MESH_ENABLE_PS + default 0 if MESH_PS_NETWORK_DUTY_APPLIED_ENTIRE + default 1 if MESH_PS_NETWORK_DUTY_APPLIED_UPLINK + help + Mesh PS network duty cycle rule. + + config MESH_MAX_LAYER + int "Mesh Max Layer" + range 1 25 if MESH_TOPO_TREE + range 1 1000 if MESH_TOPO_CHAIN + default 6 + help + Max layer allowed in mesh network. + + config MESH_CHANNEL + int "channel" + range 0 14 + default 0 + help + mesh network channel. + + config MESH_ROUTER_SSID + string "Router SSID" + default "ROUTER_SSID" + help + Router SSID. + + config MESH_ROUTER_PASSWD + string "Router password" + default "ROUTER_PASSWD" + help + Router password. + + choice + bool "Mesh AP Authentication Mode" + default WIFI_AUTH_WPA2_PSK + help + Authentication mode. + + config WIFI_AUTH_OPEN + bool "WIFI_AUTH_OPEN" + config WIFI_AUTH_WPA_PSK + bool "WIFI_AUTH_WPA_PSK" + config WIFI_AUTH_WPA2_PSK + bool "WIFI_AUTH_WPA2_PSK" + config WIFI_AUTH_WPA_WPA2_PSK + bool "WIFI_AUTH_WPA_WPA2_PSK" + endchoice + + config MESH_AP_AUTHMODE + int + default 0 if WIFI_AUTH_OPEN + default 2 if WIFI_AUTH_WPA_PSK + default 3 if WIFI_AUTH_WPA2_PSK + default 4 if WIFI_AUTH_WPA_WPA2_PSK + help + Mesh AP authentication mode. + + config MESH_AP_PASSWD + string "Mesh AP Password" + default "MAP_PASSWD" + help + Mesh AP password. + + config MESH_AP_CONNECTIONS + int "Mesh AP Connections" + range 1 10 + default 6 + help + The number of mesh stations allowed to connect in. + + config MESH_NON_MESH_AP_CONNECTIONS + int "Mesh Non Mesh AP Connections" + range 0 9 + default 0 + help + The number of non-mesh stations allowed to connect in. + + config MESH_ROUTE_TABLE_SIZE + int "Mesh Routing Table Size" + range 1 300 + default 50 + help + The number of devices over the network(max: 300). +endmenu diff --git a/internal_communication/main/include/mesh_light.h b/internal_communication/main/include/mesh_light.h new file mode 100644 index 000000000..e42a4a3ff --- /dev/null +++ b/internal_communication/main/include/mesh_light.h @@ -0,0 +1,57 @@ +/* Mesh Internal Communication 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. +*/ + +#ifndef __MESH_LIGHT_H__ +#define __MESH_LIGHT_H__ + +#include "esp_err.h" + +/******************************************************* + * Constants + *******************************************************/ +#define MESH_LIGHT_RED (0xff) +#define MESH_LIGHT_GREEN (0xfe) +#define MESH_LIGHT_BLUE (0xfd) +#define MESH_LIGHT_YELLOW (0xfc) +#define MESH_LIGHT_PINK (0xfb) +#define MESH_LIGHT_INIT (0xfa) +#define MESH_LIGHT_WARNING (0xf9) + +#define MESH_TOKEN_ID (0x0) +#define MESH_TOKEN_VALUE (0xbeef) +#define MESH_CONTROL_CMD (0x2) + +/******************************************************* + * Type Definitions + *******************************************************/ + +/******************************************************* + * Structures + *******************************************************/ +typedef struct { + uint8_t cmd; + bool on; + uint8_t token_id; + uint16_t token_value; +} mesh_light_ctl_t; + +/******************************************************* + * Variables Declarations + *******************************************************/ + +/******************************************************* + * Function Definitions + *******************************************************/ +esp_err_t mesh_light_init(void); +esp_err_t mesh_light_set(int color); +esp_err_t mesh_light_process(mesh_addr_t *from, uint8_t *buf, uint16_t len); +void mesh_connected_indicator(int layer); +void mesh_disconnected_indicator(void); + +#endif /* __MESH_LIGHT_H__ */ diff --git a/internal_communication/main/mesh_light.c b/internal_communication/main/mesh_light.c new file mode 100644 index 000000000..8d0c7f955 --- /dev/null +++ b/internal_communication/main/mesh_light.c @@ -0,0 +1,182 @@ +/* Mesh Internal Communication 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 +#include "esp_err.h" +#include "esp_mesh.h" +#include "mesh_light.h" +#include "driver/gpio.h" +#include "driver/ledc.h" + +/******************************************************* + * Constants + *******************************************************/ +/* RGB configuration on ESP-WROVER-KIT board */ +#define LEDC_IO_0 (0) +#define LEDC_IO_1 (2) +#define LEDC_IO_2 (4) +#define LEDC_IO_3 (5) + +/******************************************************* + * Variable Definitions + *******************************************************/ +static bool s_light_inited = false; + +/******************************************************* + * Function Definitions + *******************************************************/ +esp_err_t mesh_light_init(void) +{ + if (s_light_inited == true) { + return ESP_OK; + } + s_light_inited = true; + + ledc_timer_config_t ledc_timer = { + .duty_resolution = LEDC_TIMER_13_BIT, + .freq_hz = 5000, + .speed_mode = LEDC_LOW_SPEED_MODE, + .timer_num = LEDC_TIMER_0, + .clk_cfg = LEDC_AUTO_CLK, + }; + ledc_timer_config(&ledc_timer); + + ledc_channel_config_t ledc_channel = { + .channel = LEDC_CHANNEL_0, + .duty = 100, + .gpio_num = LEDC_IO_0, + .intr_type = LEDC_INTR_FADE_END, + .speed_mode = LEDC_LOW_SPEED_MODE, + .timer_sel = LEDC_TIMER_0, + .hpoint = 0, + }; + ledc_channel_config(&ledc_channel); + ledc_channel.channel = LEDC_CHANNEL_1; + ledc_channel.gpio_num = LEDC_IO_1; + ledc_channel_config(&ledc_channel); + ledc_channel.channel = LEDC_CHANNEL_2; + ledc_channel.gpio_num = LEDC_IO_2; + ledc_channel_config(&ledc_channel); + ledc_channel.channel = LEDC_CHANNEL_3; + ledc_channel.gpio_num = LEDC_IO_3; + ledc_channel_config(&ledc_channel); + ledc_fade_func_install(0); + + mesh_light_set(MESH_LIGHT_INIT); + return ESP_OK; +} + +esp_err_t mesh_light_set(int color) +{ + switch (color) { + case MESH_LIGHT_RED: + /* Red */ + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 3000); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 0); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, 0); + break; + case MESH_LIGHT_GREEN: + /* Green */ + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 3000); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, 0); + break; + case MESH_LIGHT_BLUE: + /* Blue */ + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 0); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, 3000); + break; + case MESH_LIGHT_YELLOW: + /* Yellow */ + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 3000); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 3000); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, 0); + break; + case MESH_LIGHT_PINK: + /* Pink */ + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 3000); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 0); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, 3000); + break; + case MESH_LIGHT_INIT: + /* can't say */ + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 3000); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, 3000); + break; + case MESH_LIGHT_WARNING: + /* warning */ + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 3000); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 3000); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, 3000); + break; + default: + /* off */ + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 0); + ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, 0); + } + + ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0); + ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1); + ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2); + + return ESP_OK; +} + +void mesh_connected_indicator(int layer) +{ + switch (layer) { + case 1: + mesh_light_set(MESH_LIGHT_PINK); + break; + case 2: + mesh_light_set(MESH_LIGHT_YELLOW); + break; + case 3: + mesh_light_set(MESH_LIGHT_RED); + break; + case 4: + mesh_light_set(MESH_LIGHT_BLUE); + break; + case 5: + mesh_light_set(MESH_LIGHT_GREEN); + break; + case 6: + mesh_light_set(MESH_LIGHT_WARNING); + break; + default: + mesh_light_set(0); + } +} + +void mesh_disconnected_indicator(void) +{ + mesh_light_set(MESH_LIGHT_WARNING); +} + +esp_err_t mesh_light_process(mesh_addr_t *from, uint8_t *buf, uint16_t len) +{ + mesh_light_ctl_t *in = (mesh_light_ctl_t *) buf; + if (!from || !buf || len < sizeof(mesh_light_ctl_t)) { + return ESP_FAIL; + } + if (in->token_id != MESH_TOKEN_ID || in->token_value != MESH_TOKEN_VALUE) { + return ESP_FAIL; + } + if (in->cmd == MESH_CONTROL_CMD) { + if (in->on) { + mesh_connected_indicator(esp_mesh_get_layer()); + } else { + mesh_light_set(0); + } + } + return ESP_OK; +} diff --git a/internal_communication/main/mesh_main.c b/internal_communication/main/mesh_main.c new file mode 100644 index 000000000..585df23cc --- /dev/null +++ b/internal_communication/main/mesh_main.c @@ -0,0 +1,452 @@ +/* Mesh Internal Communication 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 +#include +#include "esp_wifi.h" +#include "esp_mac.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_mesh.h" +#include "esp_mesh_internal.h" +#include "mesh_light.h" +#include "nvs_flash.h" + +/******************************************************* + * Macros + *******************************************************/ + +/******************************************************* + * Constants + *******************************************************/ +#define RX_SIZE (1500) +#define TX_SIZE (1460) + +/******************************************************* + * Variable Definitions + *******************************************************/ +static const char *MESH_TAG = "mesh_main"; +static const uint8_t MESH_ID[6] = { 0x77, 0x77, 0x77, 0x77, 0x77, 0x77}; +static uint8_t tx_buf[TX_SIZE] = { 0, }; +static uint8_t rx_buf[RX_SIZE] = { 0, }; +static bool is_running = true; +static bool is_mesh_connected = false; +static mesh_addr_t mesh_parent_addr; +static int mesh_layer = -1; +static esp_netif_t *netif_sta = NULL; + +mesh_light_ctl_t light_on = { + .cmd = MESH_CONTROL_CMD, + .on = 1, + .token_id = MESH_TOKEN_ID, + .token_value = MESH_TOKEN_VALUE, +}; + +mesh_light_ctl_t light_off = { + .cmd = MESH_CONTROL_CMD, + .on = 0, + .token_id = MESH_TOKEN_ID, + .token_value = MESH_TOKEN_VALUE, +}; + +/******************************************************* + * Function Declarations + *******************************************************/ + +/******************************************************* + * Function Definitions + *******************************************************/ +void esp_mesh_p2p_tx_main(void *arg) +{ + int i; + esp_err_t err; + int send_count = 0; + mesh_addr_t route_table[CONFIG_MESH_ROUTE_TABLE_SIZE]; + int route_table_size = 0; + mesh_data_t data; + data.data = tx_buf; + data.size = sizeof(tx_buf); + data.proto = MESH_PROTO_BIN; + data.tos = MESH_TOS_P2P; + is_running = true; + + while (is_running) { + /* non-root do nothing but print */ + if (!esp_mesh_is_root()) { + ESP_LOGI(MESH_TAG, "layer:%d, rtableSize:%d, %s", mesh_layer, + esp_mesh_get_routing_table_size(), + (is_mesh_connected && esp_mesh_is_root()) ? "ROOT" : is_mesh_connected ? "NODE" : "DISCONNECT"); + vTaskDelay(10 * 1000 / portTICK_PERIOD_MS); + continue; + } + esp_mesh_get_routing_table((mesh_addr_t *) &route_table, + CONFIG_MESH_ROUTE_TABLE_SIZE * 6, &route_table_size); + if (send_count && !(send_count % 100)) { + ESP_LOGI(MESH_TAG, "size:%d/%d,send_count:%d", route_table_size, + esp_mesh_get_routing_table_size(), send_count); + } + send_count++; + tx_buf[25] = (send_count >> 24) & 0xff; + tx_buf[24] = (send_count >> 16) & 0xff; + tx_buf[23] = (send_count >> 8) & 0xff; + tx_buf[22] = (send_count >> 0) & 0xff; + if (send_count % 2) { + memcpy(tx_buf, (uint8_t *)&light_on, sizeof(light_on)); + } else { + memcpy(tx_buf, (uint8_t *)&light_off, sizeof(light_off)); + } + + for (i = 0; i < route_table_size; i++) { + err = esp_mesh_send(&route_table[i], &data, MESH_DATA_P2P, NULL, 0); + if (err) { + ESP_LOGE(MESH_TAG, + "[ROOT-2-UNICAST:%d][L:%d]parent:"MACSTR" to "MACSTR", heap:%" PRId32 "[err:0x%x, proto:%d, tos:%d]", + send_count, mesh_layer, MAC2STR(mesh_parent_addr.addr), + MAC2STR(route_table[i].addr), esp_get_minimum_free_heap_size(), + err, data.proto, data.tos); + } else if (!(send_count % 100)) { + ESP_LOGW(MESH_TAG, + "[ROOT-2-UNICAST:%d][L:%d][rtableSize:%d]parent:"MACSTR" to "MACSTR", heap:%" PRId32 "[err:0x%x, proto:%d, tos:%d]", + send_count, mesh_layer, + esp_mesh_get_routing_table_size(), + MAC2STR(mesh_parent_addr.addr), + MAC2STR(route_table[i].addr), esp_get_minimum_free_heap_size(), + err, data.proto, data.tos); + } + } + /* if route_table_size is less than 10, add delay to avoid watchdog in this task. */ + if (route_table_size < 10) { + vTaskDelay(1 * 1000 / portTICK_PERIOD_MS); + } + } + vTaskDelete(NULL); +} + +void esp_mesh_p2p_rx_main(void *arg) +{ + int recv_count = 0; + esp_err_t err; + mesh_addr_t from; + int send_count = 0; + mesh_data_t data; + int flag = 0; + data.data = rx_buf; + data.size = RX_SIZE; + is_running = true; + + while (is_running) { + data.size = RX_SIZE; + err = esp_mesh_recv(&from, &data, portMAX_DELAY, &flag, NULL, 0); + if (err != ESP_OK || !data.size) { + ESP_LOGE(MESH_TAG, "err:0x%x, size:%d", err, data.size); + continue; + } + /* extract send count */ + if (data.size >= sizeof(send_count)) { + send_count = (data.data[25] << 24) | (data.data[24] << 16) + | (data.data[23] << 8) | data.data[22]; + } + recv_count++; + /* process light control */ + mesh_light_process(&from, data.data, data.size); + if (!(recv_count % 1)) { + ESP_LOGW(MESH_TAG, + "[#RX:%d/%d][L:%d] parent:"MACSTR", receive from "MACSTR", size:%d, heap:%" PRId32 ", flag:%d[err:0x%x, proto:%d, tos:%d]", + recv_count, send_count, mesh_layer, + MAC2STR(mesh_parent_addr.addr), MAC2STR(from.addr), + data.size, esp_get_minimum_free_heap_size(), flag, err, data.proto, + data.tos); + } + } + vTaskDelete(NULL); +} + +esp_err_t esp_mesh_comm_p2p_start(void) +{ + static bool is_comm_p2p_started = false; + if (!is_comm_p2p_started) { + is_comm_p2p_started = true; + xTaskCreate(esp_mesh_p2p_tx_main, "MPTX", 3072, NULL, 5, NULL); + xTaskCreate(esp_mesh_p2p_rx_main, "MPRX", 3072, NULL, 5, NULL); + } + return ESP_OK; +} + +void mesh_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + mesh_addr_t id = {0,}; + static uint16_t last_layer = 0; + + switch (event_id) { + case MESH_EVENT_STARTED: { + esp_mesh_get_id(&id); + ESP_LOGI(MESH_TAG, "ID:"MACSTR"", MAC2STR(id.addr)); + is_mesh_connected = false; + mesh_layer = esp_mesh_get_layer(); + } + break; + case MESH_EVENT_STOPPED: { + ESP_LOGI(MESH_TAG, ""); + is_mesh_connected = false; + mesh_layer = esp_mesh_get_layer(); + } + break; + case MESH_EVENT_CHILD_CONNECTED: { + mesh_event_child_connected_t *child_connected = (mesh_event_child_connected_t *)event_data; + ESP_LOGI(MESH_TAG, "aid:%d, "MACSTR"", + child_connected->aid, + MAC2STR(child_connected->mac)); + } + break; + case MESH_EVENT_CHILD_DISCONNECTED: { + mesh_event_child_disconnected_t *child_disconnected = (mesh_event_child_disconnected_t *)event_data; + ESP_LOGI(MESH_TAG, "aid:%d, "MACSTR"", + child_disconnected->aid, + MAC2STR(child_disconnected->mac)); + } + break; + case MESH_EVENT_ROUTING_TABLE_ADD: { + mesh_event_routing_table_change_t *routing_table = (mesh_event_routing_table_change_t *)event_data; + ESP_LOGW(MESH_TAG, "add %d, new:%d, layer:%d", + routing_table->rt_size_change, + routing_table->rt_size_new, mesh_layer); + } + break; + case MESH_EVENT_ROUTING_TABLE_REMOVE: { + mesh_event_routing_table_change_t *routing_table = (mesh_event_routing_table_change_t *)event_data; + ESP_LOGW(MESH_TAG, "remove %d, new:%d, layer:%d", + routing_table->rt_size_change, + routing_table->rt_size_new, mesh_layer); + } + break; + case MESH_EVENT_NO_PARENT_FOUND: { + mesh_event_no_parent_found_t *no_parent = (mesh_event_no_parent_found_t *)event_data; + ESP_LOGI(MESH_TAG, "scan times:%d", + no_parent->scan_times); + } + /* TODO handler for the failure */ + break; + case MESH_EVENT_PARENT_CONNECTED: { + mesh_event_connected_t *connected = (mesh_event_connected_t *)event_data; + esp_mesh_get_id(&id); + mesh_layer = connected->self_layer; + memcpy(&mesh_parent_addr.addr, connected->connected.bssid, 6); + ESP_LOGI(MESH_TAG, + "layer:%d-->%d, parent:"MACSTR"%s, ID:"MACSTR", duty:%d", + last_layer, mesh_layer, MAC2STR(mesh_parent_addr.addr), + esp_mesh_is_root() ? "" : + (mesh_layer == 2) ? "" : "", MAC2STR(id.addr), connected->duty); + last_layer = mesh_layer; + mesh_connected_indicator(mesh_layer); + is_mesh_connected = true; + if (esp_mesh_is_root()) { + esp_netif_dhcpc_stop(netif_sta); + esp_netif_dhcpc_start(netif_sta); + } + esp_mesh_comm_p2p_start(); + } + break; + case MESH_EVENT_PARENT_DISCONNECTED: { + mesh_event_disconnected_t *disconnected = (mesh_event_disconnected_t *)event_data; + ESP_LOGI(MESH_TAG, + "reason:%d", + disconnected->reason); + is_mesh_connected = false; + mesh_disconnected_indicator(); + mesh_layer = esp_mesh_get_layer(); + } + break; + case MESH_EVENT_LAYER_CHANGE: { + mesh_event_layer_change_t *layer_change = (mesh_event_layer_change_t *)event_data; + mesh_layer = layer_change->new_layer; + ESP_LOGI(MESH_TAG, "layer:%d-->%d%s", + last_layer, mesh_layer, + esp_mesh_is_root() ? "" : + (mesh_layer == 2) ? "" : ""); + last_layer = mesh_layer; + mesh_connected_indicator(mesh_layer); + } + break; + case MESH_EVENT_ROOT_ADDRESS: { + mesh_event_root_address_t *root_addr = (mesh_event_root_address_t *)event_data; + ESP_LOGI(MESH_TAG, "root address:"MACSTR"", + MAC2STR(root_addr->addr)); + } + break; + case MESH_EVENT_VOTE_STARTED: { + mesh_event_vote_started_t *vote_started = (mesh_event_vote_started_t *)event_data; + ESP_LOGI(MESH_TAG, + "attempts:%d, reason:%d, rc_addr:"MACSTR"", + vote_started->attempts, + vote_started->reason, + MAC2STR(vote_started->rc_addr.addr)); + } + break; + case MESH_EVENT_VOTE_STOPPED: { + ESP_LOGI(MESH_TAG, ""); + break; + } + case MESH_EVENT_ROOT_SWITCH_REQ: { + mesh_event_root_switch_req_t *switch_req = (mesh_event_root_switch_req_t *)event_data; + ESP_LOGI(MESH_TAG, + "reason:%d, rc_addr:"MACSTR"", + switch_req->reason, + MAC2STR( switch_req->rc_addr.addr)); + } + break; + case MESH_EVENT_ROOT_SWITCH_ACK: { + /* new root */ + mesh_layer = esp_mesh_get_layer(); + esp_mesh_get_parent_bssid(&mesh_parent_addr); + ESP_LOGI(MESH_TAG, "layer:%d, parent:"MACSTR"", mesh_layer, MAC2STR(mesh_parent_addr.addr)); + } + break; + case MESH_EVENT_TODS_STATE: { + mesh_event_toDS_state_t *toDs_state = (mesh_event_toDS_state_t *)event_data; + ESP_LOGI(MESH_TAG, "state:%d", *toDs_state); + } + break; + case MESH_EVENT_ROOT_FIXED: { + mesh_event_root_fixed_t *root_fixed = (mesh_event_root_fixed_t *)event_data; + ESP_LOGI(MESH_TAG, "%s", + root_fixed->is_fixed ? "fixed" : "not fixed"); + } + break; + case MESH_EVENT_ROOT_ASKED_YIELD: { + mesh_event_root_conflict_t *root_conflict = (mesh_event_root_conflict_t *)event_data; + ESP_LOGI(MESH_TAG, + ""MACSTR", rssi:%d, capacity:%d", + MAC2STR(root_conflict->addr), + root_conflict->rssi, + root_conflict->capacity); + } + break; + case MESH_EVENT_CHANNEL_SWITCH: { + mesh_event_channel_switch_t *channel_switch = (mesh_event_channel_switch_t *)event_data; + ESP_LOGI(MESH_TAG, "new channel:%d", channel_switch->channel); + } + break; + case MESH_EVENT_SCAN_DONE: { + mesh_event_scan_done_t *scan_done = (mesh_event_scan_done_t *)event_data; + ESP_LOGI(MESH_TAG, "number:%d", + scan_done->number); + } + break; + case MESH_EVENT_NETWORK_STATE: { + mesh_event_network_state_t *network_state = (mesh_event_network_state_t *)event_data; + ESP_LOGI(MESH_TAG, "is_rootless:%d", + network_state->is_rootless); + } + break; + case MESH_EVENT_STOP_RECONNECTION: { + ESP_LOGI(MESH_TAG, ""); + } + break; + case MESH_EVENT_FIND_NETWORK: { + mesh_event_find_network_t *find_network = (mesh_event_find_network_t *)event_data; + ESP_LOGI(MESH_TAG, "new channel:%d, router BSSID:"MACSTR"", + find_network->channel, MAC2STR(find_network->router_bssid)); + } + break; + case MESH_EVENT_ROUTER_SWITCH: { + mesh_event_router_switch_t *router_switch = (mesh_event_router_switch_t *)event_data; + ESP_LOGI(MESH_TAG, "new router:%s, channel:%d, "MACSTR"", + router_switch->ssid, router_switch->channel, MAC2STR(router_switch->bssid)); + } + break; + case MESH_EVENT_PS_PARENT_DUTY: { + mesh_event_ps_duty_t *ps_duty = (mesh_event_ps_duty_t *)event_data; + ESP_LOGI(MESH_TAG, "duty:%d", ps_duty->duty); + } + break; + case MESH_EVENT_PS_CHILD_DUTY: { + mesh_event_ps_duty_t *ps_duty = (mesh_event_ps_duty_t *)event_data; + ESP_LOGI(MESH_TAG, "cidx:%d, "MACSTR", duty:%d", ps_duty->child_connected.aid-1, + MAC2STR(ps_duty->child_connected.mac), ps_duty->duty); + } + break; + default: + ESP_LOGI(MESH_TAG, "unknown id:%" PRId32 "", event_id); + break; + } +} + +void ip_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data; + ESP_LOGI(MESH_TAG, "IP:" IPSTR, IP2STR(&event->ip_info.ip)); + +} + +void app_main(void) +{ + ESP_ERROR_CHECK(mesh_light_init()); + ESP_ERROR_CHECK(nvs_flash_init()); + /* tcpip initialization */ + ESP_ERROR_CHECK(esp_netif_init()); + /* event initialization */ + ESP_ERROR_CHECK(esp_event_loop_create_default()); + /* create network interfaces for mesh (only station instance saved for further manipulation, soft AP instance ignored */ + ESP_ERROR_CHECK(esp_netif_create_default_wifi_mesh_netifs(&netif_sta, NULL)); + /* wifi initialization */ + wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&config)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &ip_event_handler, NULL)); + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH)); + ESP_ERROR_CHECK(esp_wifi_start()); + /* mesh initialization */ + ESP_ERROR_CHECK(esp_mesh_init()); + ESP_ERROR_CHECK(esp_event_handler_register(MESH_EVENT, ESP_EVENT_ANY_ID, &mesh_event_handler, NULL)); + /* set mesh topology */ + ESP_ERROR_CHECK(esp_mesh_set_topology(CONFIG_MESH_TOPOLOGY)); + /* set mesh max layer according to the topology */ + ESP_ERROR_CHECK(esp_mesh_set_max_layer(CONFIG_MESH_MAX_LAYER)); + ESP_ERROR_CHECK(esp_mesh_set_vote_percentage(1)); + ESP_ERROR_CHECK(esp_mesh_set_xon_qsize(128)); +#ifdef CONFIG_MESH_ENABLE_PS + /* Enable mesh PS function */ + ESP_ERROR_CHECK(esp_mesh_enable_ps()); + /* better to increase the associate expired time, if a small duty cycle is set. */ + ESP_ERROR_CHECK(esp_mesh_set_ap_assoc_expire(60)); + /* better to increase the announce interval to avoid too much management traffic, if a small duty cycle is set. */ + ESP_ERROR_CHECK(esp_mesh_set_announce_interval(600, 3300)); +#else + /* Disable mesh PS function */ + ESP_ERROR_CHECK(esp_mesh_disable_ps()); + ESP_ERROR_CHECK(esp_mesh_set_ap_assoc_expire(10)); +#endif + mesh_cfg_t cfg = MESH_INIT_CONFIG_DEFAULT(); + /* mesh ID */ + memcpy((uint8_t *) &cfg.mesh_id, MESH_ID, 6); + /* router */ + cfg.channel = CONFIG_MESH_CHANNEL; + cfg.router.ssid_len = strlen(CONFIG_MESH_ROUTER_SSID); + memcpy((uint8_t *) &cfg.router.ssid, CONFIG_MESH_ROUTER_SSID, cfg.router.ssid_len); + memcpy((uint8_t *) &cfg.router.password, CONFIG_MESH_ROUTER_PASSWD, + strlen(CONFIG_MESH_ROUTER_PASSWD)); + /* mesh softAP */ + ESP_ERROR_CHECK(esp_mesh_set_ap_authmode(CONFIG_MESH_AP_AUTHMODE)); + cfg.mesh_ap.max_connection = CONFIG_MESH_AP_CONNECTIONS; + cfg.mesh_ap.nonmesh_max_connection = CONFIG_MESH_NON_MESH_AP_CONNECTIONS; + memcpy((uint8_t *) &cfg.mesh_ap.password, CONFIG_MESH_AP_PASSWD, + strlen(CONFIG_MESH_AP_PASSWD)); + ESP_ERROR_CHECK(esp_mesh_set_config(&cfg)); + /* mesh start */ + ESP_ERROR_CHECK(esp_mesh_start()); +#ifdef CONFIG_MESH_ENABLE_PS + /* set the device active duty cycle. (default:10, MESH_PS_DEVICE_DUTY_REQUEST) */ + ESP_ERROR_CHECK(esp_mesh_set_active_duty_cycle(CONFIG_MESH_PS_DEV_DUTY, CONFIG_MESH_PS_DEV_DUTY_TYPE)); + /* set the network active duty cycle. (default:10, -1, MESH_PS_NETWORK_DUTY_APPLIED_ENTIRE) */ + ESP_ERROR_CHECK(esp_mesh_set_network_duty_cycle(CONFIG_MESH_PS_NWK_DUTY, CONFIG_MESH_PS_NWK_DUTY_DURATION, CONFIG_MESH_PS_NWK_DUTY_RULE)); +#endif + ESP_LOGI(MESH_TAG, "mesh starts successfully, heap:%" PRId32 ", %s<%d>%s, ps:%d", esp_get_minimum_free_heap_size(), + esp_mesh_is_root_fixed() ? "root fixed" : "root not fixed", + esp_mesh_get_topology(), esp_mesh_get_topology() ? "(chain)":"(tree)", esp_mesh_is_ps_enabled()); +} diff --git a/internal_communication/sdkconfig.defaults b/internal_communication/sdkconfig.defaults new file mode 100644 index 000000000..4983b4dfe --- /dev/null +++ b/internal_communication/sdkconfig.defaults @@ -0,0 +1 @@ +CONFIG_COMPILER_OPTIMIZATION_SIZE=y