You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

363 lines
9.4 KiB

2 years ago
/**
* Console - VCOM command engine
*
* Created on 2020/02/28 by Ondrej Hruska
*
* Parts are based on the console component from esp-idf
* licensed under the Apache 2 license.
*/
#ifndef LIBCONSOLE_H
#define LIBCONSOLE_H
#include <stdio.h>
#include <console/config.h>
#include <stdint.h>
#include <stdbool.h>
typedef enum {
/* Colors */
COLOR_RESET = 0xF0,
COLOR_BLACK = 0x01,
COLOR_RED = 0x02,
COLOR_GREEN = 0x03,
COLOR_YELLOW = 0x04,
COLOR_BLUE = 0x05,
COLOR_MAGENTA = 0x06,
COLOR_CYAN = 0x07,
COLOR_WHITE = 0x08,
/* Modifiers */
COLOR_NORMAL = 0x0F,
COLOR_BOLD = 0x10,
COLOR_UNDERLINE = 0x20,
COLOR_BLINK = 0x30,
COLOR_HIDE = 0x40,
} console_color_t;
#if CONSOLE_USE_FREERTOS
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
typedef SemaphoreHandle_t console_mutex_t;
#endif
#if CONSOLE_USE_PTHREADS
#include <pthread.h>
typedef pthread_mutex_t console_mutex_t;
#endif
#if CONSOLE_USE_TERMIOS
#include <termios.h>
#endif
/**
* Console config struct
*/
struct console_config {
/**
* Timeout waiting for execution lock when handling a command.
* This should be longer than the slowest command in the system.
*/
uint32_t execution_lock_timeout_ms;
};
/**
* Macro to init the console config struct
*/
#define CONSOLE_CONFIG_DEFAULTS() { \
.execution_lock_timeout_ms = 10000, \
}
typedef struct console_config console_config_t;
struct console_ctx; // early declaration
/**
* Console context
*/
typedef struct console_ctx console_ctx_t;
/**
* Console errors - return codes
*/
enum console_err {
CONSOLE_OK = 0,
/** unspecified error */
CONSOLE_ERROR = 1,
/** Allocation failed */
CONSOLE_ERR_NO_MEM,
/** Function call not allowed (e.g. console not inited) */
CONSOLE_ERR_BAD_CALL,
/** Argument validation failed */
CONSOLE_ERR_INVALID_ARG,
/** Command not recognized */
CONSOLE_ERR_UNKNOWN_CMD,
/** Timeout */
CONSOLE_ERR_TIMEOUT,
/** IO error (file open fail, etc.) */
CONSOLE_ERR_IO,
/** Operation denied (not allowed / insufficient rights) */
CONSOLE_ERR_NOT_POSSIBLE,
/** End marker */
_CONSOLE_ERR_MAX,
};
/**
* Print string describing console error.
* In case of unknown error, the number is shown.
*
* The argument should be `enum console_err`, but any number is valid.
*/
void console_err_print_ctx(struct console_ctx *ctx, int e);
// TODO error-to-string function
typedef enum console_err console_err_t;
// early decl's
struct cmd_signature;
typedef struct cmd_signature cmd_signature_t;
/**
* Command signature, passed as the last argument to the command handler
* to perform registration.
*
* \note Fill only fields that differ from default (zeros/NULLs)
*/
struct cmd_signature {
const char* command; //!< Command name, used in invocations (filled internally, do not set)
const char* help; //!< Command help text, shown when called with -h
const char* hint; //!< Hint text, generated from argtable if hint==NULL & argtable!=NULL
bool no_history; //!< Command skips history
bool custom_args; //!< Disable argtable parsing in the handler function, will be parsed manually from argv/argc
/**
* Argtable, struct or array that must end with arg_end().
* Used by the register function and for disambiguation.
*/
void* argtable;
};
/**
* Active console context pointer, valid only when handling a console command (otherwise NULL).
*
* Used by the console printf & other IO methods.
*/
extern struct console_ctx * console_active_ctx;
/**
* Function handling a callback from the console loop.
*/
typedef void(*console_callback_t)(console_ctx_t *ctx);
/**
* Console context struct
*/
struct console_ctx {
#if CONSOLE_USE_FILE_IO_STREAMS
// Streams
FILE* in; //!< stdin fd, can be -1 if not available (running commands in non-interactive mode)
FILE* out; //!< stdout fd
#if CONSOLE_USE_TERMIOS
// original termios is stored here before entering raw mode
struct termios orig_termios;
#endif
#else
void *ioctx;
#endif //CONSOLE_USE_FILE_IO_STREAMS
#if CONSOLE_FILE_SUPPORT
char *history_file;
#endif //CONSOLE_FILE_SUPPORT
bool __internal_heap_allocated;
bool exit_allowed;
char prompt[CONSOLE_PROMPT_MAX_LEN]; //!< Prompt, can be modified by a command or `before_readline_fn`
char line_buffer[CONSOLE_LINE_BUF_LEN];
/**
* Callback fired in the command evaluation loop, each time before the prompt is shown and new line read.
* This command can print to the output streams, change prompt, shutdown console, etc.
*/
console_callback_t loop_handler;
/**
* Callback fired before the console task shuts down
*/
console_callback_t shutdown_handler;
/**
* Shutdown requested. Console will exit as soon as possible.
*/
bool exit_requested;
/**
* Interactive mode. Enables additional outputs for user convenience.
*/
bool interactive;
/**
* Enable ANSI colors
*/
bool use_colors;
/* These fields are valid only during command execution */
const char **argv; //!< The current argv
size_t argc; //!< The current argc
const cmd_signature_t *cmd; //!< Pointer to the currently executed command signature
/** Used for argument validation */
uint32_t __internal_magic;
};
#define CONSOLE_CTX_MAGIC 0x6f587468
/**
* Command handler type.
*
* @param ctx - console context, including input/output files
* @param reg - signature struct; if not NULL, init the static argtable, fill this struct, and return OK (0).
* @return status code, 0 = OK (use cons_err_t constants if possible)
*/
typedef int (*console_command_t)(console_ctx_t *ctx, struct cmd_signature *reg);
/**
* Intialize the console
*
* @param config - config pointer, NULL to use defaults
* @return status code
*/
console_err_t console_init(const console_config_t *config);
/**
* @brief Register console command
*
* If the command function is already registered, this creates an alias.
* A multi-word command automatically create a command group. The group can
* be described using a description string by calling `console_group_add()`
* - at convenience before or after the commands are registered.
*
* @param name - command name (may contain spaces for "multi-part commands")
* @param handler pointer to the command handler.
* @return status code
*/
console_err_t console_cmd_register(console_command_t handler, const char *name);
/**
* @brief Register a command group.
*
* Command groups are created automatically when used.
* This method can create a group with description, or attach a custom description
* to an existing group.
*
* @param name - group name (first word of multi-part commands)
* @param descr - description to attach, can be NULL
* @return staus code
*/
console_err_t console_group_add(const char *name, const char *descr);
/**
* Add alias to an existing command by name.
*
* @param original - original command name
* @param alias - command's alias
* @return status code
*/
console_err_t console_cmd_add_alias(const char *original, const char *alias);
/**
* Add alias by handler function
*
* @param handler - command handler
* @param alias - new name
* @return status code
*/
console_err_t console_cmd_add_alias_fn(console_command_t handler, const char *alias);
/**
* Internal error print function. Has WEAK linkage, can be overridden.
*
* This function is used to report detected bugs and should not be called
* in well-written "production code".
*
* @param msg - error message
*/
void console_internal_error_print(const char *msg);
/**
* This function is guarded by a mutex and will wait for the execution lock as
* configured in console_config.
*
* @brief Run command line
* @param[in] outf
* @param[in] inf
* @param cmdline command line (command name followed by a number of arguments)
* @param[out] pRetval return code from the command (set if command was run)
* @param[out] pCommandSig - is set to a pointer to the matched command signature, or NULL on error
* @return status code
*/
console_err_t console_handle_cmd(
console_ctx_t *ctx,
const char *cmdline,
int *pRetval,
const struct cmd_signature **pCommandSig
);
/**
* Count all registered commands
*
* @return
*/
size_t console_count_commands(void);
/**
* Create a console IO context and init it to defaults.
*
* takes stdin and stdout file descriptors, or IO context (based on config flags)
*
* In the FD variant, pass NULL as STDIN if not available.
*
* @param ctx - context, if using static alloc, NULL to allocate internally.
* @return the context, NULL if alloc or init fails
*/
console_ctx_t *console_ctx_init(
console_ctx_t *ctx,
#if CONSOLE_USE_FILE_IO_STREAMS
FILE* inf, FILE* outf
#else
void * ioctx
#endif
);
/**
* Destroy a console IO context.
*
* Make sure to release any user fields (ioctx, for example) beforehand.
*
* @attention ONLY CALL THIS IF THE CONTEXT WAS DYNAMICALLY ALLOCATED!
*
* @param[in,out] ctx - pointer to context, will be set to NULL.
*/
void console_ctx_destroy(console_ctx_t *ctx);
/**
* Console task
*
* @param[in] param - must be a valid console context (see `console_ctx_init()`)
*/
void console_task(void *param);
/**
* Variant of 'console_task' for pthreads (returns NULL)
*/
void* console_task_posix(void *param);
#include "console_io.h"
#endif //LIBCONSOLE_H