]> granicus.if.org Git - esp-idf/commitdiff
mesh: add manual networking function
authorqiyueixa <qiyuexia@espressif.com>
Mon, 21 May 2018 09:22:04 +0000 (17:22 +0800)
committerqiyueixa <qiyuexia@espressif.com>
Wed, 23 May 2018 10:09:12 +0000 (18:09 +0800)
1. add mesh_assoc_t to esp_mesh_internal.h file.
2. rename "node" to "device" in esp_mesh.h.
3. add MESH_EVENT_SCAN_DONE event.
4. add APIs esp_mesh_scan_get_ap_record() and esp_mesh_scan_get_ap_ie_len() to get scan results.
5. modify API esp_mesh_set_self_organized() by adding parameter "select_parent".
6. modify API esp_mesh_set_parent() by adding parameter "parent_mesh_id"
7. add manual networking example.

components/esp32/include/esp_mesh.h
components/esp32/include/esp_mesh_internal.h
components/esp32/lib
examples/mesh/manual_networking/Makefile [new file with mode: 0644]
examples/mesh/manual_networking/main/Kconfig.projbuild [new file with mode: 0644]
examples/mesh/manual_networking/main/component.mk [new file with mode: 0644]
examples/mesh/manual_networking/main/include/mesh_light.h [new file with mode: 0644]
examples/mesh/manual_networking/main/mesh_light.c [new file with mode: 0644]
examples/mesh/manual_networking/main/mesh_main.c [new file with mode: 0644]

index b504149e13211f93bc75970fcd070e552ead4ae6..14bd21f7eac0013711b95ab8492d74c6a91b2a75 100644 (file)
@@ -68,7 +68,7 @@
  *
  *  In present implementation, applications are able to access mesh stack directly without having to go through LwIP stack.
  *  Applications use esp_mesh_send() and esp_mesh_recv() to send and receive messages over the mesh network.
- *  In mesh stack design, normal nodes don't require LwIP stack. But since IDF hasn't supported system without initializing LwIP stack yet,
+ *  In mesh stack design, normal devices don't require LwIP stack. But since IDF hasn't supported system without initializing LwIP stack yet,
  *  applications still need to do LwIP initialization and two more things are required to be done
  *  (1)stop DHCP server on softAP interface by default
  *  (2)stop DHCP client on station interface by default.
@@ -78,7 +78,7 @@
  *  tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA);
  *
  *  Over the mesh network, only root is able to access external IP network.
- *  In application mesh event handler, once a node becomes a root, start DHCP client immediately if DHCP is chosen.
+ *  In application mesh event handler, once a device becomes a root, start DHCP client immediately if DHCP is chosen.
  */
 
 #ifndef __ESP_MESH_H__
@@ -142,6 +142,14 @@ extern "C" {
 #define MESH_OPT_SEND_GROUP     (7)     /**< data transmission by group; used with esp_mesh_send() and shall have payload */
 #define MESH_OPT_RECV_DS_ADDR   (8)     /**< return a remote IP address; used with esp_mesh_send() and esp_mesh_recv() */
 
+/**
+ * @brief flag of mesh networking IE
+ */
+#define MESH_ASSOC_FLAG_VOTE_IN_PROGRESS    (0x02)     /**< vote in progress */
+#define MESH_ASSOC_FLAG_NETWORK_FREE        (0x08)     /**< no root in current network */
+#define MESH_ASSOC_FLAG_ROOTS_FOUND         (0x20)     /**< root conflict is found */
+#define MESH_ASSOC_FLAG_ROOT_FIXED          (0x40)     /**< root is fixed */
+
 /*******************************************************
  *                Enumerations
  *******************************************************/
@@ -172,19 +180,21 @@ typedef enum {
                                              and this device is specified to be a root by users, users should set a new parent
                                              for this device. if self organized is enabled, this device will find a new parent
                                              by itself, users could ignore this event. */
-    MESH_EVENT_ROOT_FIXED,              /**< When nodes join a network, if the setting of Root Fixed for one node is different
-                                             from that of its parent, the node will update the setting the same as its parent's.
-                                             Root Fixed setting of each node is variable as that setting changes of root. */
+    MESH_EVENT_ROOT_FIXED,              /**< when devices join a network, if the setting of Fixed Root for one device is different
+                                             from that of its parent, the device will update the setting the same as its parent's.
+                                             Fixed Root setting of each device is variable as that setting changes of root. */
+    MESH_EVENT_SCAN_DONE,               /**< if self-organized networking is disabled, user can call esp_wifi_scan_start() to trigger
+                                             this event, and add the corresponding scan done handler in this event. */
     MESH_EVENT_MAX,
 } mesh_event_id_t;
 
 /**
- * @brief node type
+ * @brief device type
  */
 typedef enum {
     MESH_IDLE,    /**< hasn't joined the mesh network yet */
     MESH_ROOT,    /**< the only sink of the mesh network. Has the ability to access external IP network */
-    MESH_NODE,    /**< intermediate node. Has the ability to forward packets over the mesh network */
+    MESH_NODE,    /**< intermediate device. Has the ability to forward packets over the mesh network */
     MESH_LEAF,    /**< has no forwarding ability */
 } mesh_type_t;
 
@@ -221,7 +231,7 @@ typedef enum {
 typedef enum {
     MESH_REASON_CYCLIC = 100,      /**< cyclic is detected */
     MESH_REASON_PARENT_IDLE,       /**< parent is idle */
-    MESH_REASON_LEAF,              /**< the connected node is changed to a leaf */
+    MESH_REASON_LEAF,              /**< the connected device is changed to a leaf */
     MESH_REASON_DIFF_ID,           /**< in different mesh ID */
     MESH_REASON_ROOTS,             /**< root conflict is detected */
     MESH_REASON_PARENT_STOPPED,    /**< parent has stopped the mesh */
@@ -331,7 +341,7 @@ typedef struct {
  */
 typedef struct {
     int8_t rssi;           /**< rssi with router */
-    uint16_t capacity;     /**< the number of nodes in its network */
+    uint16_t capacity;     /**< the number of devices in current network */
     uint8_t addr[6];       /**< other powerful root address */
 } mesh_event_root_conflict_t;
 
@@ -350,6 +360,13 @@ typedef struct {
     bool is_fixed;     /**< status */
 } mesh_event_root_fixed_t;
 
+/**
+ * @brief scan done event information
+ */
+typedef struct {
+    uint8_t  number;     /**< the number of scanned APs */
+} mesh_event_scan_done_t;
+
 /**
  * @brief mesh event information
  */
@@ -362,16 +379,17 @@ typedef union {
     mesh_event_disconnected_t disconnected;                /**< parent disconnected */
     mesh_event_no_parent_found_t no_parent;                /**< no parent found */
     mesh_event_layer_change_t layer_change;                /**< layer change */
-    mesh_event_toDS_state_t toDS_state;                    /**< toDS state, nodes should check this state firstly before trying to send packets to
-                                                                external IP network. This state indicates right now if root is capable
-                                                                of sending packets out. If not, nodes had better to wait until this state changes
-                                                                to be MESH_TODS_REACHABLE. */
+    mesh_event_toDS_state_t toDS_state;                    /**< toDS state, devices shall check this state firstly before trying to send packets to
+                                                                external IP network. This state indicates right now if root is capable of sending
+                                                                packets out. If not, devices had better to wait until this state changes to be
+                                                                MESH_TODS_REACHABLE. */
     mesh_event_vote_started_t vote_started;                /**< vote started */
     mesh_event_root_got_ip_t got_ip;                       /**< root obtains IP address */
     mesh_event_root_address_t root_addr;                   /**< root address */
     mesh_event_root_switch_req_t switch_req;               /**< root switch request */
     mesh_event_root_conflict_t root_conflict;              /**< other powerful root */
     mesh_event_root_fixed_t root_fixed;                    /**< root fixed */
+    mesh_event_scan_done_t scan_done;                      /**< scan done */
 } mesh_event_info_t;
 
 /**
@@ -497,7 +515,7 @@ extern mesh_event_cb_t g_mesh_event_cb;
  *            Check if WiFi is started.
  *            Initialize mesh global variables with default values.
  *
- * @attention This API should be called after WiFi is started.
+ * @attention This API shall be called after WiFi is started.
  *
  * @return
  *    - ESP_OK
@@ -522,7 +540,7 @@ esp_err_t esp_mesh_deinit(void);
  *            Create TX and RX queues according to the configuration
  *            Register mesh packets receive callback
  *
- * @attention This API should be called after esp_mesh_init() and esp_mesh_set_config().
+ * @attention This API shall be called after esp_mesh_init() and esp_mesh_set_config().
  *
  * @return
  *    - ESP_OK
@@ -552,7 +570,7 @@ esp_err_t esp_mesh_stop(void);
 
 /**
  * @brief     send a packet over the mesh network
- *            Send a packet to any node in the mesh network.
+ *            Send a packet to any device in the mesh network.
  *            Send a packet to external IP network.
  *
  * @attention This API is not reentrant.
@@ -566,9 +584,9 @@ esp_err_t esp_mesh_stop(void);
  *            Should specify the transmission tos(type of service), P2P reliable by default.
  * @param     flag
  *            (1)used to speed up the route selection
- *              if the packet is target to an internal node, MESH_DATA_P2P should be set.
+ *              if the packet is target to an internal device, MESH_DATA_P2P should be set.
  *              if the packet is outgoing to root or to external IP network, MESH_DATA_TODS should be set.
- *              if the packet is from root to an internal node, MESH_DATA_FROMDS should be set.
+ *              if the packet is from root to an internal device, MESH_DATA_FROMDS should be set.
  *            (2)specify if this API is block or non-block, block by default
  *              if needs non-block, MESH_DATA_NONBLOCK should be set.
  *            (3)in the situation of root having been changed, MESH_DATA_DROP identifies this packet can be dropped by new root
@@ -581,7 +599,7 @@ esp_err_t esp_mesh_stop(void);
  * @param     opt  options
  *            (1)in case of sending a packet to a specified group, MESH_OPT_SEND_GROUP is a good choice.
  *               In this option, the value field should specify the target receiver addresses in this group.
- *            (2)root sends a packet to an internal node, this packet is from external IP network in case the receiver node responds
+ *            (2)root sends a packet to an internal device, this packet is from external IP network in case the receiver device responds
  *            this packet, MESH_OPT_RECV_DS_ADDR is required to attach the target DS address.
  * @param     opt_count  option count
  *            Currently, this API only takes one option, so opt_count is only supported to be 1.
@@ -601,7 +619,7 @@ esp_err_t esp_mesh_stop(void);
  *    - ESP_ERR_MESH_DISCARD
  */
 esp_err_t esp_mesh_send(const mesh_addr_t *to, const mesh_data_t *data,
-                        const int flag, const mesh_opt_t opt[], const int opt_count);
+                        int flag, const mesh_opt_t opt[],  int opt_count);
 
 /**
  * @brief     receive a packet targeted to self over the mesh network
@@ -679,10 +697,10 @@ esp_err_t esp_mesh_recv_toDS(mesh_addr_t *from, mesh_addr_t *to,
  *            Root conflict function could eliminate redundant roots connected with the same BSSID, but couldn't handle roots
  *            connected with different BSSID. Because users might have such requirements of setting up routers with same SSID
  *            for the future replacement. But in that case, if the above situations happen, please make sure applications
- *            implement forward functions on root to guarantee nodes in different mesh network could communicate with each other.
+ *            implement forward functions on root to guarantee devices in different mesh network can communicate with each other.
  *            max_connection of mesh softAP is limited by the max number of WiFi softAP supported(max:10).
  *
- * @attention This API should be called between esp_mesh_init() and esp_mesh_start().
+ * @attention This API shall be called between esp_mesh_init() and esp_mesh_start().
  *
  * @param     config  pointer to mesh stack configuration
  *
@@ -707,7 +725,7 @@ esp_err_t esp_mesh_get_config(mesh_cfg_t *config);
 /**
  * @brief     set router configuration
  *
- * @attention This API should be called between esp_mesh_init() and esp_mesh_start().
+ * @attention This API shall be called between esp_mesh_init() and esp_mesh_start().
  *
  * @param     router  pointer to router configuration
  *
@@ -731,7 +749,7 @@ esp_err_t esp_mesh_get_router(mesh_router_t *router);
 /**
  * @brief     set mesh network ID
  *
- * @attention This API should be called between esp_mesh_init() and esp_mesh_start().
+ * @attention This API could be called either before esp_mesh_start() or after esp_mesh_start().
  *
  * @param     id  pointer to mesh network ID
  *
@@ -753,20 +771,20 @@ esp_err_t esp_mesh_set_id(const mesh_addr_t *id);
 esp_err_t esp_mesh_get_id(mesh_addr_t *id);
 
 /**
- * @brief     set node type over the mesh network(Unimplemented)
+ * @brief     set device type over the mesh network(Unimplemented)
  *
- * @param     type  node type
+ * @param     type  device type
  *
  * @return
  *    - ESP_OK
  *    - ESP_ERR_MESH_NOT_ALLOWED
  */
-esp_err_t esp_mesh_set_type(const mesh_type_t type);
+esp_err_t esp_mesh_set_type(mesh_type_t type);
 
 /**
- * @brief     get node type over mesh network
+ * @brief     get device type over mesh network
  *
- * @attention This API should be called after having received the event MESH_EVENT_PARENT_CONNECTED.
+ * @attention This API shall be called after having received the event MESH_EVENT_PARENT_CONNECTED.
  *
  * @return    mesh type
  *
@@ -776,7 +794,7 @@ mesh_type_t esp_mesh_get_type(void);
 /**
  * @brief     set max layer configuration(max:15, default:15)
  *
- * @attention This API should be called before esp_mesh_start().
+ * @attention This API shall be called before esp_mesh_start().
  *
  * @param     max_layer  max layer value
  *
@@ -785,7 +803,7 @@ mesh_type_t esp_mesh_get_type(void);
  *    - ESP_ERR_MESH_ARGUMENT
  *    - ESP_ERR_MESH_NOT_ALLOWED
  */
-esp_err_t esp_mesh_set_max_layer(const int max_layer);
+esp_err_t esp_mesh_set_max_layer(int max_layer);
 
 /**
  * @brief     get max layer configuration
@@ -797,7 +815,7 @@ int esp_mesh_get_max_layer(void);
 /**
  * @brief     set mesh softAP password
  *
- * @attention This API should be called before esp_mesh_start().
+ * @attention This API shall be called before esp_mesh_start().
  *
  * @param     pwd  pointer to the password
  * @param     len  password length
@@ -807,12 +825,12 @@ int esp_mesh_get_max_layer(void);
  *    - ESP_ERR_MESH_ARGUMENT
  *    - ESP_ERR_MESH_NOT_ALLOWED
  */
-esp_err_t esp_mesh_set_ap_password(const uint8_t *pwd, const int len);
+esp_err_t esp_mesh_set_ap_password(const uint8_t *pwd, int len);
 
 /**
  * @brief     set mesh softAP authentication mode value
  *
- * @attention This API should be called before esp_mesh_start().
+ * @attention This API shall be called before esp_mesh_start().
  *
  * @param     authmode  authentication mode
  *
@@ -821,7 +839,7 @@ esp_err_t esp_mesh_set_ap_password(const uint8_t *pwd, const int len);
  *    - ESP_ERR_MESH_ARGUMENT
  *    - ESP_ERR_MESH_NOT_ALLOWED
  */
-esp_err_t esp_mesh_set_ap_authmode(const wifi_auth_mode_t authmode);
+esp_err_t esp_mesh_set_ap_authmode(wifi_auth_mode_t authmode);
 
 /**
  * @brief     get mesh softAP authentication mode
@@ -834,7 +852,7 @@ wifi_auth_mode_t esp_mesh_get_ap_authmode(void);
 /**
  * @brief     set mesh softAP max connection value
  *
- * @attention This API should be called before esp_mesh_start().
+ * @attention This API shall be called before esp_mesh_start().
  *
  * @param     connections  the number of max connections
  *
@@ -842,7 +860,7 @@ wifi_auth_mode_t esp_mesh_get_ap_authmode(void);
  *    - ESP_OK
  *    - ESP_ERR_MESH_ARGUMENT
  */
-esp_err_t esp_mesh_set_ap_connections(const int connections);
+esp_err_t esp_mesh_set_ap_connections(int connections);
 
 /**
  * @brief     get mesh softAP max connection configuration
@@ -855,7 +873,7 @@ int esp_mesh_get_ap_connections(void);
 /**
  * @brief     get current layer value over the mesh network
  *
- * @attention This API should be called after having received the event MESH_EVENT_PARENT_CONNECTED.
+ * @attention This API shall be called after having received the event MESH_EVENT_PARENT_CONNECTED.
  *
  * @return    layer value
  *
@@ -865,7 +883,7 @@ int esp_mesh_get_layer(void);
 /**
  * @brief     get parent BSSID
  *
- * @attention This API should be called after having received the event MESH_EVENT_PARENT_CONNECTED.
+ * @attention This API shall be called after having received the event MESH_EVENT_PARENT_CONNECTED.
  *
  * @param     bssid  pointer to parent BSSID
  *
@@ -876,7 +894,7 @@ int esp_mesh_get_layer(void);
 esp_err_t esp_mesh_get_parent_bssid(mesh_addr_t *bssid);
 
 /**
- * @brief     return if the node is root
+ * @brief     return if the device is root
  *
  * @return    true/false
  *
@@ -885,16 +903,20 @@ bool esp_mesh_is_root(void);
 
 /**
  * @brief     enable/disable mesh networking self-organized, self-organized by default
- *            if self-organized is disabled, users should set a parent for this node via
+ *            if self-organized is disabled, users should set a parent for this device via
  *            esp_mesh_set_parent();
  *
- * @param     enable
+ * @attention This API could be called either before esp_mesh_start() or after esp_mesh_start().
+ *
+ * @param     enable  enable or disable self-organized networking
+ * @param     select_parent  if enable self-organized networking, let the device select a new parent or
+ *            keep connecting to the previous parent.
  *
  * @return
  *    - ESP_OK
  *    - ESP_FAIL
  */
-esp_err_t esp_mesh_set_self_organized(const bool enable);
+esp_err_t esp_mesh_set_self_organized(bool enable, bool select_parent);
 
 /**
  * @brief     return if mesh networking is self-organized or not
@@ -906,7 +928,7 @@ bool esp_mesh_get_self_organized(void);
 
 /**
  * @brief     root waive itself
- *            A node is elected to be a root during the networking mostly because it has a strong RSSI with router.
+ *            A device is elected to be a root during the networking mostly because it has a strong RSSI with router.
  *            If such superior conditions change, users could call this API to perform a root switch.
  *
  *            In this API, users could specify a desired root address to replace itself or specify an attempts value
@@ -931,14 +953,14 @@ bool esp_mesh_get_self_organized(void);
  *    - ESP_OK
  *    - ESP_FAIL
  */
-esp_err_t esp_mesh_waive_root(const mesh_vote_t *vote, const int reason);
+esp_err_t esp_mesh_waive_root(const mesh_vote_t *vote, int reason);
 
 /**
  * @brief     set vote percentage threshold for approval of being a root
  *            During the networking, only obtaining vote percentage reaches this threshold,
- *            the node could be a root.
+ *            the device could be a root.
  *
- * @attention This API should be called before esp_mesh_start().
+ * @attention This API shall be called before esp_mesh_start().
  *
  * @param     percentage  vote percentage threshold
  *
@@ -946,7 +968,7 @@ esp_err_t esp_mesh_waive_root(const mesh_vote_t *vote, const int reason);
  *    - ESP_OK
  *    - ESP_FAIL
  */
-esp_err_t esp_mesh_set_vote_percentage(const float percentage);
+esp_err_t esp_mesh_set_vote_percentage(float percentage);
 
 /**
  * @brief     get vote percentage threshold for approval of being a root
@@ -966,7 +988,7 @@ float esp_mesh_get_vote_percentage(void);
  *    - ESP_OK
  *    - ESP_FAIL
  */
-esp_err_t esp_mesh_set_ap_assoc_expire(const int seconds);
+esp_err_t esp_mesh_set_ap_assoc_expire(int seconds);
 
 /**
  * @brief     get mesh softAP associate expired time
@@ -976,27 +998,27 @@ esp_err_t esp_mesh_set_ap_assoc_expire(const int seconds);
 int esp_mesh_get_ap_assoc_expire(void);
 
 /**
- * @brief     get total number of nodes over the mesh network(including root)
+ * @brief     get total number of devices in current network(including root)
  *
  * @attention The returned value might be incorrect when the network is changing.
  **
- * @return    total number of nodes(including root)
+ * @return    total number of devices(including root)
  */
 int esp_mesh_get_total_node_num(void);
 
 /**
- * @brief     get the number of nodes in routing table(including self)
+ * @brief     get the number of devices in this device's sub-network(including self)
  *
- * @return    the number of nodes in routing table(including self)
+ * @return    the number of devices over this device's sub-network(including self)
  */
 int esp_mesh_get_routing_table_size(void);
 
 /**
- * @brief     get routing table(including itself)
+ * @brief     get routing table of this device's sub-network(including itself)
  *
  * @param     mac  pointer to routing table
  * @param     len  routing table size(in bytes)
- * @param     size  pointer to the number of nodes in routing table(including itself)
+ * @param     size  pointer to the number of devices in routing table(including itself)
  *
  * @return
  *    - ESP_OK
@@ -1015,7 +1037,7 @@ esp_err_t esp_mesh_get_routing_table(mesh_addr_t *mac, int len, int *size);
  *    - ESP_OK
  *    - ESP_FAIL
  */
-esp_err_t esp_mesh_post_toDS_state(const bool reachable);
+esp_err_t esp_mesh_post_toDS_state(bool reachable);
 
 /**
  * @brief     return the number of packets pending in the queue waiting to be sent by the mesh stack
@@ -1052,9 +1074,9 @@ int esp_mesh_available_txupQ_num(const mesh_addr_t *addr, uint32_t *xseqno_in);
 /**
  * @brief     set queue size
  *
- * @attention This API should be called before esp_mesh_start().
+ * @attention This API shall be called before esp_mesh_start().
  *
- * @param     qsize  default:72(min:36, max:105)
+ * @param     qsize  default:32(min:16)
  *
  * @return
  *    - ESP_OK
@@ -1079,7 +1101,7 @@ int esp_mesh_get_xon_qsize(void);
  *    - ESP_WIFI_ERR_NOT_INIT
  *    - ESP_WIFI_ERR_NOT_START
  */
-esp_err_t esp_mesh_allow_root_conflicts(const bool allowed);
+esp_err_t esp_mesh_allow_root_conflicts(bool allowed);
 
 /**
  * @brief     check if allow more than one root to exist in one network
@@ -1098,7 +1120,7 @@ bool esp_mesh_is_root_conflicts_allowed(void);
  *    - ESP_OK
  *    - ESP_MESH_ERR_ARGUMENT
  */
-esp_err_t esp_mesh_set_group_id(const mesh_addr_t *addr, const int num);
+esp_err_t esp_mesh_set_group_id(const mesh_addr_t *addr, int num);
 
 /**
  * @brief     delete group ID addresses
@@ -1110,7 +1132,7 @@ esp_err_t esp_mesh_set_group_id(const mesh_addr_t *addr, const int num);
  *    - ESP_OK
  *    - ESP_MESH_ERR_ARGUMENT
  */
-esp_err_t esp_mesh_delete_group_id(const mesh_addr_t *addr, const int num);
+esp_err_t esp_mesh_delete_group_id(const mesh_addr_t *addr, int num);
 
 /**
  * @brief     get the number of group ID addresses
@@ -1129,7 +1151,7 @@ int esp_mesh_get_group_num(void);
  *    - ESP_OK
  *    - ESP_MESH_ERR_ARGUMENT
  */
-esp_err_t esp_mesh_get_group_list(mesh_addr_t *addr, const int num);
+esp_err_t esp_mesh_get_group_list(mesh_addr_t *addr, int num);
 
 /**
  * @brief     check if the specified group address is my group
@@ -1141,7 +1163,7 @@ bool esp_mesh_is_my_group(const mesh_addr_t *addr);
 /**
  * @brief     set mesh network capacity
  *
- * @attention This API should be called before esp_mesh_start().
+ * @attention This API shall be called before esp_mesh_start().
  *
  * @param     num  mesh network capacity
  *
@@ -1172,7 +1194,7 @@ esp_err_t esp_mesh_set_ie_crypto_funcs(const mesh_crypto_funcs_t *crypto_funcs);
 /**
  * @brief    set mesh ie crypto key
  *
- * @attention This API should be called after esp_mesh_set_config() and before esp_mesh_start().
+ * @attention This API shall be called after esp_mesh_set_config() and before esp_mesh_start().
  *
  * @param     key  ASCII crypto key
  * @param     len  length in bytes, range:8~64
@@ -1225,21 +1247,21 @@ int esp_mesh_get_root_healing_delay(void);
 esp_err_t esp_mesh_set_event_cb(const mesh_event_cb_t event_cb);
 
 /**
- * @brief     set Root Fixed setting for nodes
- *            If Root Fixed setting of nodes is enabled, they won't compete to be a root.
- *            If a scenario needs a fixed root, all nodes in this network shall enable this setting.
+ * @brief     set Fixed Root setting for the device
+ *            If Fixed Root setting of the device is enabled, it won't compete to be a root.
+ *            If a scenario needs a fixed root, all devices in this network shall enable this setting.
  *
  * @param     enable  enable or not
  *
  * @return
  *    - ESP_OK
  */
-esp_err_t esp_mesh_fix_root(const bool enable);
+esp_err_t esp_mesh_fix_root(bool enable);
 
 /**
- * @brief     check if Root Fixed setting is enabled
- *            Root Fixed setting can be changed by API esp_mesh_fix_root().
- *            Root Fixed setting can also be changed by event MESH_EVENT_ROOT_FIXED.
+ * @brief     check if Fixed Root setting is enabled
+ *            Fixed Root setting can be changed by API esp_mesh_fix_root().
+ *            Fixed Root setting can also be changed by event MESH_EVENT_ROOT_FIXED.
  *
  * @return    true/false
  */
@@ -1247,9 +1269,9 @@ bool esp_mesh_is_root_fixed(void);
 
 /**
  * @brief     set a specified parent
- *            self-organized networking will be disabled.
  *
- * @param     parent  parent configuration
+ * @param     parent  parent configuration, the ssid and the channel of the parent are mandatory.
+ * @param     parent_mesh_id  parent mesh ID, if not set, use the device default one.
  * @param     my_type  my mesh type
  * @param     my_layer  my mesh layer
  *
@@ -1258,8 +1280,35 @@ bool esp_mesh_is_root_fixed(void);
  *    - ESP_ERR_ARGUMENT
  *    - ESP_ERR_MESH_NOT_CONFIG
  */
-esp_err_t esp_mesh_set_parent(wifi_config_t *parent, mesh_type_t my_type, int my_layer);
+esp_err_t esp_mesh_set_parent(const wifi_config_t *parent, const mesh_addr_t *parent_mesh_id, mesh_type_t my_type, int my_layer);
 
+/**
+ * @brief     get mesh networking IE length of one AP
+ *
+ * @param     len  mesh networking IE length
+ *
+ * @return
+ *    - ESP_OK
+ *    - ESP_ERR_WIFI_NOT_INIT
+ *    - ESP_ERR_WIFI_ARG
+ *    - ESP_ERR_WIFI_FAIL
+ */
+esp_err_t esp_mesh_scan_get_ap_ie_len(int *len);
+
+/**
+ * @brief     get AP record
+ *            Different from esp_wifi_scan_get_ap_records(), this API only gets one of scanned APs each time.
+ *
+ * @param     ap_record  pointer to the AP record
+ * @param     buffer  pointer to the mesh networking IE of this AP
+ *
+ * @return
+ *    - ESP_OK
+ *    - ESP_ERR_WIFI_NOT_INIT
+ *    - ESP_ERR_WIFI_ARG
+ *    - ESP_ERR_WIFI_FAIL
+ */
+esp_err_t esp_mesh_scan_get_ap_record(wifi_ap_record_t *ap_record, void *buffer);
 
 #ifdef __cplusplus
 }
index 19273ba06da7d0c09f2b157559d3ddd4d067a457..da349297ebb75ad73c07d526cb827b3b22eb58ec 100644 (file)
@@ -49,6 +49,46 @@ typedef struct {
     int backoff_rssi;  /* RSSI threshold for connecting to the root */
 } mesh_switch_parent_t;
 
+/**
+ * @brief mesh networking IE
+ */
+typedef struct {
+    /**< mesh networking IE head */
+    uint8_t eid;             /**< element ID */
+    uint8_t len;             /**< element length */
+    uint8_t oui[3];          /**< organization identifier */
+    /**< mesh networking IE content */
+    uint8_t type;            /** mesh networking IE type */
+    uint8_t encryped : 1;    /**< if mesh networking IE is encrypted */
+    uint8_t version : 7;     /**< mesh networking IE version */
+    /**< content */
+    uint8_t mesh_type;       /**< mesh device type */
+    uint8_t mesh_id[6];      /**< mesh ID */
+    uint8_t layer_cap;       /**< max layer */
+    uint8_t layer;           /**< current layer */
+    uint8_t assoc_cap;       /**< max connections of mesh AP */
+    uint8_t assoc;           /**< current connections */
+    uint8_t leaf_cap;        /**< leaf capacity */
+    uint8_t leaf_assoc;      /**< the number of current connected leaf */
+    uint16_t root_cap;       /**< root capacity */
+    uint16_t self_cap;       /**< self capacity */
+    uint16_t layer2_cap;     /**< layer2 capacity */
+    uint16_t scan_ap_num;    /**< the number of scanned APs */
+    int8_t rssi;             /**< rssi of the parent */
+    int8_t router_rssi;      /**< rssi of the router */
+    uint8_t flag;            /**< flag of networking */
+    uint8_t rc_addr[6];      /**< root address */
+    int8_t rc_rssi;          /**< root rssi */
+    uint8_t vote_addr[6];    /**< voter address */
+    int8_t vote_rssi;        /**< vote rssi of the router */
+    uint8_t vote_ttl;        /**< vote ttl */
+    uint16_t votes;          /**< votes */
+    uint16_t my_votes;       /**< my votes */
+    uint8_t reason;          /**< reason */
+    uint8_t child[6];        /**< child address */
+    uint8_t toDS;            /**< toDS state */
+} __attribute__((packed)) mesh_assoc_t;
+
 /*******************************************************
  *                Function Definitions
  *******************************************************/
index 963fb2baa4bf6320a89674ef1ba1de6f15ddd06d..8b6d5837a4215b83ff8a3ff088ccbb716adf05fb 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 963fb2baa4bf6320a89674ef1ba1de6f15ddd06d
+Subproject commit 8b6d5837a4215b83ff8a3ff088ccbb716adf05fb
diff --git a/examples/mesh/manual_networking/Makefile b/examples/mesh/manual_networking/Makefile
new file mode 100644 (file)
index 0000000..6a51b33
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := manual_networking
+
+include $(IDF_PATH)/make/project.mk
+
diff --git a/examples/mesh/manual_networking/main/Kconfig.projbuild b/examples/mesh/manual_networking/main/Kconfig.projbuild
new file mode 100644 (file)
index 0000000..a3bad4b
--- /dev/null
@@ -0,0 +1,80 @@
+menu "Example Configuration"
+
+config MESH_CHANNEL
+    int "channel"
+    range 1 14
+    default 1
+    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 MAP_AUTH_MODE_OPEN
+        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 stations allowed to connect in.
+
+config MESH_MAX_LAYER
+    int "Mesh Max Layer"
+        range 1 15
+        default 6
+        help
+            Max layer allowed in mesh network.
+
+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).
+
+config MESH_PARENT_SSID
+    string "Parent SSID"
+        default "PARENT_SSID"
+        help
+            Parent SSID.
+endmenu
+
diff --git a/examples/mesh/manual_networking/main/component.mk b/examples/mesh/manual_networking/main/component.mk
new file mode 100644 (file)
index 0000000..a98f634
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
diff --git a/examples/mesh/manual_networking/main/include/mesh_light.h b/examples/mesh/manual_networking/main/include/mesh_light.h
new file mode 100644 (file)
index 0000000..ecf4e06
--- /dev/null
@@ -0,0 +1,57 @@
+/* Mesh Manual Networking 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/examples/mesh/manual_networking/main/mesh_light.c b/examples/mesh/manual_networking/main/mesh_light.c
new file mode 100644 (file)
index 0000000..4780503
--- /dev/null
@@ -0,0 +1,180 @@
+/* Mesh Manual Networking 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 <string.h>
+#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 = {
+        .bit_num = LEDC_TIMER_13_BIT,
+        .freq_hz = 5000,
+        .speed_mode = LEDC_HIGH_SPEED_MODE,
+        .timer_num = LEDC_TIMER_0
+    };
+    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_HIGH_SPEED_MODE,
+        .timer_sel = LEDC_TIMER_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_HIGH_SPEED_MODE, LEDC_CHANNEL_0, 3000);
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, 0);
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_2, 0);
+        break;
+    case MESH_LIGHT_GREEN:
+        /* Green */
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, 0);
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, 3000);
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_2, 0);
+        break;
+    case MESH_LIGHT_BLUE:
+        /* Blue */
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, 0);
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, 0);
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_2, 3000);
+        break;
+    case MESH_LIGHT_YELLOW:
+        /* Yellow */
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, 3000);
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, 3000);
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_2, 0);
+        break;
+    case MESH_LIGHT_PINK:
+        /* Pink */
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, 3000);
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, 0);
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_2, 3000);
+        break;
+    case MESH_LIGHT_INIT:
+        /* can't say */
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, 0);
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, 3000);
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_2, 3000);
+        break;
+    case MESH_LIGHT_WARNING:
+        /* warning */
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, 3000);
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, 3000);
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_2, 3000);
+        break;
+    default:
+        /* off */
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, 0);
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, 0);
+        ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_2, 0);
+    }
+
+    ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0);
+    ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1);
+    ledc_update_duty(LEDC_HIGH_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/examples/mesh/manual_networking/main/mesh_main.c b/examples/mesh/manual_networking/main/mesh_main.c
new file mode 100644 (file)
index 0000000..2703dd5
--- /dev/null
@@ -0,0 +1,327 @@
+/* Mesh Manual Networking 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 <string.h>
+#include "esp_wifi.h"
+#include "esp_system.h"
+#include "esp_event_loop.h"
+#include "esp_log.h"
+#include "esp_mesh.h"
+#include "esp_mesh_internal.h"
+#include "mesh_light.h"
+#include "nvs_flash.h"
+
+/*******************************************************
+ *                Macros
+ *******************************************************/
+//#define MESH_SET_ROOT
+
+#ifndef MESH_SET_ROOT
+#define MESH_SET_NODE
+#endif
+
+/*******************************************************
+ *                Constants
+ *******************************************************/
+
+/*******************************************************
+ *                Variable Definitions
+ *******************************************************/
+static const char *MESH_TAG = "mesh_main";
+static const uint8_t MESH_ID[6] = { 0x77, 0x77, 0x77, 0x77, 0x77, 0x77};
+static mesh_addr_t mesh_parent_addr;
+static int mesh_layer = -1;
+
+/*******************************************************
+ *                Function Declarations
+ *******************************************************/
+void mesh_event_handler(mesh_event_t event);
+void mesh_scan_done_handler(int num);
+
+/*******************************************************
+ *                Function Definitions
+ *******************************************************/
+void mesh_scan_done_handler(int num)
+{
+    int i;
+    int ie_len = 0;
+    mesh_assoc_t assoc;
+    mesh_assoc_t parent_assoc = { .layer = CONFIG_MESH_MAX_LAYER, .rssi = -120 };
+    wifi_ap_record_t record;
+    wifi_ap_record_t parent_record = { 0, };
+    bool parent_found = false;
+    mesh_type_t my_type = MESH_IDLE;
+    int my_layer = -1;
+
+    for (i = 0; i < num; i++) {
+        esp_mesh_scan_get_ap_ie_len(&ie_len);
+        esp_mesh_scan_get_ap_record(&record, &assoc);
+        if (ie_len == sizeof(assoc)) {
+            ESP_LOGW(MESH_TAG,
+                     "<MESH>[%d]%s, layer:%d/%d, assoc:%d/%d, %d, "MACSTR", channel:%u, rssi:%d, ID<"MACSTR">",
+                     i, record.ssid, assoc.layer, assoc.layer_cap, assoc.assoc,
+                     assoc.assoc_cap, assoc.layer2_cap, MAC2STR(record.bssid),
+                     record.primary, record.rssi, MAC2STR(assoc.mesh_id));
+#ifdef MESH_SET_NODE
+            if (assoc.mesh_type != MESH_IDLE && assoc.layer_cap
+                    && assoc.assoc < assoc.assoc_cap && record.rssi > -70) {
+                if (assoc.layer < parent_assoc.layer || assoc.layer2_cap < parent_assoc.layer2_cap) {
+                    parent_found = true;
+                    memcpy(&parent_record, &record, sizeof(record));
+                    memcpy(&parent_assoc, &assoc, sizeof(assoc));
+                    if (parent_assoc.layer_cap != 1) {
+                        my_type = MESH_NODE;
+                    } else {
+                        my_type = MESH_LEAF;
+                    }
+                    my_layer = parent_assoc.layer + 1;
+                }
+            }
+#endif
+        } else {
+            ESP_LOGI(MESH_TAG, "[%d]%s, "MACSTR", channel:%u, rssi:%d", i,
+                     record.ssid, MAC2STR(record.bssid), record.primary,
+                     record.rssi);
+#ifdef MESH_SET_ROOT
+            if (!strcmp(CONFIG_MESH_ROUTER_SSID, (char *) record.ssid)) {
+                parent_found = true;
+                memcpy(&parent_record, &record, sizeof(record));
+                my_type = MESH_ROOT;
+                my_layer = MESH_ROOT_LAYER;
+            }
+#endif
+        }
+    }
+
+    if (parent_found) {
+        /*
+         * parent
+         * Both channel and ssid of the parent are mandatory.
+         */
+        wifi_config_t parent = { 0, };
+        parent.sta.channel = parent_record.primary;
+        memcpy(&parent.sta.ssid, &parent_record.ssid,
+               sizeof(parent_record.ssid));
+        parent.sta.bssid_set = 1;
+        memcpy(&parent.sta.bssid, parent_record.bssid, 6);
+        if (my_type == MESH_ROOT) {
+            ESP_LOGW(MESH_TAG, "<PARENT>%s, "MACSTR", channel:%u, rssi:%d",
+                     parent_record.ssid, MAC2STR(parent_record.bssid),
+                     parent_record.primary, parent_record.rssi);
+        } else {
+            ESP_LOGW(MESH_TAG,
+                     "<PARENT>%s, layer:%d/%d, assoc:%d/%d, %d, "MACSTR", channel:%u, rssi:%d",
+                     parent_record.ssid, parent_assoc.layer,
+                     parent_assoc.layer_cap, parent_assoc.assoc,
+                     parent_assoc.assoc_cap, parent_assoc.layer2_cap,
+                     MAC2STR(parent_record.bssid), parent_record.primary,
+                     parent_record.rssi);
+        }
+        ESP_ERROR_CHECK(esp_mesh_set_parent(&parent, (mesh_addr_t*)&parent_assoc.mesh_id, my_type, my_layer));
+
+    } else {
+        ESP_LOGW(MESH_TAG,
+                 "no parent found, enable self-organized networking.");
+        ESP_ERROR_CHECK(esp_mesh_set_self_organized(1, 1));
+    }
+}
+
+void mesh_event_handler(mesh_event_t event)
+{
+       mesh_addr_t id = {0,};
+    static uint8_t last_layer = 0;
+    ESP_LOGD(MESH_TAG, "esp_event_handler:%d", event.id);
+
+    switch (event.id) {
+    case MESH_EVENT_STARTED:
+       esp_mesh_get_id(&id);
+        ESP_LOGI(MESH_TAG, "<MESH_EVENT_STARTED>ID:"MACSTR"", MAC2STR(id.addr));
+        mesh_layer = esp_mesh_get_layer();
+        ESP_ERROR_CHECK(esp_mesh_set_self_organized(0, 0));
+        ESP_ERROR_CHECK(esp_wifi_scan_stop());
+        wifi_scan_config_t scan_config = { 0 };
+        /* mesh softAP is hidden */
+        scan_config.show_hidden = 1;
+        ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, 0));
+        break;
+    case MESH_EVENT_STOPPED:
+        ESP_LOGI(MESH_TAG, "<MESH_EVENT_STOPPED>");
+        mesh_layer = esp_mesh_get_layer();
+        break;
+    case MESH_EVENT_CHILD_CONNECTED:
+        ESP_LOGI(MESH_TAG, "<MESH_EVENT_CHILD_CONNECTED>aid:%d, "MACSTR"",
+                 event.info.child_connected.aid,
+                 MAC2STR(event.info.child_connected.mac));
+        break;
+    case MESH_EVENT_CHILD_DISCONNECTED:
+        ESP_LOGI(MESH_TAG, "<MESH_EVENT_CHILD_DISCONNECTED>aid:%d, "MACSTR"",
+                 event.info.child_disconnected.aid,
+                 MAC2STR(event.info.child_disconnected.mac));
+        break;
+    case MESH_EVENT_ROUTING_TABLE_ADD:
+        ESP_LOGW(MESH_TAG, "<MESH_EVENT_ROUTING_TABLE_ADD>add %d, new:%d",
+                 event.info.routing_table.rt_size_change,
+                 event.info.routing_table.rt_size_new);
+        break;
+    case MESH_EVENT_ROUTING_TABLE_REMOVE:
+        ESP_LOGW(MESH_TAG, "<MESH_EVENT_ROUTING_TABLE_REMOVE>remove %d, new:%d",
+                 event.info.routing_table.rt_size_change,
+                 event.info.routing_table.rt_size_new);
+        break;
+    case MESH_EVENT_NO_PARNET_FOUND:
+        ESP_LOGI(MESH_TAG, "<MESH_EVENT_NO_PARNET_FOUND>scan times:%d",
+                 event.info.no_parent.scan_times);
+        /* TODO handler for the failure */
+        break;
+    case MESH_EVENT_PARENT_CONNECTED:
+       esp_mesh_get_id(&id);
+        mesh_layer = event.info.connected.self_layer;
+        memcpy(&mesh_parent_addr.addr, event.info.connected.connected.bssid, 6);
+        ESP_LOGI(MESH_TAG,
+                 "<MESH_EVENT_PARENT_CONNECTED>layer:%d-->%d, parent:"MACSTR"%s, ID:"MACSTR"",
+                 last_layer, mesh_layer, MAC2STR(mesh_parent_addr.addr),
+                 esp_mesh_is_root() ? "<ROOT>" :
+                 (mesh_layer == 2) ? "<layer2>" : "", MAC2STR(id.addr));
+        last_layer = mesh_layer;
+        mesh_connected_indicator(mesh_layer);
+        if (esp_mesh_is_root()) {
+            tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA);
+        }
+        break;
+    case MESH_EVENT_PARENT_DISCONNECTED:
+        ESP_LOGI(MESH_TAG,
+                 "<MESH_EVENT_PARENT_DISCONNECTED>reason:%d",
+                 event.info.disconnected.reason);
+        mesh_disconnected_indicator();
+        mesh_layer = esp_mesh_get_layer();
+        break;
+    case MESH_EVENT_LAYER_CHANGE:
+        mesh_layer = event.info.layer_change.new_layer;
+        ESP_LOGI(MESH_TAG, "<MESH_EVENT_LAYER_CHANGE>layer:%d-->%d%s",
+                 last_layer, mesh_layer,
+                 esp_mesh_is_root() ? "<ROOT>" :
+                 (mesh_layer == 2) ? "<layer2>" : "");
+        last_layer = mesh_layer;
+        mesh_connected_indicator(mesh_layer);
+        break;
+    case MESH_EVENT_ROOT_ADDRESS:
+        ESP_LOGI(MESH_TAG, "<MESH_EVENT_ROOT_ADDRESS>root address:"MACSTR"",
+                 MAC2STR(event.info.root_addr.addr));
+        break;
+    case MESH_EVENT_ROOT_GOT_IP:
+        /* root starts to connect to server */
+        ESP_LOGI(MESH_TAG,
+                 "<MESH_EVENT_ROOT_GOT_IP>sta ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR,
+                 IP2STR(&event.info.got_ip.ip_info.ip),
+                 IP2STR(&event.info.got_ip.ip_info.netmask),
+                 IP2STR(&event.info.got_ip.ip_info.gw));
+        break;
+    case MESH_EVENT_ROOT_LOST_IP:
+        ESP_LOGI(MESH_TAG, "<MESH_EVENT_ROOT_LOST_IP>");
+        break;
+    case MESH_EVENT_VOTE_STARTED:
+        ESP_LOGI(MESH_TAG,
+                 "<MESH_EVENT_VOTE_STARTED>attempts:%d, reason:%d, rc_addr:"MACSTR"",
+                 event.info.vote_started.attempts,
+                 event.info.vote_started.reason,
+                 MAC2STR(event.info.vote_started.rc_addr.addr));
+        break;
+    case MESH_EVENT_VOTE_STOPPED:
+        ESP_LOGI(MESH_TAG, "<MESH_EVENT_VOTE_STOPPED>");
+        break;
+    case MESH_EVENT_ROOT_SWITCH_REQ:
+        ESP_LOGI(MESH_TAG,
+                 "<MESH_EVENT_ROOT_SWITCH_REQ>reason:%d, rc_addr:"MACSTR"",
+                 event.info.switch_req.reason,
+                 MAC2STR( event.info.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, "<MESH_EVENT_ROOT_SWITCH_ACK>layer:%d, parent:"MACSTR"", mesh_layer, MAC2STR(mesh_parent_addr.addr));
+        break;
+    case MESH_EVENT_TODS_STATE:
+        ESP_LOGI(MESH_TAG, "<MESH_EVENT_TODS_REACHABLE>state:%d",
+                 event.info.toDS_state);
+        break;
+    case MESH_EVENT_ROOT_FIXED:
+        ESP_LOGI(MESH_TAG, "<MESH_EVENT_ROOT_FIXED>%s",
+                 event.info.root_fixed.is_fixed ? "fixed" : "not fixed");
+        break;
+    case MESH_EVENT_ROOT_ASKED_YIELD:
+        ESP_LOGI(MESH_TAG,
+                 "<MESH_EVENT_ROOT_ASKED_YIELD>"MACSTR", rssi:%d, capacity:%d",
+                 MAC2STR(event.info.root_conflict.addr),
+                 event.info.root_conflict.rssi,
+                 event.info.root_conflict.capacity);
+        break;
+    case MESH_EVENT_CHANNEL_SWITCH:
+        ESP_LOGI(MESH_TAG, "<MESH_EVENT_CHANNEL_SWITCH>");
+        break;
+    case MESH_EVENT_SCAN_DONE:
+        ESP_LOGI(MESH_TAG, "<MESH_EVENT_SCAN_DONE>number:%d",
+                 event.info.scan_done.number);
+        mesh_scan_done_handler(event.info.scan_done.number);
+        break;
+    default:
+        ESP_LOGI(MESH_TAG, "unknown id:%d", event.id);
+        break;
+    }
+}
+
+void app_main(void)
+{
+    ESP_ERROR_CHECK(mesh_light_init());
+    ESP_ERROR_CHECK(nvs_flash_init());
+    /*  tcpip initialization */
+    tcpip_adapter_init();
+    /* for mesh
+     * stop DHCP server on softAP interface by default
+     * stop DHCP client on station interface by default
+     * */
+    ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP));
+    ESP_ERROR_CHECK(tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA));
+#if 0
+    /* static ip settings */
+    tcpip_adapter_ip_info_t sta_ip;
+    sta_ip.ip.addr = ipaddr_addr("192.168.1.102");
+    sta_ip.gw.addr = ipaddr_addr("192.168.1.1");
+    sta_ip.netmask.addr = ipaddr_addr("255.255.255.0");
+    tcpip_adapter_set_ip_info(WIFI_IF_STA, &sta_ip);
+#endif
+    /*  wifi initialization */
+    ESP_ERROR_CHECK(esp_event_loop_init(NULL, NULL));
+    wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();
+    ESP_ERROR_CHECK(esp_wifi_init(&config));
+    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_mesh_set_ap_authmode(WIFI_AUTH_OPEN));
+    mesh_cfg_t cfg = MESH_INIT_CONFIG_DEFAULT();
+    /* mesh ID */
+    memcpy((uint8_t *) &cfg.mesh_id, MESH_ID, 6);
+    /* mesh event callback */
+    cfg.event_cb = &mesh_event_handler;
+    /* 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 */
+    cfg.mesh_ap.max_connection = CONFIG_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());
+    ESP_LOGI(MESH_TAG, "mesh starts successfully, heap:%d, %s\n",  esp_get_free_heap_size(),
+             esp_mesh_is_root_fixed() ? "root fixed" : "root not fixed");
+}