text: // Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  #include <stdio.h>
  #include <string.h>
  
  #include "esp_system.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 "esp_vfs_fat.h"
  #include "nvs.h"
  #include "nvs_flash.h"
  
  #include "esp_bt.h"
  #include "esp_bt_main.h"
  
  #include "ble_mesh_console_decl.h"
  
  #define TAG "ble_mesh_test"
  
  #if CONFIG_STORE_HISTORY
  
  #define MOUNT_PATH "/data"
  #define HISTORY_PATH MOUNT_PATH "/history.txt"
  
  static void initialize_filesystem(void)
  {
      static wl_handle_t wl_handle;
      const esp_vfs_fat_mount_config_t mount_config = {
          .max_files = 4,
          .format_if_mount_failed = true
      };
      esp_err_t err = esp_vfs_fat_spiflash_mount(MOUNT_PATH, "storage", &mount_config, &wl_handle);
      if (err != ESP_OK) {
          ESP_LOGE(TAG, "Failed to mount FATFS (0x%x)", err);
          return;
      }
  }
  #endif // CONFIG_STORE_HISTORY
  
  static void initialize_console(void)
  {
      /* Disable buffering on stdin and stdout */
      setvbuf(stdin, NULL, _IONBF, 0);
      setvbuf(stdout, NULL, _IONBF, 0);
  
      /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
      esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
      /* Move the caret to the beginning of the next line on '\n' */
      esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
  
      /* Install UART driver for interrupt-driven reads and writes */
      ESP_ERROR_CHECK( uart_driver_install(CONFIG_CONSOLE_UART_NUM,
                                           256, 0, 0, NULL, 0) );
  
      /* Tell VFS to use UART driver */
      esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM);
  
      /* Initialize the console */
      esp_console_config_t console_config = {
          .max_cmdline_args = 20,
          .max_cmdline_length = 256,
  #if CONFIG_LOG_COLORS
          .hint_color = atoi(LOG_COLOR_CYAN)
  #endif
      };
      ESP_ERROR_CHECK( esp_console_init(&console_config) );
  
      /* Configure linenoise line completion library */
      /* Enable multiline editing. If not set, long commands will scroll within
       * a single line.
       */
      linenoiseSetMultiLine(1);
  
      /* Tell linenoise where to get command completions and hints */
      linenoiseSetCompletionCallback(&esp_console_get_completion);
      linenoiseSetHintsCallback((linenoiseHintsCallback *) &esp_console_get_hint);
  
      /* Set command history size */
      linenoiseHistorySetMaxLen(100);
  
  #if CONFIG_STORE_HISTORY
      /* Load command history from filesystem */
      linenoiseHistoryLoad(HISTORY_PATH);
  #endif
  }
  
  
  esp_err_t bluetooth_init(void)
  {
      esp_err_t ret;
  
      esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
      ret = esp_bt_controller_init(&bt_cfg);
      if (ret) {
          ESP_LOGE(TAG, "%s failed to initialize controller\n", __func__);
          return ret;
      }
  
      ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
      if (ret) {
          ESP_LOGE(TAG, "%s failed to enable controller\n", __func__);
          return ret;
      }
      ret = esp_bluedroid_init();
      if (ret) {
          ESP_LOGE(TAG, "%s failed to initialize bluetooth\n", __func__);
          return ret;
      }
      ret = esp_bluedroid_enable();
      if (ret) {
          ESP_LOGE(TAG, "%s failed to enable bluetooth\n", __func__);
          return ret;
      }
  
      esp_log_level_set("*", ESP_LOG_ERROR);
      esp_log_level_set("ble_mesh_prov_console", ESP_LOG_INFO);
  
      return ret;
  }
  
  void app_main(void)
  {
      esp_err_t res;
  
      nvs_flash_init();
  
      // init and enable bluetooth
      res = bluetooth_init();
      if (res) {
          printf("esp32_bluetooth_init failed (ret %d)", res);
      }
  
  #if CONFIG_STORE_HISTORY
      initialize_filesystem();
  #endif
  
      initialize_console();
  
      /* Register commands */
      esp_console_register_help_command();
      register_system();
      register_bluetooth();
      ble_mesh_register_mesh_node();
      ble_mesh_register_mesh_test_performance_client();
  #if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI)
      ble_mesh_register_gen_onoff_client();
  #endif
  #if (CONFIG_BLE_MESH_PROVISIONER)
      ble_mesh_register_mesh_provisioner();
  #endif
  #if (CONFIG_BLE_MESH_CFG_CLI)
      ble_mesh_register_configuration_client_model();
  #endif
  
  
      /* Prompt to be printed before each line.
       * This can be customized, made dynamic, etc.
       */
      const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR;
  
      printf("\n"
             "This is an example of an ESP-IDF console component.\n"
             "Type 'help' to get the list of commands.\n"
             "Use UP/DOWN arrows to navigate through the command history.\n"
             "Press TAB when typing a command name to auto-complete.\n");
  
      /* Figure out if the terminal supports escape sequences */
      int probe_status = linenoiseProbe();
      if (probe_status) { /* zero indicates OK */
          printf("\n"
                 "Your terminal application does not support escape sequences.\n"
                 "Line editing and history features are disabled.\n"
                 "On Windows, try using Putty instead.\n");
          linenoiseSetDumbMode(1);
  #if CONFIG_LOG_COLORS
          /* Since the terminal doesn't support escape sequences,
           * don't use color codes in the prompt.
           */
          prompt = "esp32> ";
  #endif //CONFIG_LOG_COLORS
      }
  
      /* Main loop */
      while (true) {
          /* Get a line using linenoise.
           * The line is returned when ENTER is pressed.
           */
          char *line = linenoise(prompt);
          if (line == NULL) { /* Ignore empty lines */
              continue;
          }
          /* Add the command to the history */
          linenoiseHistoryAdd(line);
  #if CONFIG_STORE_HISTORY
          /* Save command history to filesystem */
          linenoiseHistorySave(HISTORY_PATH);
  #endif
  
          /* Try to run the command */
          int ret;
          esp_err_t err = esp_console_run(line, &ret);
          if (err == ESP_ERR_NOT_FOUND) {
              printf("Unrecognized command\n");
          } else if (err == ESP_ERR_INVALID_ARG) {
              // command was empty
          } else if (err == ESP_OK && ret != ESP_OK) {
              printf("\nCommand returned non-zero error code: 0x%x\n", ret);
          } else if (err != ESP_OK) {
              printf("Internal error: 0x%x\n", err);
          }
          /* linenoise allocates line buffer on the heap, so need to free it */
          linenoiseFree(line);
      }
  }
  