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