console.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /* Console example
  2. This example code is in the Public Domain (or CC0 licensed, at your option.)
  3. Unless required by applicable law or agreed to in writing, this
  4. software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  5. CONDITIONS OF ANY KIND, either express or implied.
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include "esp_system.h"
  11. #include "esp_log.h"
  12. #include "esp_console.h"
  13. #include "esp_vfs_dev.h"
  14. #include "driver/uart.h"
  15. #include "linenoise/linenoise.h"
  16. #include "argtable3/argtable3.h"
  17. #include "esp_vfs_fat.h"
  18. #include "nvs.h"
  19. #include "nvs_flash.h"
  20. #include "pthread.h"
  21. #include "platform_esp32.h"
  22. #include "esp_pthread.h"
  23. #include "cmd_decl.h"
  24. #include "console.h"
  25. #include "wifi_manager.h"
  26. #include "cmd_squeezelite.h"
  27. #include "nvs_utilities.h"
  28. pthread_t thread_console;
  29. static void * console_thread();
  30. void console_start();
  31. static const char * TAG = "console";
  32. #if RECOVERY_APPLICATION ==1
  33. extern void start_ota(const char * bin_url);
  34. #endif
  35. /* Prompt to be printed before each line.
  36. * This can be customized, made dynamic, etc.
  37. */
  38. const char* prompt = LOG_COLOR_I "squeezelite-esp32> " LOG_RESET_COLOR;
  39. /* Console command history can be stored to and loaded from a file.
  40. * The easiest way to do this is to use FATFS filesystem on top of
  41. * wear_levelling library.
  42. */
  43. #define MOUNT_PATH "/data"
  44. #define HISTORY_PATH MOUNT_PATH "/history.txt"
  45. void run_command(char * line);
  46. //optListStruct * getOptionByName(char * option){
  47. // optListStruct * curOpt=&optList[0];
  48. // while(curOpt->optName !=NULL){
  49. // if(!strcmp(curOpt->optName, option)){
  50. // return curOpt;
  51. // }
  52. // curOpt++;
  53. // }
  54. // return NULL;
  55. //}
  56. //
  57. //static int list_options(int argc, char **argv)
  58. //{
  59. // nvs_handle nvs;
  60. // esp_err_t err;
  61. //
  62. // err = nvs_open(current_namespace, NVS_READONLY, &nvs);
  63. // if (err != ESP_OK) {
  64. // return err;
  65. // }
  66. // //
  67. // optListStruct * curOpt=&optList[0];
  68. // printf("System Configuration Options.\n");
  69. // while(curOpt->optName!=NULL){
  70. // printf("Option: %s\n"
  71. // " Description: %20s\n"
  72. // " Default Value: %20s\n"
  73. // " Current Value: ",curOpt->optName, curOpt->description, curOpt->defaultValue);
  74. // size_t len;
  75. // if ( (nvs_get_str(nvs, curOpt->optName, NULL, &len)) == ESP_OK) {
  76. // char *str = (char *)malloc(len);
  77. // if ( (nvs_get_str(nvs, curOpt->optName, str, &len)) == ESP_OK) {
  78. // printf("%20s\n", str);
  79. // }
  80. // free(str);
  81. // }
  82. // else
  83. // {
  84. // if(store_nvs_value(NVS_TYPE_STR, curOpt->optName,curOpt->defaultValue, strlen(curOpt->defaultValue))==ESP_OK)
  85. // {
  86. // printf("%20s\n", curOpt->defaultValue);
  87. // }
  88. // else
  89. // {
  90. // printf("Error. Invalid key\n");
  91. // }
  92. // }
  93. // curOpt++;
  94. // }
  95. // printf("\n");
  96. // nvs_close(nvs);
  97. // return 0;
  98. //}
  99. //void register_list_options(){
  100. // const esp_console_cmd_t config_list = {
  101. // .command = "config-list",
  102. // .help = "Lists available configuration options.",
  103. // .hint = NULL,
  104. // .func = &list_options,
  105. // .argtable = NULL
  106. // };
  107. //
  108. // ESP_ERROR_CHECK( esp_console_cmd_register(&config_list) );
  109. //
  110. //}
  111. void process_autoexec(){
  112. int i=1;
  113. char autoexec_name[21]={0};
  114. char * autoexec_value=NULL;
  115. uint8_t * autoexec_flag=NULL;
  116. autoexec_flag = get_nvs_value_alloc(NVS_TYPE_U8, "autoexec");
  117. if(autoexec_flag!=NULL ){
  118. ESP_LOGI(TAG,"autoexec flag value found with value %u", *autoexec_flag);
  119. if(*autoexec_flag == 1) {
  120. do {
  121. snprintf(autoexec_name,sizeof(autoexec_name)-1,"autoexec%u",i++);
  122. ESP_LOGD(TAG,"Getting command name %s", autoexec_name);
  123. autoexec_value= get_nvs_value_alloc(NVS_TYPE_STR, autoexec_name);
  124. if(autoexec_value!=NULL ){
  125. ESP_LOGI(TAG,"Running command %s = %s", autoexec_name, autoexec_value);
  126. run_command(autoexec_value);
  127. ESP_LOGD(TAG,"Freeing memory for command %s name", autoexec_name);
  128. free(autoexec_value);
  129. }
  130. else {
  131. ESP_LOGD(TAG,"No matching command found for name %s", autoexec_name);
  132. break;
  133. }
  134. } while(1);
  135. }
  136. free(autoexec_flag);
  137. }
  138. else
  139. {
  140. ESP_LOGD(TAG,"No matching command found for name autoexec. Adding default entries");
  141. uint8_t autoexec_dft=0;
  142. char autoexec1_dft[256]="squeezelite -o I2S -b 500:2000 -d all=info -M esp32";
  143. store_nvs_value(NVS_TYPE_U8,"autoexec",&autoexec_dft);
  144. store_nvs_value(NVS_TYPE_STR,"autoexec1",autoexec1_dft);
  145. }
  146. }
  147. static void initialize_filesystem() {
  148. static wl_handle_t wl_handle;
  149. const esp_vfs_fat_mount_config_t mount_config = {
  150. .max_files = 10,
  151. .format_if_mount_failed = true,
  152. .allocation_unit_size = 4096
  153. };
  154. esp_err_t err = esp_vfs_fat_spiflash_mount(MOUNT_PATH, "storage",
  155. &mount_config, &wl_handle);
  156. if (err != ESP_OK) {
  157. ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err));
  158. return;
  159. }
  160. }
  161. static void initialize_nvs() {
  162. esp_err_t err = nvs_flash_init();
  163. if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
  164. ESP_ERROR_CHECK(nvs_flash_erase());
  165. err = nvs_flash_init();
  166. }
  167. ESP_ERROR_CHECK(err);
  168. }
  169. void initialize_console() {
  170. /* Disable buffering on stdin */
  171. setvbuf(stdin, NULL, _IONBF, 0);
  172. /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
  173. esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
  174. /* Move the caret to the beginning of the next line on '\n' */
  175. esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
  176. /* Configure UART. Note that REF_TICK is used so that the baud rate remains
  177. * correct while APB frequency is changing in light sleep mode.
  178. */
  179. const uart_config_t uart_config = { .baud_rate =
  180. CONFIG_CONSOLE_UART_BAUDRATE, .data_bits = UART_DATA_8_BITS,
  181. .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1,
  182. .use_ref_tick = true };
  183. ESP_ERROR_CHECK(uart_param_config(CONFIG_CONSOLE_UART_NUM, &uart_config));
  184. /* Install UART driver for interrupt-driven reads and writes */
  185. ESP_ERROR_CHECK(
  186. uart_driver_install(CONFIG_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0));
  187. /* Tell VFS to use UART driver */
  188. esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM);
  189. /* Initialize the console */
  190. esp_console_config_t console_config = { .max_cmdline_args = 22,
  191. .max_cmdline_length = 600,
  192. #if CONFIG_LOG_COLORS
  193. .hint_color = atoi(LOG_COLOR_CYAN)
  194. #endif
  195. };
  196. ESP_ERROR_CHECK(esp_console_init(&console_config));
  197. /* Configure linenoise line completion library */
  198. /* Enable multiline editing. If not set, long commands will scroll within
  199. * single line.
  200. */
  201. linenoiseSetMultiLine(1);
  202. /* Tell linenoise where to get command completions and hints */
  203. linenoiseSetCompletionCallback(&esp_console_get_completion);
  204. linenoiseSetHintsCallback((linenoiseHintsCallback*) &esp_console_get_hint);
  205. /* Set command history size */
  206. linenoiseHistorySetMaxLen(100);
  207. /* Load command history from filesystem */
  208. linenoiseHistoryLoad(HISTORY_PATH);
  209. }
  210. void console_start() {
  211. initialize_nvs();
  212. initialize_filesystem();
  213. initialize_console();
  214. /* Register commands */
  215. esp_console_register_help_command();
  216. register_system();
  217. register_nvs();
  218. #if RECOVERY_APPLICATION!=1
  219. #warning "compiling for squeezelite"
  220. register_squeezelite();
  221. #elif RECOVERY_APPLICATION==1
  222. #warning "compiling for recovery"
  223. register_ota_cmd();
  224. #else
  225. #error "Unknown build configuration"
  226. #endif
  227. register_i2ctools();
  228. printf("\n"
  229. "Type 'help' to get the list of commands.\n"
  230. "Use UP/DOWN arrows to navigate through command history.\n"
  231. "Press TAB when typing command name to auto-complete.\n"
  232. "\n"
  233. "To automatically execute lines at startup:\n"
  234. "\tSet NVS variable autoexec (U8) = 1 to enable, 0 to disable automatic execution.\n"
  235. "\tSet NVS variable autoexec[1~9] (string)to a command that should be executed automatically\n"
  236. "\n"
  237. "\n");
  238. /* Figure out if the terminal supports escape sequences */
  239. int probe_status = linenoiseProbe();
  240. if (probe_status) { /* zero indicates success */
  241. printf("\n****************************\n"
  242. "Your terminal application does not support escape sequences.\n"
  243. "Line editing and history features are disabled.\n"
  244. "On Windows, try using Putty instead.\n"
  245. "****************************\n");
  246. linenoiseSetDumbMode(1);
  247. #if CONFIG_LOG_COLORS
  248. /* Since the terminal doesn't support escape sequences,
  249. * don't use color codes in the prompt.
  250. */
  251. prompt = "squeezelite-esp32> ";
  252. #endif //CONFIG_LOG_COLORS
  253. }
  254. esp_pthread_cfg_t cfg = esp_pthread_get_default_config();
  255. cfg.thread_name= "console";
  256. cfg.inherit_cfg = true;
  257. esp_pthread_set_cfg(&cfg);
  258. pthread_attr_t attr;
  259. pthread_attr_init(&attr);
  260. pthread_create(&thread_console, &attr, console_thread, NULL);
  261. pthread_attr_destroy(&attr);
  262. }
  263. void run_command(char * line){
  264. /* Try to run the command */
  265. int ret;
  266. esp_err_t err = esp_console_run(line, &ret);
  267. if (err == ESP_ERR_NOT_FOUND) {
  268. printf("Unrecognized command\n");
  269. } else if (err == ESP_ERR_INVALID_ARG) {
  270. // command was empty
  271. } else if (err == ESP_OK && ret != ESP_OK) {
  272. printf("Command returned non-zero error code: 0x%x (%s)\n", ret,
  273. esp_err_to_name(err));
  274. } else if (err != ESP_OK) {
  275. printf("Internal error: %s\n", esp_err_to_name(err));
  276. }
  277. }
  278. static void * console_thread() {
  279. process_autoexec();
  280. /* Main loop */
  281. while (1) {
  282. /* Get a line using linenoise.
  283. * The line is returned when ENTER is pressed.
  284. */
  285. char* line = linenoise(prompt);
  286. if (line == NULL) { /* Ignore empty lines */
  287. continue;
  288. }
  289. /* Add the command to the history */
  290. linenoiseHistoryAdd(line);
  291. /* Save command history to filesystem */
  292. linenoiseHistorySave(HISTORY_PATH);
  293. printf("\n");
  294. run_command(line);
  295. /* linenoise allocates line buffer on the heap, so need to free it */
  296. linenoiseFree(line);
  297. }
  298. return NULL;
  299. }