sdk-hwV1.3/lichee/melis-v3.0/source/ekernel/components/aw/multi_console/console.c

984 lines
22 KiB
C
Executable File

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <cli_console.h>
#include <hal_log.h>
int32_t hal_uart_send(int32_t dev, const char *data, uint32_t num);
extern cli_console cli_null_console; /* null console never exit */
static LIST_HEAD(gCliConsolelist);
#if !defined(CONFIG_DISABLE_ALL_UART_LOG)
extern cli_console cli_uart_console;
static cli_console *default_console = &cli_uart_console;
#else
static cli_console *default_console = &cli_null_console;
#endif
static cli_console *global_console = NULL;
static int mul_console_init_flag = 0;
static cli_console_spinlock_t console_lock;
#ifdef CONFIG_MULTI_CONSOLE_DEBUG
/*
* dump target console information
* @console: target console
* */
static void dump_cli_console_info(cli_console *console)
{
struct list_head *pos;
struct list_head *q;
wraper_task *tmp;
int i = 0;
if (console == NULL)
{
return;
}
printf("name : [%s]\n", console->name);
list_for_each_safe(pos, q, &console->task_list)
{
tmp = list_entry(pos, wraper_task, task_list_node);
if (tmp)
{
printf("inode[%d] : %s\n", i, get_task_name(tmp->task));
i++;
}
}
}
/*
* dump all cli console information
*/
int dump_all_cli_console_info(void)
{
struct list_head *pos;
struct list_head *q;
cli_console *tmp = NULL;
list_for_each_safe(pos, q, &gCliConsolelist)
{
tmp = list_entry(pos, cli_console, i_list);
dump_cli_console_info(tmp);
}
return 0;
}
/**
* cli_console_debug_printf, to debug multi-console itself
*/
int cli_console_debug_printf(const char *fmt, ...)
{
int ret;
va_list ap;
cpu_cpsr_t flags_cpsr;
char *b;
int i;
#define CLI_CONSOLE_DEBUG_BUF_SIZE 512
static char cli_console_debug_buf[CLI_CONSOLE_DEBUG_BUF_SIZE];
va_start(ap, fmt);
flags_cpsr = cli_console_lock(&console_lock);
ret = vsnprintf(cli_console_debug_buf, sizeof(cli_console_debug_buf) - 1, fmt, ap);
b = (char *)&cli_console_debug_buf;
if (ret > CLI_CONSOLE_DEBUG_BUF_SIZE)
{
ret = CLI_CONSOLE_DEBUG_BUF_SIZE;
}
for (i = 0; i < ret; i ++)
{
if (*(b + i) == '\n')
{
hal_uart_send(CONFIG_CLI_UART_PORT, "\r", 1);
}
hal_uart_send(CONFIG_CLI_UART_PORT, b + i, 1);
}
cli_console_unlock(&console_lock, flags_cpsr);
va_end(ap);
return ret;
}
#endif
int cli_console_printf(cli_console *console, const char *fmt, ...)
{
int ret;
va_list ap;
cpu_cpsr_t flags_cpsr;
#define CLI_CONSOLE_DEBUG_BUF_SIZE 512
static char cli_console_debug_buf[CLI_CONSOLE_DEBUG_BUF_SIZE];
va_start(ap, fmt);
flags_cpsr = cli_console_lock(&console_lock);
ret = vsnprintf(cli_console_debug_buf, sizeof(cli_console_debug_buf) - 1, fmt, ap);
if (ret > CLI_CONSOLE_DEBUG_BUF_SIZE)
{
ret = CLI_CONSOLE_DEBUG_BUF_SIZE;
}
cli_console_unlock(&console_lock, flags_cpsr);
cli_console_write(console, &cli_console_debug_buf, ret);
va_end(ap);
return ret;
}
int register_cli_console_to_list(cli_console *console)
{
cpu_cpsr_t flags_cpsr;
if (console == NULL)
{
return -1;
}
INIT_LIST_HEAD(&console->i_list);
flags_cpsr = cli_console_lock(&console_lock);
list_add(&console->i_list, &gCliConsolelist);
cli_console_unlock(&console_lock, flags_cpsr);
return 0;
}
int remove_cli_console_from_list(cli_console *console)
{
struct list_head *pos;
struct list_head *q;
cli_console *tmp;
cpu_cpsr_t flags_cpsr;
if (console == NULL)
{
return -1;
}
flags_cpsr = cli_console_lock(&console_lock);
list_for_each_safe(pos, q, &gCliConsolelist)
{
tmp = list_entry(pos, cli_console, i_list);
if (tmp == console)
{
list_del(pos);
break;
}
}
cli_console_unlock(&console_lock, flags_cpsr);
return 0;
}
static cli_console *lookup_cli_console(const char *name)
{
struct list_head *pos;
struct list_head *q;
cli_console *tmp;
cpu_cpsr_t flags_cpsr;
if (name == NULL)
{
return NULL;
}
flags_cpsr = cli_console_lock(&console_lock);
list_for_each_safe(pos, q, &gCliConsolelist)
{
tmp = list_entry(pos, cli_console, i_list);
if (!strcmp(name, tmp->name))
{
cli_console_unlock(&console_lock, flags_cpsr);
return tmp;
}
}
cli_console_unlock(&console_lock, flags_cpsr);
return NULL;
}
static int cli_console_check_is_in_list(cli_console *console)
{
struct list_head *pos;
struct list_head *q;
cli_console *tmp;
int ret = 0;
cpu_cpsr_t flags_cpsr;
if (console == NULL)
{
return ret;
}
flags_cpsr = cli_console_lock(&console_lock);
list_for_each_safe(pos, q, &gCliConsolelist)
{
tmp = list_entry(pos, cli_console, i_list);
if (console == tmp)
{
ret = 1;
}
}
cli_console_unlock(&console_lock, flags_cpsr);
return ret;
}
int get_alive_console_num(void)
{
struct list_head *pos;
struct list_head *q;
cli_console *tmp;
int alive_console_n = 0;
cpu_cpsr_t flags_cpsr;
flags_cpsr = cli_console_lock(&console_lock);
list_for_each_safe(pos, q, &gCliConsolelist)
{
tmp = list_entry(pos, cli_console, i_list);
if (tmp->alive == 1)
{
alive_console_n++;
}
}
cli_console_unlock(&console_lock, flags_cpsr);
return alive_console_n;
}
cli_console *get_default_console(void)
{
cpu_cpsr_t flags_cpsr;
cli_console *tmp;
flags_cpsr = cli_console_lock(&console_lock);
if (default_console->exit_flag == 1 || default_console->init_flag == 0)
{
tmp = &cli_null_console;
}
else
{
tmp = default_console;
}
cli_console_unlock(&console_lock, flags_cpsr);
return tmp;
}
cli_console *set_default_console(void *console)
{
cpu_cpsr_t flags_cpsr;
cli_console *last_console;
flags_cpsr = cli_console_lock(&console_lock);
last_console = default_console;
default_console = console;
cli_console_unlock(&console_lock, flags_cpsr);
return last_console;
}
cli_console *get_global_console(void)
{
cpu_cpsr_t flags_cpsr;
cli_console *tmp;
flags_cpsr = cli_console_lock(&console_lock);
tmp = global_console;
cli_console_unlock(&console_lock, flags_cpsr);
return tmp;
}
cli_console *set_global_console(void *console)
{
cpu_cpsr_t flags_cpsr;
cli_console *last_console;
flags_cpsr = cli_console_lock(&console_lock);
last_console = global_console;
global_console = console;
cli_console_unlock(&console_lock, flags_cpsr);
return last_console;
}
cli_console *get_current_console(void)
{
cli_console *console = NULL;
console = get_global_console();
if (console)
{
return console;
}
console = cli_task_get_console(cli_current_task());
return (console != NULL && console->exit_flag != 1 && console->init_flag == 1) ? console : get_default_console();
}
/*
* get real console from cli task
* @return cli task console
* */
cli_console *get_clitask_console(void)
{
return cli_task_get_console(cli_current_task());
}
void cli_console_add_task_list_node(void *current_console, void *task)
{
cli_console *console = (cli_console *)(current_console);
cpu_cpsr_t flags_cpsr;
if (console == NULL || task == NULL)
{
return;
}
wraper_task *wraper_task_node = malloc(sizeof(wraper_task));
if (wraper_task_node == NULL)
{
return;
}
memset(wraper_task_node, 0, sizeof(wraper_task));
flags_cpsr = cli_console_lock(&console->lock);
wraper_task_node->task = task;
INIT_LIST_HEAD(&wraper_task_node->task_list_node);
list_add(&wraper_task_node->task_list_node, &console->task_list);
cli_console_unlock(&console->lock, flags_cpsr);
}
void cli_console_remove_task_list_node(cli_console *console, void *task)
{
struct list_head *pos;
struct list_head *q;
wraper_task *tmp;
cpu_cpsr_t flags_cpsr;
if (console == NULL)
{
return;
}
flags_cpsr = cli_console_lock(&console->lock);
list_for_each_safe(pos, q, &console->task_list)
{
tmp = list_entry(pos, wraper_task, task_list_node);
if (tmp && tmp->task == task)
{
list_del(pos);
free(tmp);
break;
}
}
cli_console_unlock(&console->lock, flags_cpsr);
}
static void cli_console_clear_task_list(cli_console *console)
{
struct list_head *pos;
struct list_head *q;
wraper_task *tmp;
cpu_cpsr_t flags_cpsr;
if (console == NULL)
{
return;
}
flags_cpsr = cli_console_lock(&console->lock);
list_for_each_safe(pos, q, &console->task_list)
{
tmp = list_entry(pos, wraper_task, task_list_node);
if (tmp && tmp->task)
{
cli_task_clear_console(tmp->task);
list_del(pos);
free(tmp);
}
}
cli_console_unlock(&console->lock, flags_cpsr);
}
static int new_line_format_write(
cli_console *console,
device_console *dev_console,
const char *inbuf,
char *outbuf,
size_t input_nbytes,
size_t output_nbytes)
{
int size = input_nbytes;
int wbytes = 0;
int i = 0;
int j = 0;
while (size--)
{
if (*(inbuf + j) == '\n')
{
outbuf[i++] = '\r';
}
outbuf[i++] = *(inbuf + j);
j++;
}
wbytes = dev_console->write(outbuf, output_nbytes, console->private_data);
if (wbytes >= input_nbytes)
{
wbytes = input_nbytes;
}
return wbytes;
}
int cli_console_read(cli_console *console, void *buf, size_t nbytes)
{
device_console *dev_console;
int rbytes = 0;
if (!cli_console_check_is_in_list(console))
{
console = get_current_console();
}
if (console == NULL)
{
console = get_current_console();
}
if (console && !console->exit_flag)
{
dev_console = console->dev_console;
if (dev_console && dev_console->read)
{
rbytes = dev_console->read(buf, nbytes, console->private_data);
}
}
else
{
rbytes = 0;
}
return rbytes;
}
int cli_console_write(cli_console *console, const void *buf, size_t nbytes)
{
int wbytes = -1;
cpu_cpsr_t flags_cpsr;
device_console *dev_console = NULL;
if (cli_console_is_irq_context() != 0)
{
#if !defined(CONFIG_DISABLE_ALL_UART_LOG)
wbytes = uart_console_write(buf, nbytes, NULL);
#else
wbytes = nbytes;
#endif
return wbytes;
}
if (!cli_console_check_is_in_list(console))
{
console = get_current_console();
}
if (console == NULL)
{
console = get_current_console();
}
if (console && !console->exit_flag)
{
dev_console = console->dev_console;
if (dev_console && dev_console->write)
{
#if 1
int re_num = 0, size = nbytes, re_it = 0;
char *inbuf = (char *)buf;
while (size--)
{
if (*(inbuf + re_it) == '\n')
{
re_num++;
}
re_it++;
}
if (re_num + nbytes > 64)
{
char *outbuf = malloc(re_num + nbytes);
if (outbuf)
{
memset(outbuf, 0, re_num + nbytes);
wbytes = new_line_format_write(console, dev_console, inbuf, outbuf, nbytes, re_num + nbytes);
free(outbuf);
}
else
{
wbytes = dev_console->write(inbuf, nbytes, console->private_data);
}
}
else
{
char outbuf[64];
memset(outbuf, 0, 64);
wbytes = new_line_format_write(console, dev_console, inbuf, outbuf, nbytes, re_num + nbytes);
}
#else
wbytes = dev_console->write(buf, nbytes, console->private_data);
#endif
}
}
else
{
wbytes = nbytes;
}
return wbytes;
}
int cli_console_init(cli_console *console)
{
int ret = -1;
device_console *dev_console = NULL;
if (console && console->init_flag == 0)
{
INIT_LIST_HEAD(&console->task_list);
register_cli_console_to_list(console);
cli_console_lock_init(&console->lock);
dev_console = console->dev_console;
if (dev_console && dev_console->init)
{
ret = dev_console->init(console->private_data);
if (ret == 1)
{
console->exit_flag = 0;
console->init_flag = 1;
}
}
}
return ret;
}
int cli_console_deinit(cli_console *console)
{
int ret = -1;
device_console *dev_console = NULL;
if (global_console != NULL && global_console == console)
{
set_global_console(NULL);
}
if (console && console->init_flag == 1)
{
cpu_cpsr_t flags_cpsr;
flags_cpsr = cli_console_lock(&console->lock);
console->exit_flag = 1;
cli_console_unlock(&console->lock, flags_cpsr);
cli_console_clear_task_list(console);
remove_cli_console_from_list(console);
dev_console = console->dev_console;
if (dev_console && dev_console->deinit)
{
ret = dev_console->deinit(console->private_data);
if (ret == 1)
{
console->exit_flag = 1;
console->init_flag = 0;
}
}
}
return ret;
}
/*
* create new cli_console
* @param dev_console: the device console is attached to the new cli console
* @param name: the name of new cli console
* @param private_data: the private data of the new cli console
*/
cli_console *cli_console_create(
device_console *dev_console,
const char *name,
void *private_data)
{
cli_console *console;
if (dev_console == NULL)
{
return NULL;
}
console = malloc(sizeof(cli_console));
if (console == NULL)
{
return NULL;
}
memset(console, 0, sizeof(cli_console));
console->dev_console = dev_console;
memcpy(console->name, name, CLI_CONSOLE_MAX_NAME_LEN - 1 > strlen(name) ? strlen(name) : CLI_CONSOLE_MAX_NAME_LEN - 1);
console->private_data = private_data;
return console;
}
int cli_console_destory(cli_console *console)
{
if (console)
{
free(console);
return 0;
}
return -1;
}
/* get current console name
* @return the name of current console name
*/
char *cli_task_get_console_name(void)
{
cli_console *console;
char *name = NULL;
console = get_clitask_console();
if (console)
{
name = console->name;
}
if (name == NULL)
{
name = default_console->name;
}
return name;
}
/* get target console name
* @param console: the target console
* @return the name of target console
* */
char *cli_console_get_name(cli_console *console)
{
char *name = NULL;
if (console)
{
name = console->name;
}
if (name == NULL)
{
name = default_console->name;
}
return name;
}
int cli_console_check_invalid(cli_console *console)
{
if (console == NULL)
{
return 0;
}
return 1;
}
/* create a cli console task
* @param console: the console which is attached t the new task
* @param stack_size: the stack size of the new cli task
* @param priority: the priority of the new cli task
* */
int cli_console_task_create(cli_console *console, pthread_t *tid, uint32_t stack_size, uint32_t priority)
{
int32_t ret;
if (!cli_console_check_invalid(console))
{
return -1;
}
cli_console_init(console);
console->alive = 1;
pthread_attr_t attr;
struct sched_param sched;
sched.sched_priority = priority;
pthread_attr_init(&attr);
pthread_attr_setschedparam(&attr, &sched);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_attr_setstacksize(&attr, stack_size);
ret = pthread_create(tid, &attr, cli_console_thread_entry, console);
if (ret != 0)
{
return -1;
}
console->task = (void *)tid;
pthread_setname_np(*tid, cli_console_get_name(console));
return 0;
}
/*
* destory cli console task
* @param console: cli_console need to be destoryed
* @return 0
* */
int cli_console_task_destory(cli_console *console)
{
if (console == NULL)
{
return -1;
}
console->exit_flag = 1;
cli_console_deinit(console);
console->alive = 0;
return 0;
}
/*
* create a task for run cli command
* @param console: cli console
* @param stack_size: the stack size of the new task
* @param priority: the priority of the new task
* @param task_entry: the entry of the new task
* @param task_args: the arguments of the new task entry
* @param task_name: the name of the new task
* @return the new task handle
* */
void *cli_command_task_create(
cli_console *console,
uint32_t stack_size,
uint32_t priority,
void *task_entry,
void *task_args,
const char *task_name)
{
int32_t ret;
if (!cli_console_check_invalid(console))
{
return NULL;
}
cli_console_init(console);
pthread_attr_t attr;
struct sched_param sched;
pthread_t tid;
sched.sched_priority = priority;
pthread_attr_init(&attr);
pthread_attr_setschedparam(&attr, &sched);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_attr_setstacksize(&attr, stack_size);
ret = pthread_create(&tid, &attr, task_entry, task_args);
if (ret != 0)
{
return NULL;
}
console->alive = 1;
console->task = (void *)tid;
pthread_setname_np(tid, task_name);
return (void *)tid;
}
void cli_console_current_task_destory(void)
{
cli_console_task_destory(get_clitask_console());
}
/*
* check cli_console exit_flag
* @return 0/1, 0:the task should be alive; 1:the task should be deleted
* */
int cli_console_task_check_exit_flag(void)
{
int exit_flag = 0;
cli_console *console;
console = cli_task_get_console(cli_current_task());
if (console)
{
exit_flag = console->exit_flag;
}
else
{
exit_flag = 0;
}
return exit_flag;
}
void cli_console_set_exit_flag(cli_console *console)
{
if (console)
{
console->exit_flag = 1;
}
}
void check_console_task_exit(void)
{
cli_console *console = get_clitask_console();
if (console && console->exit_flag == 1 && console != get_default_console())
{
pthread_exit(NULL);
}
}
void task_inited_hook(void *thread)
{
cli_task_set_console(thread, cli_task_get_console(cli_current_task()));
}
void task_delete_hook(void *thread)
{
cli_task_set_console(thread, NULL);
}
#ifdef CONFIG_RTTKERNEL
static rt_err_t console_device_init(struct rt_device *dev)
{
return 0;
}
static rt_err_t console_device_open(struct rt_device *dev, rt_uint16_t oflag)
{
return 0;
}
static rt_err_t console_device_close(struct rt_device *dev)
{
return 0;
}
static rt_size_t console_device_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size)
{
return cli_console_read(get_current_console(), buffer, size);
}
static rt_size_t console_device_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
return cli_console_write(get_current_console(), buffer, size);
}
static rt_err_t console_device_control(struct rt_device *dev, int cmd, void *args)
{
return 0;
}
#if defined(RT_USING_POSIX)
#include <dfs_file.h>
#include <rtdevice.h>
#include <dfs_poll.h>
#include <string.h>
#include <inttypes.h>
static int console_device_fops_open(struct dfs_fd *fd)
{
return console_device_open((rt_device_t)fd->data, 0);
}
static int console_device_fops_close(struct dfs_fd *fd)
{
return console_device_close((rt_device_t)fd->data);
}
static int console_device_fops_read(struct dfs_fd *fd, void *buf, size_t count)
{
return console_device_read((rt_device_t)fd->data, fd->pos, buf, count);
}
static int console_device_fops_write(struct dfs_fd *fd, const void *buf, size_t count)
{
return console_device_write((rt_device_t)fd->data, fd->pos, buf, count);
}
static int console_device_fops_flush(struct dfs_fd *fd)
{
return 0;
}
static int console_device_fops_lseek(struct dfs_fd *fd, off_t offset)
{
return 0;
}
static int console_device_fops_getdents(struct dfs_fd *fd, struct dirent *dirp, uint32_t count)
{
return 0;
}
static struct dfs_file_ops uart_device_fops =
{
.open = console_device_fops_open,
.close = console_device_fops_close,
.flush = console_device_fops_flush,
.ioctl = NULL,
.lseek = console_device_fops_lseek,
.read = console_device_fops_read,
.write = console_device_fops_write,
.getdents = console_device_fops_getdents,
.poll = NULL,
.mmap = NULL,
};
#endif
static void console_create_device(char *dev_name)
{
rt_err_t ret;
static struct rt_device dev;
dev.init = console_device_init;
dev.open = console_device_open;
dev.close = console_device_close;
dev.read = console_device_read;
dev.write = console_device_write;
dev.control = console_device_control;
ret = rt_device_register(&dev, dev_name, RT_DEVICE_FLAG_RDWR);
if (ret)
{
hal_log_err("fatal error, ret %d, register device to rtsystem failure.\n", ret);
return;
}
#if defined(RT_USING_POSIX)
dev.fops = &uart_device_fops;
#endif
rt_console_set_device(dev_name);
}
#endif
int multiple_console_init(void)
{
cli_console_lock_init(&console_lock);
cli_console_init(&cli_null_console);
cli_console_init(default_console);
#ifdef CONFIG_RTTKERNEL
console_create_device("console");
#endif
return 0;
}