瀏覽代碼

openthread: add a manual mode in Thread border router example

zhangwenxu 4 年之前
父節點
當前提交
91f54c673d

+ 9 - 2
components/openthread/CMakeLists.txt

@@ -135,7 +135,7 @@ idf_component_register(SRC_DIRS "${src_dirs}"
                        EXCLUDE_SRCS "${exclude_srcs}"
                        INCLUDE_DIRS "${public_include_dirs}"
                        PRIV_INCLUDE_DIRS "${private_include_dirs}"
-                       REQUIRES mbedtls ieee802154 console)
+                       REQUIRES mbedtls ieee802154 console lwip)
 
 if(CONFIG_OPENTHREAD_ENABLED)
     if(CONFIG_OPENTHREAD_RADIO)
@@ -156,11 +156,18 @@ if(CONFIG_OPENTHREAD_ENABLED)
 
     if(CONFIG_OPENTHREAD_ESP_LIB_FROM_INTERNAL_SRC)
         idf_component_get_property(openthread_port_lib openthread_port COMPONENT_LIB)
+        idf_component_get_property(lwip_lib lwip COMPONENT_LIB)
+        idf_component_get_property(esp_netif_lib esp_netif COMPONENT_LIB)
         idf_component_get_property(esp_system_lib esp_system COMPONENT_LIB)
         target_link_libraries(${COMPONENT_LIB} PUBLIC
                               $<TARGET_FILE:${openthread_port_lib}>
                               $<TARGET_FILE:${esp_system_lib}>)
-
+        target_link_libraries(${COMPONENT_LIB} PUBLIC
+                              $<TARGET_FILE:${lwip_lib}>
+                              $<TARGET_FILE:${esp_netif_lib}>
+                              $<TARGET_FILE:${openthread_port_lib}>
+                              $<TARGET_FILE:${esp_netif_lib}>
+                              $<TARGET_FILE:${lwip_lib}>)
         if(CONFIG_OPENTHREAD_BORDER_ROUTER)
             idf_component_get_property(openthread_br_lib openthread_br COMPONENT_LIB)
             target_link_libraries(${COMPONENT_LIB} PUBLIC $<TARGET_FILE:${openthread_br_lib}>)

+ 58 - 4
examples/openthread/ot_br/README.md

@@ -27,8 +27,14 @@ ESP32 pin | ESP32-H2 pin
 ```
 idf.py menuconfig
 ```
+Two ways are provided to setup the Thread Border Router in this example:
 
-You need to configure the `CONFIG_EXAMPLE_WIFI_SSID` and `CONFIG_EXAMPLE_WIFI_PASSWORD` with your access point's ssid and psk.
+- Auto Start
+Enable `OPENTHREAD_BR_AUTO_START`, configure the `CONFIG_EXAMPLE_WIFI_SSID` and `CONFIG_EXAMPLE_WIFI_PASSWORD` with your access point's ssid and psk.
+The device will connect to Wi-Fi and form a Thread network automatically after bootup.
+
+- Manual mode
+Disable `OPENTHREAD_BR_AUTO_START`, and use the CLI command to configure the Wi-Fi and form Thread network manually.
 
 ### Build, Flash, and Run
 
@@ -37,6 +43,57 @@ Build the project and flash it to the board, then run monitor tool to view seria
 ```
 idf.py -p PORT build flash monitor
 ```
+If the OPENTHREAD_BR_AUTO_START option is enabled, The device will be connected to the configured Wi-Fi and Thread network automatically then act as the border router.
+
+Otherwise, you need to manually configure the Wi-Fi and Thread network with CLI command.
+
+Command `sta` is used for connecting WiFi.
+
+```bash
+> sta
+---wifi sta parameter---
+-s                   :     wifi ssid
+-p                   :     wifi psk
+---example---
+join a wifi, 
+ssid: threadcertAP 
+psk: threadcertAP    :     sta -s threadcertAP -p threadcertAP
+Done 
+> sta -s threadcertAP -p threadcertAP
+ssid: threadcertAP
+psk: threadcertAP
+I (47043) wifi:wifi driver task: 3ffd05ac, prio:23, stack:6656, core=0
+
+
+......
+
+
+I (49263) wifi:AP's beacon interval = 102400 us, DTIM period = 1
+I (50233) esp_netif_handlers: sta ip: 192.168.3.10, mask: 255.255.255.0, gw: 192.168.3.1
+wifi sta is connected successfully
+Done
+>
+```
+
+Command `wifiinfo` is used for checking the state of Wi-Fi connection and printing IP addresses.
+
+```bash
+> wifiinfo
+---get WiFi informations---
+-i                   :     get sta addr
+-s                   :     get wifi state, disconnect or connect
+Done
+> wifiinfo -s
+connected
+Done
+> wifiinfo -i
+inet 192.168.3.10
+inet6 FE80::7AE3:6DFF:FECD:125C 
+Done
+> 
+```
+
+For forming Thread network, you can refer to [ot_cli_README](../ot_cli/README.md)
 
 ## Example Output
 
@@ -56,9 +113,6 @@ I(8139) OPENTHREAD:[NOTE]-MLE-----: Allocate router id 50
 I(8139) OPENTHREAD:[NOTE]-MLE-----: RLOC16 fffe -> c800
 I(8159) OPENTHREAD:[NOTE]-MLE-----: Role Detached -> Leader
 ```
-
-The device will automatically connect to the configured Wi-Fi and Thread network and act as the border router.
-
 ## Using the border agent feature
 
 You need to ot-commissioner on the host machine and another Thread end device running OpenThread cli.

+ 9 - 2
examples/openthread/ot_br/main/CMakeLists.txt

@@ -1,2 +1,9 @@
-idf_component_register(SRCS "esp_ot_br.c"
-                       INCLUDE_DIRS ".")
+if(CONFIG_OPENTHREAD_BR_AUTO_START)
+    set(srcs    "esp_ot_br.c")
+else()
+    set(srcs    "esp_ot_br.c"
+                "esp_ot_cli_extension.c"
+                "esp_br_wifi_cmd.c")
+endif()
+    idf_component_register(SRCS "${srcs}"
+                           INCLUDE_DIRS ".")

+ 8 - 0
examples/openthread/ot_br/main/Kconfig.projbuild

@@ -38,4 +38,12 @@ menu "OpenThread Border Router Example"
         help
             The OpenThread pre-shared commissioner key in hex string format
 
+    config OPENTHREAD_BR_AUTO_START
+        bool 'Enable the automatic start mode in Thread Border Router.'
+        default False
+        help
+            If enabled, The Thread Border Router will connect to Wi-Fi with pre-configured
+            SSID and PSK, and then form a Thread network automatically. Otherwise, user need
+            to configure Wi-Fi and Thread manually.
+
 endmenu

+ 173 - 0
examples/openthread/ot_br/main/esp_br_wifi_cmd.c

@@ -0,0 +1,173 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * OpenThread Border Router 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "esp_netif_types.h"
+#include "esp_openthread_border_router.h"
+#include "esp_check.h"
+#include "esp_event.h"
+#include "esp_openthread_lock.h"
+#include "esp_netif.h"
+#include "esp_netif_ip_addr.h"
+#include "esp_netif_net_stack.h"
+#include "esp_wifi.h"
+#include "freertos/event_groups.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/portmacro.h"
+#include "freertos/task.h"
+#include "openthread/cli.h"
+
+static EventGroupHandle_t wifi_event_group;
+const int CONNECTED_IP4_BIT = BIT0;
+const int CONNECTED_IP6_BIT = BIT1;
+static bool s_wifi_connected = false;
+
+void esp_ot_wifi_netif_init(void)
+{
+    esp_netif_t *esp_netif = esp_netif_create_default_wifi_sta();
+    assert(esp_netif);
+}
+
+static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
+{
+    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
+        xEventGroupClearBits(wifi_event_group, CONNECTED_IP4_BIT);
+        xEventGroupClearBits(wifi_event_group, CONNECTED_IP6_BIT);
+        esp_wifi_connect();
+    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
+        xEventGroupSetBits(wifi_event_group, CONNECTED_IP4_BIT);
+    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED) {
+        esp_netif_create_ip6_linklocal(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"));
+    } else if (event_base == IP_EVENT && event_id == IP_EVENT_GOT_IP6) {
+        xEventGroupSetBits(wifi_event_group, CONNECTED_IP6_BIT);
+    }
+}
+
+static void wifi_join(const char *ssid, const char *psk)
+{
+    static bool s_initialized = false;
+    if (!s_initialized) {
+        wifi_event_group = xEventGroupCreate();
+        wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+        esp_wifi_init(&cfg);
+        ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &event_handler, NULL) );
+        ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );
+        ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, &event_handler, NULL) );
+        ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_GOT_IP6, &event_handler, NULL) );
+        esp_wifi_set_storage(WIFI_STORAGE_RAM);
+        esp_wifi_set_mode(WIFI_MODE_NULL);
+        s_initialized = true;
+    }
+    esp_wifi_start();
+    wifi_config_t wifi_config = { 0 };
+    strncpy((char *) wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid));
+    if (psk) {
+        strncpy((char *) wifi_config.sta.password, psk, sizeof(wifi_config.sta.password));
+    }
+
+    ESP_ERROR_CHECK( esp_wifi_set_ps(WIFI_PS_NONE) );
+    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
+    ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
+    esp_wifi_connect();
+
+    int bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_IP4_BIT | CONNECTED_IP6_BIT, pdFALSE, pdTRUE, 10000 / portTICK_PERIOD_MS);
+
+    if (((bits & CONNECTED_IP4_BIT) != 0) && ((bits & CONNECTED_IP6_BIT) != 0)) {
+        s_wifi_connected = true;
+        xEventGroupClearBits(wifi_event_group, CONNECTED_IP4_BIT);
+        xEventGroupClearBits(wifi_event_group, CONNECTED_IP6_BIT);
+        esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &event_handler);
+        esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, &event_handler);
+        esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler);
+        esp_event_handler_unregister(IP_EVENT, IP_EVENT_GOT_IP6, &event_handler);
+        vEventGroupDelete(wifi_event_group);
+        s_initialized = false;
+        esp_openthread_lock_acquire(portMAX_DELAY);
+        esp_openthread_border_router_init();
+        esp_openthread_lock_release();
+        otCliOutputFormat("wifi sta is connected successfully\n");
+    } else {
+        esp_wifi_disconnect();
+        esp_wifi_stop();
+        ESP_LOGW("","Connection time out, please check your ssid & password, then retry.");
+        otCliOutputFormat("wifi sta connection is failed\n");
+    }
+}
+
+void esp_ot_process_wifi_sta(void *aContext, uint8_t aArgsLength, char *aArgs[])
+{
+    char ssid[100] = "";
+    char psk[100] = "";
+    (void)(aContext);
+    if (aArgsLength == 0) {
+        otCliOutputFormat("---wifi sta parameter---\n");
+        otCliOutputFormat("-s                   :     wifi ssid\n");
+        otCliOutputFormat("-p                   :     wifi psk\n");
+        otCliOutputFormat("---example---\n");
+        otCliOutputFormat("join a wifi:\nssid: threadcertAP \npsk: threadcertAP    :     sta -s threadcertAP -p threadcertAP\n");
+    } else {
+        for (int i = 0; i < aArgsLength; i++) {
+            if (strcmp(aArgs[i], "-s") == 0) {
+                i++;
+                strcpy(ssid, aArgs[i]);
+                otCliOutputFormat("ssid: %s\n", ssid);
+            } else if (strcmp(aArgs[i], "-p") == 0) {
+                i++;
+                strcpy(psk, aArgs[i]);
+                otCliOutputFormat("psk: %s\n", psk);
+            }
+        }
+        if (!s_wifi_connected) {
+            wifi_join(ssid, psk);
+        } else {
+            otCliOutputFormat("wifi has already connected\n");
+        }
+    }
+}
+
+void esp_ot_process_get_wifi_info(void *aContext, uint8_t aArgsLength, char *aArgs[])
+{
+    (void)(aContext);
+    if (aArgsLength == 0) {
+        otCliOutputFormat("---get wifi informations---\n");
+        otCliOutputFormat("-i                   :     get sta addr\n");
+        otCliOutputFormat("-s                   :     get wifi state, disconnect or connect\n");
+    } else {
+        for (int i = 0; i < aArgsLength; i++) {
+            if (strcmp(aArgs[i], "-i") == 0) {
+                if (s_wifi_connected) {
+                    esp_netif_ip_info_t local_ip;
+                    char addr_str[128];
+                    esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &local_ip);
+                    ip4addr_ntoa_r((ip4_addr_t *)(&local_ip.ip), addr_str, sizeof(addr_str) - 1);
+                    otCliOutputFormat("inet %s\n");
+                    esp_ip6_addr_t if_ip6;
+                    esp_netif_get_ip6_linklocal(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &if_ip6);
+                    ip6addr_ntoa_r((ip6_addr_t *)(&if_ip6), addr_str, sizeof(addr_str) - 1);
+                    otCliOutputFormat("inet6 %s\n", addr_str);
+                } else {
+                    otCliOutputFormat("wifi is disconnected\n");
+                }
+            } else if (strcmp(aArgs[i], "-s") == 0) {
+                if (s_wifi_connected) {
+                    otCliOutputFormat("connected\n");
+                } else {
+                    otCliOutputFormat("disconnected\n");
+                }
+            }
+        }
+    }
+}

+ 42 - 0
examples/openthread/ot_br/main/esp_br_wifi_cmd.h

@@ -0,0 +1,42 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * OpenThread Border Router 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.
+*/
+
+#pragma once
+
+#include "esp_netif.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief User command "sta" process.
+ *
+ */
+void esp_ot_process_wifi_sta(void *aContext, uint8_t aArgsLength, char *aArgs[]);
+
+/**
+ * @brief User command "wifiinfo" process.
+ *
+ */
+void esp_ot_process_get_wifi_info(void *aContext, uint8_t aArgsLength, char *aArgs[]);
+
+/**
+ * @brief Wifi netif init.
+ *
+ */
+void esp_ot_wifi_netif_init(void);
+
+#ifdef __cplusplus
+}
+#endif

+ 17 - 4
examples/openthread/ot_br/main/esp_ot_br.c

@@ -1,7 +1,7 @@
 /*
  * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
  *
- * SPDX-License-Identifier: CC0
+ * SPDX-License-Identifier: CC0-1.0
  *
  * OpenThread Border Router Example
  *
@@ -52,9 +52,12 @@
 #include "openthread/tasklet.h"
 #include "openthread/thread.h"
 #include "openthread/thread_ftd.h"
+#include "esp_br_wifi_cmd.h"
+#include "esp_ot_cli_extension.h"
 
 #define TAG "esp_ot_br"
 
+#if CONFIG_OPENTHREAD_BR_AUTO_START
 static int hex_digit_to_int(char hex)
 {
     if ('A' <= hex && hex <= 'F') {
@@ -152,6 +155,7 @@ static void launch_openthread_network(otInstance *instance)
         abort();
     }
 }
+#endif // CONFIG_OPENTHREAD_BR_AUTO_START
 
 static void ot_task_worker(void *aContext)
 {
@@ -164,20 +168,23 @@ static void ot_task_worker(void *aContext)
     esp_netif_config_t cfg = ESP_NETIF_DEFAULT_OPENTHREAD();
     esp_netif_t *openthread_netif = esp_netif_new(&cfg);
     assert(openthread_netif != NULL);
-
     // Initialize the OpenThread stack
-    esp_openthread_set_backbone_netif(get_example_netif());
+
     ESP_ERROR_CHECK(esp_openthread_init(&config));
 
     // Initialize border routing features
     esp_openthread_lock_acquire(portMAX_DELAY);
     ESP_ERROR_CHECK(esp_netif_attach(openthread_netif, esp_openthread_netif_glue_init(&config)));
-    ESP_ERROR_CHECK(esp_openthread_border_router_init());
 
     (void)otLoggingSetLevel(CONFIG_LOG_DEFAULT_LEVEL);
     esp_openthread_cli_init();
+#if CONFIG_OPENTHREAD_BR_AUTO_START
+    ESP_ERROR_CHECK(esp_openthread_border_router_init());
     create_config_network(esp_openthread_get_instance());
     launch_openthread_network(esp_openthread_get_instance());
+#else
+    esp_cli_custom_command_init();
+#endif // CONFIG_OPENTHREAD_BR_AUTO_START
     esp_openthread_lock_release();
 
     // Run the main loop
@@ -205,8 +212,14 @@ void app_main(void)
     ESP_ERROR_CHECK(nvs_flash_init());
     ESP_ERROR_CHECK(esp_netif_init());
     ESP_ERROR_CHECK(esp_event_loop_create_default());
+#if CONFIG_OPENTHREAD_BR_AUTO_START
     ESP_ERROR_CHECK(example_connect());
     ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
+    esp_openthread_set_backbone_netif(get_example_netif());
+#else
+    esp_ot_wifi_netif_init();
+    esp_openthread_set_backbone_netif(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"));
+#endif // CONFIG_OPENTHREAD_BR_AUTO_START
     ESP_ERROR_CHECK(mdns_init());
     ESP_ERROR_CHECK(mdns_hostname_set("esp-ot-br"));
     xTaskCreate(ot_task_worker, "ot_br_main", 20480, xTaskGetCurrentTaskHandle(), 5, NULL);

+ 29 - 0
examples/openthread/ot_br/main/esp_ot_cli_extension.c

@@ -0,0 +1,29 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * OpenThread Command Line 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 "esp_openthread.h"
+#include "openthread/cli.h"
+#include "esp_ot_cli_extension.h"
+#include "esp_br_wifi_cmd.h"
+
+static const otCliCommand kCommands[] = {
+    {"sta", esp_ot_process_wifi_sta},
+    {"wifiinfo", esp_ot_process_get_wifi_info}
+};
+
+void esp_cli_custom_command_init()
+{
+    otInstance *instance = esp_openthread_get_instance();
+    otCliSetUserCommands(kCommands, (sizeof(kCommands) / sizeof(kCommands[0])), instance);
+}

+ 28 - 0
examples/openthread/ot_br/main/esp_ot_cli_extension.h

@@ -0,0 +1,28 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: CC0-1.0
+ *
+ * OpenThread Command Line 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.
+*/
+
+#pragma once
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+* @brief Init the custom command.
+*
+*/
+void esp_cli_custom_command_init(void);
+
+#ifdef __cplusplus
+}
+#endif

+ 1 - 1
examples/openthread/ot_br/main/esp_ot_config.h

@@ -1,7 +1,7 @@
 /*
  * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
  *
- * SPDX-License-Identifier: CC0
+ * SPDX-License-Identifier: CC0-1.0
  *
  * OpenThread Border Router Example
  *