]> git.meshlink.io Git - meshlink-tiny/blob - src/mlt_main.c
977b9c3f0fc457f167db5935ebfd5028a76c413e
[meshlink-tiny] / src / mlt_main.c
1 /* MeshLink-tiny Example */
2
3 #include <string.h>
4 #include "freertos/FreeRTOS.h"
5 #include "freertos/task.h"
6 #include "freertos/event_groups.h"
7 #include "esp_system.h"
8 #include "esp_wifi.h"
9 #include "esp_event.h"
10 #include "esp_log.h"
11 #include "esp_console.h"
12 #include "esp_vfs_dev.h"
13 #include "driver/uart.h"
14 #include "linenoise/linenoise.h"
15 #include "argtable3/argtable3.h"
16 #include "nvs_flash.h"
17
18 #include "lwip/err.h"
19 #include "lwip/sys.h"
20
21 #include "meshlink-tiny.h"
22
23 /* The examples use WiFi configuration that you can set via project configuration menu
24
25    If you'd rather not, just change the below entries to strings with
26    the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
27 */
28 #define EXAMPLE_ESP_WIFI_SSID      CONFIG_ESP_WIFI_SSID
29 #define EXAMPLE_ESP_WIFI_PASS      CONFIG_ESP_WIFI_PASSWORD
30 #define EXAMPLE_ESP_MAXIMUM_RETRY  CONFIG_ESP_MAXIMUM_RETRY
31
32 /* FreeRTOS event group to signal when we are connected*/
33 static EventGroupHandle_t s_wifi_event_group;
34
35 /* The event group allows multiple bits for each event, but we only care about two events:
36  * - we are connected to the AP with an IP
37  * - we failed to connect after the maximum amount of retries */
38 #define WIFI_CONNECTED_BIT BIT0
39 #define WIFI_FAIL_BIT      BIT1
40
41 static const char *TAG = "wifi station";
42
43 static int s_retry_num = 0;
44
45 static void event_handler(void *arg, esp_event_base_t event_base,
46                           int32_t event_id, void *event_data) {
47         if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
48                 esp_wifi_connect();
49         } else if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
50                 if(s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
51                         esp_wifi_connect();
52                         s_retry_num++;
53                         ESP_LOGI(TAG, "retry to connect to the AP");
54                 } else {
55                         xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
56                 }
57
58                 ESP_LOGI(TAG, "connect to the AP fail");
59         } else if(event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
60                 ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
61                 ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
62                 s_retry_num = 0;
63                 xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
64         }
65 }
66
67 void wifi_init_sta(void) {
68         s_wifi_event_group = xEventGroupCreate();
69
70         ESP_ERROR_CHECK(esp_netif_init());
71
72         ESP_ERROR_CHECK(esp_event_loop_create_default());
73         esp_netif_create_default_wifi_sta();
74
75         wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
76         ESP_ERROR_CHECK(esp_wifi_init(&cfg));
77
78         esp_event_handler_instance_t instance_any_id;
79         esp_event_handler_instance_t instance_got_ip;
80         ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
81                         ESP_EVENT_ANY_ID,
82                         &event_handler,
83                         NULL,
84                         &instance_any_id));
85         ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
86                         IP_EVENT_STA_GOT_IP,
87                         &event_handler,
88                         NULL,
89                         &instance_got_ip));
90
91         wifi_config_t wifi_config = {
92                 .sta = {
93                         .ssid = EXAMPLE_ESP_WIFI_SSID,
94                         .password = EXAMPLE_ESP_WIFI_PASS,
95                         /* Setting a password implies station will connect to all security modes including WEP/WPA.
96                          * However these modes are deprecated and not advisable to be used. Incase your Access point
97                          * doesn't support WPA2, these mode can be enabled by commenting below line */
98                         .threshold.authmode = WIFI_AUTH_WPA2_PSK,
99
100                         .pmf_cfg = {
101                                 .capable = true,
102                                 .required = false
103                         },
104                 },
105         };
106         ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
107         ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
108         ESP_ERROR_CHECK(esp_wifi_start());
109
110         ESP_LOGI(TAG, "wifi_init_sta finished.");
111
112         /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
113          * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
114         EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
115                                                WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
116                                                pdFALSE,
117                                                pdFALSE,
118                                                portMAX_DELAY);
119
120         /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
121          * happened. */
122         if(bits & WIFI_CONNECTED_BIT) {
123                 ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
124                          EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
125         } else if(bits & WIFI_FAIL_BIT) {
126                 ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
127                          EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
128         } else {
129                 ESP_LOGE(TAG, "UNEXPECTED EVENT");
130         }
131
132         /* The event will not be processed after unregister */
133         ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
134         ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
135         vEventGroupDelete(s_wifi_event_group);
136 }
137
138 static void mlt_log(meshlink_handle_t *mesh, meshlink_log_level_t leve, const char *text) {
139         ESP_LOGI(TAG, "Log: %s", text);
140 }
141
142 meshlink_handle_t *mesh = NULL;
143
144 static void receive(meshlink_handle_t *mesh, meshlink_node_t *from, const void *data, size_t len) {
145         char *str = (char *)data;
146         str[len] = 0;
147         ESP_LOGI(TAG, "%s says: %s", from->name, str);
148 }
149
150 static int join_func(int argc, char **argv) {
151         if(argc < 2) {
152                 return 1;
153         }
154
155         if(!meshlink_join(mesh, argv[1])) {
156                 ESP_LOGE(TAG, "Join failed");
157                 return 1;
158         }
159
160         ESP_LOGI(TAG, "Join completed");
161
162         meshlink_set_receive_cb(mesh, receive);
163
164         if(!meshlink_start(mesh)) {
165                 ESP_LOGE(TAG, "Could not start mesh!");
166                 return 1;
167         }
168
169         return 0;
170 }
171
172 static int say_func(int argc, char **argv) {
173         if(argc < 3) {
174                 return 1;
175         }
176
177         meshlink_node_t *peer = meshlink_get_node(mesh, argv[1]);
178
179         if(!peer) {
180                 ESP_LOGE(TAG, "Peer not found");
181                 return 1;
182         }
183
184         if(!meshlink_send(mesh, peer, argv[2], strlen(argv[2]))) {
185                 ESP_LOGE(TAG, "Send failed");
186                 return 1;
187         }
188
189         return 0;
190 }
191
192 static int quit_func(int argc, char **argv) {
193         meshlink_close(mesh);
194         mesh = NULL;
195         ESP_LOGI(TAG, "Closed mesh");
196         return 0;
197 }
198
199 static void mlt_main(void) {
200         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, mlt_log);
201
202         ESP_LOGI(TAG, "Starting MeshLink-tiny instance...");
203         mesh = meshlink_open_ephemeral("esp32", "chat", DEV_CLASS_PORTABLE);
204
205         if(!mesh) {
206                 ESP_LOGE(TAG, "Open failed!");
207                 return;
208         }
209
210         fflush(stdout);
211         fsync(fileno(stdout));
212         setvbuf(stdin, NULL, _IONBF, 0);
213
214         esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR);
215         esp_vfs_dev_uart_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF);
216
217         const uart_config_t uart_config = {
218                 .baud_rate = CONFIG_ESP_CONSOLE_UART_BAUDRATE,
219                 .data_bits = UART_DATA_8_BITS,
220                 .parity = UART_PARITY_DISABLE,
221                 .stop_bits = UART_STOP_BITS_1,
222 #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
223                 .source_clk = UART_SCLK_REF_TICK,
224 #else
225                 .source_clk = UART_SCLK_XTAL,
226 #endif
227         };
228         /* Install UART driver for interrupt-driven reads and writes */
229         ESP_ERROR_CHECK(uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM,
230                                             256, 0, 0, NULL, 0));
231         ESP_ERROR_CHECK(uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config));
232
233         /* Tell VFS to use UART driver */
234         esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
235
236         esp_console_config_t console_config = {
237                 .max_cmdline_args = 8,
238                 .max_cmdline_length = 256,
239         };
240
241         ESP_ERROR_CHECK(esp_console_init(&console_config));
242
243         linenoiseSetMultiLine(1);
244         linenoiseHistorySetMaxLen(1);
245         linenoiseAllowEmpty(false);
246
247         esp_console_cmd_t join_cmd = {
248                 .command = "join",
249                 .help = "Join a mesh",
250                 .func = join_func,
251         };
252
253         esp_console_cmd_t say_cmd = {
254                 .command = "say",
255                 .help = "Say something",
256                 .func = say_func,
257         };
258
259         esp_console_cmd_t quit_cmd = {
260                 .command = "quit",
261                 .help = "Quit",
262                 .func = quit_func,
263         };
264
265         esp_console_cmd_register(&join_cmd);
266         esp_console_cmd_register(&say_cmd);
267         esp_console_cmd_register(&quit_cmd);
268         esp_console_register_help_command();
269
270         while(mesh) {
271                 char *line = linenoise("> ");
272
273                 if(!line) {
274                         continue;
275                 }
276
277                 linenoiseHistoryAdd(line);
278                 int ret;
279                 esp_console_run(line, &ret);
280                 linenoiseFree(line);
281         }
282
283         ESP_LOGI(TAG, "App quit");
284         esp_console_deinit();
285 }
286
287 void app_main(void) {
288         //Initialize NVS
289         esp_err_t ret = nvs_flash_init();
290
291         if(ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
292                 ESP_ERROR_CHECK(nvs_flash_erase());
293                 ret = nvs_flash_init();
294         }
295
296         ESP_ERROR_CHECK(ret);
297
298         ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
299         wifi_init_sta();
300         mlt_main();
301 }