]> git.meshlink.io Git - meshlink-tiny/commitdiff
Add an example chat application.
authorGuus Sliepen <guus@meshlink.io>
Mon, 12 Jul 2021 19:57:36 +0000 (21:57 +0200)
committerGuus Sliepen <guus@meshlink.io>
Thu, 2 Sep 2021 21:50:51 +0000 (23:50 +0200)
CMakeLists.txt [new file with mode: 0644]
README.ESP32 [new file with mode: 0644]
config-esp32.h [new file with mode: 0644]
main [new symlink]
src/CMakeLists.txt [new file with mode: 0644]
src/Kconfig.projbuild [new file with mode: 0644]
src/mlt_main.c [new file with mode: 0644]
src/system.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..28af8d7
--- /dev/null
@@ -0,0 +1,7 @@
+# The following five lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/components)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(meshlink_tiny)
diff --git a/README.ESP32 b/README.ESP32
new file mode 100644 (file)
index 0000000..2387441
--- /dev/null
@@ -0,0 +1,16 @@
+To build, you must have the Espressif IoT Development Framework (ESP-IDF)
+installed. You can find it here:
+
+https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/
+
+Make sure you have sourced export.sh so the idf.py command runs correctly. Then
+run these commands:
+
+    idf.py set-target esp32
+    idf.py menuconfig
+
+Go to the "WiFi Configuration" menu and fill in the details matching your WiFi
+network. Then build and flash with:
+
+    idf.py build
+    idf.py -p <serial port device> flash
diff --git a/config-esp32.h b/config-esp32.h
new file mode 100644 (file)
index 0000000..aabb266
--- /dev/null
@@ -0,0 +1,188 @@
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the `asprintf' function. */
+#define HAVE_ASPRINTF 1
+
+/* Define to 1 if you have the <curses.h> header file. */
+#define HAVE_CURSES_H 1
+
+/* Define to 1 if you have the <dirent.h> header file. */
+#define HAVE_DIRENT_H 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `fchmod' function. */
+#define HAVE_FCHMOD 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Linux */
+#define HAVE_LINUX 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* MinGW */
+/* #undef HAVE_MINGW */
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define if you have POSIX threads libraries and header files. */
+#define HAVE_PTHREAD 1
+
+/* Have PTHREAD_PRIO_INHERIT. */
+#define HAVE_PTHREAD_PRIO_INHERIT 1
+
+/* Define to 1 if you have the `random' function. */
+#define HAVE_RANDOM 1
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the <stdatomic.h> header file. */
+#define HAVE_STDATOMIC_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#define HAVE_SYS_FILE_H 0
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 0
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 0
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 0
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 0
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 0
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 0
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 0
+
+/* Define to 1 if you have the <sys/wait.h> header file. */
+#define HAVE_SYS_WAIT_H 0
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `usleep' function. */
+#define HAVE_USLEEP 1
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#define LT_OBJDIR ".libs/"
+
+/* Name of package */
+#define PACKAGE "meshlink"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "MeshLink"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "MeshLink 0.1"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "meshlink"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.1"
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+   your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+
+/* Version number of package */
+#define VERSION "0.1"
+
+/* Enable Darwin features */
+#define _DARWIN_C_SOURCE 1
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Enable POSIX features */
+#define _POSIX_C_SOURCE 200809L
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Enable BSD extensions */
+#define __USE_BSD 1
+
+/* Defined if the __malloc__ attribute is not supported. */
+/* #undef __malloc__ */
+
+/* Defined if the __warn_unused_result__ attribute is not supported. */
+/* #undef __warn_unused_result__ */
diff --git a/main b/main
new file mode 120000 (symlink)
index 0000000..e831038
--- /dev/null
+++ b/main
@@ -0,0 +1 @@
+src
\ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3346908
--- /dev/null
@@ -0,0 +1,46 @@
+idf_component_register(SRCS 
+               "buffer.c"
+               "conf.c"
+               "connection.c"
+               "crypto.c"
+               "devtools.c"
+               "dropin.c"
+               "event.c"
+               "hash.c"
+               "list.c"
+               "logger.c"
+               "meshlink.c"
+               "meta.c"
+               "net.c"
+               "net_setup.c"
+               "net_socket.c"
+               "netutl.c"
+               "node.c"
+               "prf.c"
+               "protocol.c"
+               "protocol_auth.c"
+               "protocol_edge.c"
+               "protocol_key.c"
+               "protocol_misc.c"
+               "splay_tree.c"
+               "sptps.c"
+               "utils.c"
+               "xoshiro.c"
+               "ed25519/add_scalar.c"
+               "ed25519/ecdh.c"
+               "ed25519/ecdsa.c"
+               "ed25519/ecdsagen.c"
+               "ed25519/fe.c"
+               "ed25519/ge.c"
+               "ed25519/key_exchange.c"
+               "ed25519/keypair.c"
+               "ed25519/sc.c"
+               "ed25519/seed.c"
+               "ed25519/sha512.c"
+               "ed25519/sign.c"
+               "ed25519/verify.c"
+               "chacha-poly1305/chacha-poly1305.c"
+               "chacha-poly1305/chacha.c"
+               "chacha-poly1305/poly1305.c"
+               "mlt_main.c"
+                INCLUDE_DIRS ".")
diff --git a/src/Kconfig.projbuild b/src/Kconfig.projbuild
new file mode 100644 (file)
index 0000000..e4fd563
--- /dev/null
@@ -0,0 +1,20 @@
+menu "WiFi Configuration"
+
+    config ESP_WIFI_SSID
+        string "WiFi SSID"
+        default "myssid"
+        help
+            SSID (network name) for the example to connect to.
+
+    config ESP_WIFI_PASSWORD
+        string "WiFi Password"
+        default "mypassword"
+        help
+            WiFi password (WPA or WPA2) for the example to use.
+
+    config ESP_MAXIMUM_RETRY
+        int "Maximum retry"
+        default 5
+        help
+            Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
+endmenu
diff --git a/src/mlt_main.c b/src/mlt_main.c
new file mode 100644 (file)
index 0000000..977b9c3
--- /dev/null
@@ -0,0 +1,301 @@
+/* MeshLink-tiny Example */
+
+#include <string.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/event_groups.h"
+#include "esp_system.h"
+#include "esp_wifi.h"
+#include "esp_event.h"
+#include "esp_log.h"
+#include "esp_console.h"
+#include "esp_vfs_dev.h"
+#include "driver/uart.h"
+#include "linenoise/linenoise.h"
+#include "argtable3/argtable3.h"
+#include "nvs_flash.h"
+
+#include "lwip/err.h"
+#include "lwip/sys.h"
+
+#include "meshlink-tiny.h"
+
+/* The examples use WiFi configuration that you can set via project configuration menu
+
+   If you'd rather not, just change the below entries to strings with
+   the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
+*/
+#define EXAMPLE_ESP_WIFI_SSID      CONFIG_ESP_WIFI_SSID
+#define EXAMPLE_ESP_WIFI_PASS      CONFIG_ESP_WIFI_PASSWORD
+#define EXAMPLE_ESP_MAXIMUM_RETRY  CONFIG_ESP_MAXIMUM_RETRY
+
+/* FreeRTOS event group to signal when we are connected*/
+static EventGroupHandle_t s_wifi_event_group;
+
+/* The event group allows multiple bits for each event, but we only care about two events:
+ * - we are connected to the AP with an IP
+ * - we failed to connect after the maximum amount of retries */
+#define WIFI_CONNECTED_BIT BIT0
+#define WIFI_FAIL_BIT      BIT1
+
+static const char *TAG = "wifi station";
+
+static int s_retry_num = 0;
+
+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_START) {
+               esp_wifi_connect();
+       } else if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
+               if(s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
+                       esp_wifi_connect();
+                       s_retry_num++;
+                       ESP_LOGI(TAG, "retry to connect to the AP");
+               } else {
+                       xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
+               }
+
+               ESP_LOGI(TAG, "connect to the AP fail");
+       } else if(event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
+               ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
+               ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
+               s_retry_num = 0;
+               xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
+       }
+}
+
+void wifi_init_sta(void) {
+       s_wifi_event_group = xEventGroupCreate();
+
+       ESP_ERROR_CHECK(esp_netif_init());
+
+       ESP_ERROR_CHECK(esp_event_loop_create_default());
+       esp_netif_create_default_wifi_sta();
+
+       wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+       ESP_ERROR_CHECK(esp_wifi_init(&cfg));
+
+       esp_event_handler_instance_t instance_any_id;
+       esp_event_handler_instance_t instance_got_ip;
+       ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
+                       ESP_EVENT_ANY_ID,
+                       &event_handler,
+                       NULL,
+                       &instance_any_id));
+       ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
+                       IP_EVENT_STA_GOT_IP,
+                       &event_handler,
+                       NULL,
+                       &instance_got_ip));
+
+       wifi_config_t wifi_config = {
+               .sta = {
+                       .ssid = EXAMPLE_ESP_WIFI_SSID,
+                       .password = EXAMPLE_ESP_WIFI_PASS,
+                       /* Setting a password implies station will connect to all security modes including WEP/WPA.
+                        * However these modes are deprecated and not advisable to be used. Incase your Access point
+                        * doesn't support WPA2, these mode can be enabled by commenting below line */
+                       .threshold.authmode = WIFI_AUTH_WPA2_PSK,
+
+                       .pmf_cfg = {
+                               .capable = true,
+                               .required = false
+                       },
+               },
+       };
+       ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
+       ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
+       ESP_ERROR_CHECK(esp_wifi_start());
+
+       ESP_LOGI(TAG, "wifi_init_sta finished.");
+
+       /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
+        * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
+       EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
+                                              WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
+                                              pdFALSE,
+                                              pdFALSE,
+                                              portMAX_DELAY);
+
+       /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
+        * happened. */
+       if(bits & WIFI_CONNECTED_BIT) {
+               ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
+                        EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
+       } else if(bits & WIFI_FAIL_BIT) {
+               ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
+                        EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
+       } else {
+               ESP_LOGE(TAG, "UNEXPECTED EVENT");
+       }
+
+       /* The event will not be processed after unregister */
+       ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
+       ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
+       vEventGroupDelete(s_wifi_event_group);
+}
+
+static void mlt_log(meshlink_handle_t *mesh, meshlink_log_level_t leve, const char *text) {
+       ESP_LOGI(TAG, "Log: %s", text);
+}
+
+meshlink_handle_t *mesh = NULL;
+
+static void receive(meshlink_handle_t *mesh, meshlink_node_t *from, const void *data, size_t len) {
+       char *str = (char *)data;
+       str[len] = 0;
+       ESP_LOGI(TAG, "%s says: %s", from->name, str);
+}
+
+static int join_func(int argc, char **argv) {
+       if(argc < 2) {
+               return 1;
+       }
+
+       if(!meshlink_join(mesh, argv[1])) {
+               ESP_LOGE(TAG, "Join failed");
+               return 1;
+       }
+
+       ESP_LOGI(TAG, "Join completed");
+
+       meshlink_set_receive_cb(mesh, receive);
+
+       if(!meshlink_start(mesh)) {
+               ESP_LOGE(TAG, "Could not start mesh!");
+               return 1;
+       }
+
+       return 0;
+}
+
+static int say_func(int argc, char **argv) {
+       if(argc < 3) {
+               return 1;
+       }
+
+       meshlink_node_t *peer = meshlink_get_node(mesh, argv[1]);
+
+       if(!peer) {
+               ESP_LOGE(TAG, "Peer not found");
+               return 1;
+       }
+
+       if(!meshlink_send(mesh, peer, argv[2], strlen(argv[2]))) {
+               ESP_LOGE(TAG, "Send failed");
+               return 1;
+       }
+
+       return 0;
+}
+
+static int quit_func(int argc, char **argv) {
+       meshlink_close(mesh);
+       mesh = NULL;
+       ESP_LOGI(TAG, "Closed mesh");
+       return 0;
+}
+
+static void mlt_main(void) {
+       meshlink_set_log_cb(NULL, MESHLINK_DEBUG, mlt_log);
+
+       ESP_LOGI(TAG, "Starting MeshLink-tiny instance...");
+       mesh = meshlink_open_ephemeral("esp32", "chat", DEV_CLASS_PORTABLE);
+
+       if(!mesh) {
+               ESP_LOGE(TAG, "Open failed!");
+               return;
+       }
+
+       fflush(stdout);
+       fsync(fileno(stdout));
+       setvbuf(stdin, NULL, _IONBF, 0);
+
+       esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR);
+       esp_vfs_dev_uart_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF);
+
+       const uart_config_t uart_config = {
+               .baud_rate = CONFIG_ESP_CONSOLE_UART_BAUDRATE,
+               .data_bits = UART_DATA_8_BITS,
+               .parity = UART_PARITY_DISABLE,
+               .stop_bits = UART_STOP_BITS_1,
+#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
+               .source_clk = UART_SCLK_REF_TICK,
+#else
+               .source_clk = UART_SCLK_XTAL,
+#endif
+       };
+       /* Install UART driver for interrupt-driven reads and writes */
+       ESP_ERROR_CHECK(uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM,
+                                           256, 0, 0, NULL, 0));
+       ESP_ERROR_CHECK(uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config));
+
+       /* Tell VFS to use UART driver */
+       esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
+
+       esp_console_config_t console_config = {
+               .max_cmdline_args = 8,
+               .max_cmdline_length = 256,
+       };
+
+       ESP_ERROR_CHECK(esp_console_init(&console_config));
+
+       linenoiseSetMultiLine(1);
+       linenoiseHistorySetMaxLen(1);
+       linenoiseAllowEmpty(false);
+
+       esp_console_cmd_t join_cmd = {
+               .command = "join",
+               .help = "Join a mesh",
+               .func = join_func,
+       };
+
+       esp_console_cmd_t say_cmd = {
+               .command = "say",
+               .help = "Say something",
+               .func = say_func,
+       };
+
+       esp_console_cmd_t quit_cmd = {
+               .command = "quit",
+               .help = "Quit",
+               .func = quit_func,
+       };
+
+       esp_console_cmd_register(&join_cmd);
+       esp_console_cmd_register(&say_cmd);
+       esp_console_cmd_register(&quit_cmd);
+       esp_console_register_help_command();
+
+       while(mesh) {
+               char *line = linenoise("> ");
+
+               if(!line) {
+                       continue;
+               }
+
+               linenoiseHistoryAdd(line);
+               int ret;
+               esp_console_run(line, &ret);
+               linenoiseFree(line);
+       }
+
+       ESP_LOGI(TAG, "App quit");
+       esp_console_deinit();
+}
+
+void app_main(void) {
+       //Initialize NVS
+       esp_err_t ret = nvs_flash_init();
+
+       if(ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+               ESP_ERROR_CHECK(nvs_flash_erase());
+               ret = nvs_flash_init();
+       }
+
+       ESP_ERROR_CHECK(ret);
+
+       ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
+       wifi_init_sta();
+       mlt_main();
+}
index a31ba7a345d291d4f75ba2c513b73b2559472689..1f6f0cdb6e1cf196f7f6811b3b4ac163a91f620f 100644 (file)
@@ -20,7 +20,7 @@
     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
-#include "../config.h"
+#include "../config-esp32.h"
 
 #include "have.h"