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