retrofit to gcc8

This commit is contained in:
Sebastien
2020-03-04 13:01:24 -05:00
parent 5fb4b14e87
commit c97f9e2c59
61 changed files with 234 additions and 135 deletions

View File

@@ -1,8 +1,4 @@
set(COMPONENT_ADD_INCLUDEDIRS . )
set(COMPONENT_SRCS "esp_app_main.c" "platform_esp32.c" "cmd_wifi.c" "console.c" "nvs_utilities.c" "cmd_squeezelite.c" "config.c")
set(REQUIRES esp_common)
set(REQUIRES_COMPONENTS freertos squeezelite nvs_flash esp32 spi_flash newlib log console ota tools )
register_component()
idf_component_register(SRCS "esp_app_main.c"
REQUIRES esp_common pthread squeezelite-ota platform_console
INCLUDE_DIRS .
)

View File

@@ -1,22 +0,0 @@
/* Console example — declarations of command registration functions.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "cmd_system.h"
#include "cmd_wifi.h"
#include "cmd_nvs.h"
#include "cmd_i2ctools.h"
#include "cmd_ota.h"
#ifdef __cplusplus
}
#endif

View File

@@ -1,127 +0,0 @@
//size_t esp_console_split_argv(char *line, char **argv, size_t argv_size);
#include "cmd_squeezelite.h"
#include <stdio.h>
#include <string.h>
#include "cmd_decl.h"
#include "esp_log.h"
#include "esp_console.h"
#include "esp_pthread.h"
#include "argtable3/argtable3.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "pthread.h"
#include "platform_esp32.h"
#include "nvs.h"
#include "nvs_flash.h"
//extern char current_namespace[];
static const char * TAG = "squeezelite_cmd";
#define SQUEEZELITE_THREAD_STACK_SIZE (6*1024)
extern int main(int argc, char **argv);
static int launchsqueezelite(int argc, char **argv);
pthread_t thread_squeezelite;
pthread_t thread_squeezelite_runner;
/** Arguments used by 'squeezelite' function */
static struct {
struct arg_str *parameters;
struct arg_end *end;
} squeezelite_args;
static struct {
int argc;
char ** argv;
} thread_parms ;
static void * squeezelite_runner_thread(){
ESP_LOGI(TAG ,"Calling squeezelite");
main(thread_parms.argc,thread_parms.argv);
return NULL;
}
#define ADDITIONAL_SQUEEZELILTE_ARGS 5
static void * squeezelite_thread(){
int * exit_code;
static bool isRunning=false;
if(isRunning) {
ESP_LOGE(TAG,"Squeezelite already running. Exiting!");
return NULL;
}
isRunning=true;
// Let's not wait on WiFi to allow squeezelite to run in bluetooth mode
// ESP_LOGI(TAG,"Waiting for WiFi.");
// while(!wait_for_wifi()){usleep(100000);};
ESP_LOGV(TAG ,"Number of args received: %u",thread_parms.argc );
ESP_LOGV(TAG ,"Values:");
for(int i = 0;i<thread_parms.argc; i++){
ESP_LOGV(TAG ," %s",thread_parms.argv[i]);
}
ESP_LOGV(TAG,"Starting Squeezelite runner Thread");
esp_pthread_cfg_t cfg = esp_pthread_get_default_config();
cfg.thread_name= "squeezelite-run";
cfg.inherit_cfg = true;
cfg.stack_size = SQUEEZELITE_THREAD_STACK_SIZE ;
esp_pthread_set_cfg(&cfg);
// no attribute if we want esp stack stack to prevail
pthread_create(&thread_squeezelite_runner, NULL, squeezelite_runner_thread,NULL);
// Wait for thread completion so we can free up memory.
pthread_join(thread_squeezelite_runner,(void **)&exit_code);
ESP_LOGV(TAG ,"Exited from squeezelite's main(). Freeing argv structure.");
for(int i=0;i<thread_parms.argc;i++){
ESP_LOGV(TAG ,"Freeing char buffer for parameter %u", i+1);
free(thread_parms.argv[i]);
}
ESP_LOGV(TAG ,"Freeing argv pointer");
free(thread_parms.argv);
isRunning=false;
return NULL;
}
static int launchsqueezelite(int argc, char **argv)
{
ESP_LOGV(TAG ,"Begin");
ESP_LOGV(TAG, "Parameters:");
for(int i = 0;i<argc; i++){
ESP_LOGV(TAG, " %s",argv[i]);
}
ESP_LOGV(TAG,"Saving args in thread structure");
thread_parms.argc=0;
thread_parms.argv = malloc(sizeof(char**)*(argc+ADDITIONAL_SQUEEZELILTE_ARGS));
memset(thread_parms.argv,'\0',sizeof(char**)*(argc+ADDITIONAL_SQUEEZELILTE_ARGS));
for(int i=0;i<argc;i++){
ESP_LOGD(TAG ,"assigning parm %u : %s",i,argv[i]);
thread_parms.argv[thread_parms.argc++]=strdup(argv[i]);
}
if(argc==1){
// There isn't a default configuration that would actually work
// if no parameter is passed.
ESP_LOGV(TAG ,"Adding argv value at %u. Prev value: %s",thread_parms.argc,thread_parms.argv[thread_parms.argc-1]);
thread_parms.argv[thread_parms.argc++]=strdup("-?");
}
ESP_LOGD(TAG,"Starting Squeezelite Thread");
esp_pthread_cfg_t cfg = esp_pthread_get_default_config();
cfg.thread_name= "squeezelite";
cfg.inherit_cfg = true;
esp_pthread_set_cfg(&cfg);
pthread_create(&thread_squeezelite, NULL, squeezelite_thread,NULL);
ESP_LOGD(TAG ,"Back to console thread!");
return 0;
}
void register_squeezelite(){
squeezelite_args.parameters = arg_str0(NULL, NULL, "<parms>", "command line for squeezelite. -h for help, --defaults to launch with default values.");
squeezelite_args.end = arg_end(1);
const esp_console_cmd_t launch_squeezelite = {
.command = "squeezelite",
.help = "Starts squeezelite",
.hint = NULL,
.func = &launchsqueezelite,
.argtable = &squeezelite_args
};
ESP_ERROR_CHECK( esp_console_cmd_register(&launch_squeezelite) );
}

View File

@@ -1,13 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
// Register WiFi functions
void register_squeezelite();
#ifdef __cplusplus
}
#endif

View File

@@ -1,200 +0,0 @@
/* Console example — WiFi commands
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
// cmd_wifi has been replaced by wifi-manager
/* Console example <20> WiFi commands
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "cmd_wifi.h"
#include <stdio.h>
#include <string.h>
#include "cmd_decl.h"
#include "esp_log.h"
#include "esp_console.h"
#include "argtable3/argtable3.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "tcpip_adapter.h"
#include "esp_event.h"
#include "led.h"
extern bool bypass_wifi_manager;
#define JOIN_TIMEOUT_MS (10000)
extern EventGroupHandle_t wifi_event_group;
extern const int CONNECTED_BIT;
static const char * TAG = "cmd_wifi";
/** Arguments used by 'join' function */
static struct {
struct arg_int *timeout;
struct arg_str *ssid;
struct arg_str *password;
struct arg_end *end;
} join_args;
///** Arguments used by 'join' function */
//static struct {
// struct arg_int *autoconnect;
// struct arg_end *end;
//} auto_connect_args;
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_DISCONNECTED) {
led_blink_pushed(LED_GREEN, 250, 250);
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
led_unpush(LED_GREEN);
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
}
}
//bool wait_for_wifi(){
//
// bool connected=(xEventGroupGetBits(wifi_event_group) & CONNECTED_BIT)!=0;
//
// if(!connected){
// ESP_LOGD(TAG,"Waiting for WiFi...");
// connected = (xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
// pdFALSE, pdTRUE, JOIN_TIMEOUT_MS / portTICK_PERIOD_MS)& CONNECTED_BIT)!=0;
// if(!connected){
// ESP_LOGD(TAG,"wifi timeout.");
// }
// else
// {
// ESP_LOGI(TAG,"WiFi Connected!");
// }
// }
//
//
// return connected;
//
//}
static void initialise_wifi(void)
{
static bool initialized = false;
if (initialized) {
return;
}
tcpip_adapter_init();
// Now moved to esp_app_main: wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_create_default());
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_NULL) );
ESP_ERROR_CHECK( esp_wifi_start() );
initialized = true;
led_blink(LED_GREEN, 250, 250);
}
static bool wifi_join(const char *ssid, const char *pass, int timeout_ms)
{
initialise_wifi();
wifi_config_t wifi_config = { 0 };
strncpy((char *) wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid));
if (pass) {
strncpy((char *) wifi_config.sta.password, pass, sizeof(wifi_config.sta.password));
}
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
ESP_ERROR_CHECK( esp_wifi_connect() );
int bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
pdFALSE, pdTRUE, timeout_ms / portTICK_PERIOD_MS);
return (bits & CONNECTED_BIT) != 0;
}
static int set_auto_connect(int argc, char **argv)
{
// int nerrors = arg_parse(argc, argv, (void **) &join_args);
// if (nerrors != 0) {
// arg_print_errors(stderr, join_args.end, argv[0]);
// return 1;
// }
// ESP_LOGI(__func__, "Connecting to '%s'",
// join_args.ssid->sval[0]);
//
// /* set default value*/
// if (join_args.timeout->count == 0) {
// join_args.timeout->ival[0] = JOIN_TIMEOUT_MS;
// }
//
// bool connected = wifi_join(join_args.ssid->sval[0],
// join_args.password->sval[0],
// join_args.timeout->ival[0]);
// if (!connected) {
// ESP_LOGW(__func__, "Connection timed out");
// return 1;
// }
// ESP_LOGI(__func__, "Connected");
return 0;
}
static int connect(int argc, char **argv)
{
int nerrors = arg_parse(argc, argv, (void **) &join_args);
if (nerrors != 0) {
arg_print_errors(stderr, join_args.end, argv[0]);
return 1;
}
ESP_LOGI(__func__, "Connecting to '%s'",
join_args.ssid->sval[0]);
/* set default value*/
if (join_args.timeout->count == 0) {
join_args.timeout->ival[0] = JOIN_TIMEOUT_MS;
}
bool connected = wifi_join(join_args.ssid->sval[0],
join_args.password->sval[0],
join_args.timeout->ival[0]);
if (!connected) {
ESP_LOGW(__func__, "Connection timed out");
return 1;
}
ESP_LOGI(__func__, "Connected");
return 0;
}
void register_wifi_join()
{
join_args.timeout = arg_int0(NULL, "timeout", "<t>", "Connection timeout, ms");
join_args.ssid = arg_str1(NULL, NULL, "<ssid>", "SSID of AP");
join_args.password = arg_str0(NULL, NULL, "<pass>", "PSK of AP");
join_args.end = arg_end(2);
const esp_console_cmd_t join_cmd = {
.command = "join",
.help = "Join WiFi AP as a station",
.hint = NULL,
.func = &connect,
.argtable = &join_args
};
ESP_ERROR_CHECK( esp_console_cmd_register(&join_cmd) );
}
void register_wifi()
{
register_wifi_join();
if(bypass_wifi_manager){
initialise_wifi();
}
}

View File

@@ -1,18 +0,0 @@
/* Console example <20> declarations of command registration functions.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
// Register WiFi functions
void register_wifi();
#ifdef __cplusplus
}
#endif

View File

@@ -1,265 +0,0 @@
/* Console example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdlib.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 "nvs.h"
#include "nvs_flash.h"
#include "pthread.h"
#include "platform_esp32.h"
#include "esp_pthread.h"
#include "cmd_decl.h"
#include "console.h"
#include "wifi_manager.h"
#include "cmd_squeezelite.h"
#include "config.h"
pthread_t thread_console;
static void * console_thread();
void console_start();
static const char * TAG = "console";
extern bool bypass_wifi_manager;
/* Prompt to be printed before each line.
* This can be customized, made dynamic, etc.
*/
const char* prompt = LOG_COLOR_I "squeezelite-esp32> " LOG_RESET_COLOR;
/* Console command history can be stored to and loaded from a file.
* The easiest way to do this is to use FATFS filesystem on top of
* wear_levelling library.
*/
#define MOUNT_PATH "/data"
#define HISTORY_PATH MOUNT_PATH "/history.txt"
void run_command(char * line);
void process_autoexec(){
int i=1;
char autoexec_name[21]={0};
char * autoexec_value=NULL;
uint8_t autoexec_flag=0;
char * str_flag = config_alloc_get(NVS_TYPE_STR, "autoexec");
if(!bypass_wifi_manager){
ESP_LOGW(TAG, "Processing autoexec commands while wifi_manager active. Wifi related commands will be ignored.");
}
#if RECOVERY_APPLICATION
ESP_LOGD(TAG, "Processing autoexec commands in recovery mode. Squeezelite commands will be ignored.");
#endif
if(str_flag !=NULL ){
autoexec_flag=atoi(str_flag);
ESP_LOGI(TAG,"autoexec is set to %s auto-process", autoexec_flag>0?"perform":"skip");
if(autoexec_flag == 1) {
do {
snprintf(autoexec_name,sizeof(autoexec_name)-1,"autoexec%u",i++);
ESP_LOGD(TAG,"Getting command name %s", autoexec_name);
autoexec_value= config_alloc_get(NVS_TYPE_STR, autoexec_name);
if(autoexec_value!=NULL ){
if(!bypass_wifi_manager && strstr(autoexec_value, "join ")!=NULL ){
ESP_LOGW(TAG,"Ignoring wifi join command.");
}
#if RECOVERY_APPLICATION
else if(!strstr(autoexec_value, "squeezelite " ) ){
ESP_LOGW(TAG,"Ignoring command. ");
}
#endif
else {
ESP_LOGI(TAG,"Running command %s = %s", autoexec_name, autoexec_value);
run_command(autoexec_value);
}
ESP_LOGD(TAG,"Freeing memory for command %s name", autoexec_name);
free(autoexec_value);
}
else {
ESP_LOGD(TAG,"No matching command found for name %s", autoexec_name);
break;
}
} while(1);
}
free(str_flag);
}
else
{
ESP_LOGD(TAG,"No matching command found for name autoexec.");
}
}
void initialize_console() {
/* Disable buffering on stdin */
setvbuf(stdin, 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);
/* Configure UART. Note that REF_TICK is used so that the baud rate remains
* correct while APB frequency is changing in light sleep mode.
*/
const uart_config_t uart_config = { .baud_rate =
CONFIG_CONSOLE_UART_BAUDRATE, .data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1,
.use_ref_tick = true };
ESP_ERROR_CHECK(uart_param_config(CONFIG_CONSOLE_UART_NUM, &uart_config));
/* 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 = 22,
.max_cmdline_length = 600,
#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
* 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);
/* Load command history from filesystem */
//linenoiseHistoryLoad(HISTORY_PATH);
}
void console_start() {
initialize_console();
/* Register commands */
esp_console_register_help_command();
register_system();
register_nvs();
register_wifi();
#if RECOVERY_APPLICATION!=1
register_squeezelite();
#elif RECOVERY_APPLICATION==1
register_ota_cmd();
#else
#error "Unknown build configuration"
#endif
register_i2ctools();
printf("\n"
#if RECOVERY_APPLICATION
"****************************************************************\n"
"RECOVERY APPLICATION\n"
"This mode is used to flash Squeezelite into the OTA partition\n"
"****\n\n"
#endif
"Type 'help' to get the list of commands.\n"
"Use UP/DOWN arrows to navigate through command history.\n"
"Press TAB when typing command name to auto-complete.\n"
"\n"
#if !RECOVERY_APPLICATION
"To automatically execute lines at startup:\n"
"\tSet NVS variable autoexec (U8) = 1 to enable, 0 to disable automatic execution.\n"
"\tSet NVS variable autoexec[1~9] (string)to a command that should be executed automatically\n"
#endif
"\n"
"\n");
/* Figure out if the terminal supports escape sequences */
int probe_status = linenoiseProbe();
if (probe_status) { /* zero indicates success */
printf("\n****************************\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"
"****************************\n");
linenoiseSetDumbMode(1);
#if CONFIG_LOG_COLORS
/* Since the terminal doesn't support escape sequences,
* don't use color codes in the prompt.
*/
prompt = "squeezelite-esp32> ";
#endif //CONFIG_LOG_COLORS
}
esp_pthread_cfg_t cfg = esp_pthread_get_default_config();
cfg.thread_name= "console";
cfg.inherit_cfg = true;
#if RECOVERY_APPLICATION
cfg.stack_size = 4096 ;
#endif
esp_pthread_set_cfg(&cfg);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&thread_console, &attr, console_thread, NULL);
pthread_attr_destroy(&attr);
}
void run_command(char * line){
/* Try to run the command */
int ret;
esp_err_t err = esp_console_run(line, &ret);
if (err == ESP_ERR_NOT_FOUND) {
ESP_LOGE(TAG,"Unrecognized command: %s\n", line);
} else if (err == ESP_ERR_INVALID_ARG) {
// command was empty
} else if (err == ESP_OK && ret != ESP_OK) {
ESP_LOGW(TAG,"Command returned non-zero error code: 0x%x (%s)\n", ret,
esp_err_to_name(err));
} else if (err != ESP_OK) {
ESP_LOGE(TAG,"Internal error: %s\n", esp_err_to_name(err));
}
}
static void * console_thread() {
#if !RECOVERY_APPLICATION
process_autoexec();
#endif
/* Main loop */
while (1) {
/* 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);
/* Save command history to filesystem */
linenoiseHistorySave(HISTORY_PATH);
printf("\n");
run_command(line);
/* linenoise allocates line buffer on the heap, so need to free it */
linenoiseFree(line);
taskYIELD();
}
return NULL;
}

View File

@@ -1,18 +0,0 @@
/* Console example — declarations of command registration functions.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -45,7 +45,7 @@
#include "wifi_manager.h"
#include "squeezelite-ota.h"
#include <math.h>
#include "config.h"
#include "platform_config.h"
#include "audio_controls.h"
#include "telnet.h"

View File

@@ -1,39 +0,0 @@
/*
* Squeezelite for esp32
*
* (c) Sebastien 2019
* Philippe G. 2019, philippe_44@outlook.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "esp_pthread.h"
#ifndef SQUEEZELITE_ESP32_RELEASE_URL
#define SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
#endif
extern void run_command(char * line);
extern bool wait_for_wifi();
extern void console_start();
extern pthread_cond_t wifi_connect_suspend_cond;
extern pthread_t wifi_connect_suspend_mutex;
typedef enum {
INFO,
WARNING,
ERROR
} message_severity_t;
extern void set_status_message(message_severity_t severity, const char * message);