1 /* OpenThread Border Router Example
2
3 This example code is in the Public Domain (or CC0 licensed, at your option.)
4
5 Unless required by applicable law or agreed to in writing, this
6 software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
7 CONDITIONS OF ANY KIND, either express or implied.
8 */
9
10 #include <stdio.h>
11 #include <string.h>
12
13 #include "esp_check.h"
14 #include "esp_err.h"
15 #include "esp_event.h"
16 #include "esp_log.h"
17 #include "esp_netif.h"
18 #include "esp_netif_ip_addr.h"
19 #include "esp_netif_net_stack.h"
20 #include "esp_openthread.h"
21 #include "esp_openthread_border_router.h"
22 #include "esp_openthread_cli.h"
23 #include "esp_openthread_lock.h"
24 #include "esp_openthread_netif_glue.h"
25 #include "esp_openthread_types.h"
26 #include "esp_ot_config.h"
27 #include "esp_vfs_eventfd.h"
28 #include "esp_wifi.h"
29 #include "mdns.h"
30 #include "nvs_flash.h"
31 #include "protocol_examples_common.h"
32 #include "sdkconfig.h"
33 #include "driver/uart.h"
34 #include "freertos/FreeRTOS.h"
35 #include "freertos/portmacro.h"
36 #include "freertos/task.h"
37 #include "hal/uart_types.h"
38 #include "openthread/border_router.h"
39 #include "openthread/cli.h"
40 #include "openthread/dataset.h"
41 #include "openthread/dataset_ftd.h"
42 #include "openthread/dataset_updater.h"
43 #include "openthread/error.h"
44 #include "openthread/instance.h"
45 #include "openthread/ip6.h"
46 #include "openthread/logging.h"
47 #include "openthread/tasklet.h"
48 #include "openthread/thread.h"
49 #include "openthread/thread_ftd.h"
50
51 #define TAG "esp_ot_br"
52
hex_digit_to_int(char hex)53 static int hex_digit_to_int(char hex)
54 {
55 if ('A' <= hex && hex <= 'F') {
56 return 10 + hex - 'A';
57 }
58 if ('a' <= hex && hex <= 'f') {
59 return 10 + hex - 'a';
60 }
61 if ('0' <= hex && hex <= '9') {
62 return hex - '0';
63 }
64 return -1;
65 }
66
hex_string_to_binary(const char * hex_string,uint8_t * buf,size_t buf_size)67 static size_t hex_string_to_binary(const char *hex_string, uint8_t *buf, size_t buf_size)
68 {
69 int num_char = strlen(hex_string);
70
71 if (num_char != buf_size * 2) {
72 return 0;
73 }
74 for (size_t i = 0; i < num_char; i += 2) {
75 int digit0 = hex_digit_to_int(hex_string[i]);
76 int digit1 = hex_digit_to_int(hex_string[i + 1]);
77
78 if (digit0 < 0 || digit1 < 0) {
79 return 0;
80 }
81 buf[i / 2] = (digit0 << 4) + digit1;
82 }
83
84 return buf_size;
85 }
86
create_config_network(otInstance * instance)87 static void create_config_network(otInstance *instance)
88 {
89 otOperationalDataset dataset;
90
91 if (otDatasetGetActive(instance, &dataset) == OT_ERROR_NONE) {
92 ESP_LOGI(TAG, "Already has network, skip configuring OpenThread network.");
93 return;
94 }
95
96 uint16_t network_name_len = strnlen(CONFIG_OPENTHREAD_NETWORK_NAME, OT_NETWORK_NAME_MAX_SIZE + 1);
97
98 assert(network_name_len <= OT_NETWORK_NAME_MAX_SIZE);
99
100 if (otDatasetCreateNewNetwork(instance, &dataset) != OT_ERROR_NONE) {
101 ESP_LOGE(TAG, "Failed to create OpenThread network dataset.");
102 abort();
103 }
104 dataset.mChannel = CONFIG_OPENTHREAD_NETWORK_CHANNEL;
105 dataset.mComponents.mIsChannelPresent = true;
106 dataset.mPanId = CONFIG_OPENTHREAD_NETWORK_PANID;
107 dataset.mComponents.mIsPanIdPresent = true;
108 memcpy(dataset.mNetworkName.m8, CONFIG_OPENTHREAD_NETWORK_NAME, network_name_len);
109 dataset.mComponents.mIsNetworkNamePresent = true;
110 if (hex_string_to_binary(CONFIG_OPENTHREAD_NETWORK_EXTPANID, dataset.mExtendedPanId.m8,
111 sizeof(dataset.mExtendedPanId.m8)) != sizeof(dataset.mExtendedPanId.m8)) {
112 ESP_LOGE(TAG, "Cannot convert OpenThread extended pan id. Please double-check your config.");
113 abort();
114 }
115 dataset.mComponents.mIsExtendedPanIdPresent = true;
116 if (hex_string_to_binary(CONFIG_OPENTHREAD_NETWORK_MASTERKEY, dataset.mNetworkKey.m8,
117 sizeof(dataset.mNetworkKey.m8)) != sizeof(dataset.mNetworkKey.m8)) {
118 ESP_LOGE(TAG, "Cannot convert OpenThread master key. Please double-check your config.");
119 abort();
120 }
121 dataset.mComponents.mIsNetworkKeyPresent = true;
122 if (hex_string_to_binary(CONFIG_OPENTHREAD_NETWORK_PSKC, dataset.mPskc.m8, sizeof(dataset.mPskc.m8)) !=
123 sizeof(dataset.mPskc.m8)) {
124 ESP_LOGE(TAG, "Cannot convert OpenThread pre-shared commissioner key. Please double-check your config.");
125 abort();
126 }
127 dataset.mComponents.mIsPskcPresent = true;
128 if (otDatasetSetActive(instance, &dataset) != OT_ERROR_NONE) {
129 ESP_LOGE(TAG, "Failed to set OpenThread active dataset.");
130 abort();
131 }
132 if (otBorderRouterRegister(instance) != OT_ERROR_NONE) {
133 ESP_LOGE(TAG, "Failed to register border router.");
134 abort();
135 }
136 return;
137 }
138
launch_openthread_network(otInstance * instance)139 static void launch_openthread_network(otInstance *instance)
140 {
141 if (otIp6SetEnabled(instance, true) != OT_ERROR_NONE) {
142 ESP_LOGE(TAG, "Failed to enable OpenThread IP6 link");
143 abort();
144 }
145 if (otThreadSetEnabled(instance, true) != OT_ERROR_NONE) {
146 ESP_LOGE(TAG, "Failed to enable OpenThread");
147 abort();
148 }
149 }
150
ot_task_worker(void * aContext)151 static void ot_task_worker(void *aContext)
152 {
153 esp_openthread_platform_config_t config = {
154 .radio_config = ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG(),
155 .host_config = ESP_OPENTHREAD_DEFAULT_HOST_CONFIG(),
156 .port_config = ESP_OPENTHREAD_DEFAULT_PORT_CONFIG(),
157 };
158
159 esp_netif_config_t cfg = ESP_NETIF_DEFAULT_OPENTHREAD();
160 esp_netif_t *openthread_netif = esp_netif_new(&cfg);
161 assert(openthread_netif != NULL);
162
163 // Initialize the OpenThread stack
164 ESP_ERROR_CHECK(esp_openthread_init(&config));
165
166 // Initialize border routing features
167 ESP_ERROR_CHECK(esp_netif_attach(openthread_netif, esp_openthread_netif_glue_init(&config)));
168 ESP_ERROR_CHECK(esp_openthread_border_router_init(get_example_netif()));
169
170 esp_openthread_lock_acquire(portMAX_DELAY);
171 (void)otLoggingSetLevel(CONFIG_LOG_DEFAULT_LEVEL);
172 esp_openthread_cli_init();
173 create_config_network(esp_openthread_get_instance());
174 launch_openthread_network(esp_openthread_get_instance());
175 esp_openthread_lock_release();
176
177 // Run the main loop
178 esp_openthread_cli_create_task();
179 esp_openthread_launch_mainloop();
180
181 // Clean up
182 esp_netif_destroy(openthread_netif);
183 esp_openthread_netif_glue_deinit();
184 esp_vfs_eventfd_unregister();
185 vTaskDelete(NULL);
186 }
187
app_main(void)188 void app_main(void)
189 {
190 // Used eventfds:
191 // * netif
192 // * task queue
193 // * border router
194 esp_vfs_eventfd_config_t eventfd_config = {
195 .max_fds = 3,
196 };
197 ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config));
198
199 ESP_ERROR_CHECK(nvs_flash_init());
200 ESP_ERROR_CHECK(esp_netif_init());
201 ESP_ERROR_CHECK(esp_event_loop_create_default());
202 ESP_ERROR_CHECK(example_connect());
203 ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
204 ESP_ERROR_CHECK(mdns_init());
205 ESP_ERROR_CHECK(mdns_hostname_set("esp-ot-br"));
206 xTaskCreate(ot_task_worker, "ot_br_main", 20480, xTaskGetCurrentTaskHandle(), 5, NULL);
207 }
208