319 lines
8.6 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/******************************************************************************
* @brief <20><><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD>
*
* Copyright (c) 2015-2020, <master_roger@sina.com>
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2015-06-09 Morro <20><><EFBFBD><EFBFBD>
*
* 2017-07-04 Morro <20>Ż<EFBFBD><C5BB>ֶηָ<D6B8><EEB4A6>
*
* 2020-07-05 Morro ʹ<><CAB9>cli_obj_t<5F><74><EFBFBD><EFBFBD>, ֧<>ֶ<EFBFBD><D6B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD>
* 2020-08-29 Morro ֧<><D6A7>ATָ<54><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Կ<EFBFBD><D4BF><EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֮<EFBFBD><D6AE><EFBFBD>ղ<EFBFBD><D5B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD><DDB5><EFBFBD><EFBFBD><EFBFBD>
* 2020-02-16 Morro <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
******************************************************************************/
#include "cli.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdbool.h>
static const cmd_item_t cmd_tbl_start SECTION("cli.cmd.0") = {0};
static const cmd_item_t cmd_tbl_end SECTION("cli.cmd.4") = {0};
/**
* @brief <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param[in] keyword - <20><><EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD><D8BC><EFBFBD>
* @return <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
static const cmd_item_t *find_cmd(const char *keyword, int n)
{
const cmd_item_t *it;
for (it = &cmd_tbl_start + 1; it < &cmd_tbl_end; it++) {
if (!strncasecmp(keyword, it->name, n))
return it;
}
return NULL;
}
/*******************************************************************************
* @brief <20>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD>ָ<EFBFBD> - <20><>Դ<EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>separatorָ<72><D6B8><EFBFBD>ķָ<C4B7><D6B8><EFBFBD>
* (<28><>',')<29><><EFBFBD><EFBFBD><E6BBBB><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>'\0'<27>γ<EFBFBD><CEB3>Ӵ<EFBFBD><D3B4><EFBFBD>ͬʱ<CDAC><CAB1>list
* ָ<><D6B8><EFBFBD>б<EFBFBD><D0B1>е<EFBFBD>ÿһ<C3BF><D2BB>ָ<EFBFBD><D6B8><EFBFBD>ֱ<EFBFBD>ָ<EFBFBD><D6B8>һ<EFBFBD><D2BB><EFBFBD>Ӵ<EFBFBD>
* @example
* input=> s = "abc,123,456,,fb$"
* separator = ",$"
*
* output=>s = abc'\0' 123'\0' 456'\0' '\0' fb'\0''\0'
* list[0] = "abc"
* list[1] = "123"
* list[2] = "456"
* list[3] = ""
* list[4] = "fb"
* list[5] = ""
*
* @param[in] str - Դ<>ַ<EFBFBD><D6B7><EFBFBD>
* @param[in] separator - <20>ָ<EFBFBD><D6B8>ַ<EFBFBD><D6B7><EFBFBD>
* @param[in] list - <20>ַ<EFBFBD><D6B7><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD>б<EFBFBD>
* @param[in] len - <20>б<EFBFBD><D0B1><EFBFBD><EFBFBD><EFBFBD>
* @return listָ<74><D6B8><EFBFBD>б<EFBFBD><D0B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD>򷵻<EFBFBD>6
******************************************************************************/
static size_t strsplit(char *s, const char *separator, char *list[], size_t len)
{
size_t count = 0;
if (s == NULL || list == NULL || len == 0)
return 0;
list[count++] = s;
while(*s && count < len) {
if (strchr(separator, *s) != NULL) {
*s = '\0';
list[count++] = s + 1; /*ָ<><D6B8><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>Ӵ<EFBFBD>*/
}
s++;
}
return count;
}
/**
*@brief <20><>ӡһ<D3A1><D2BB><EFBFBD><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڿ<EFBFBD><DABF><EFBFBD>̨
*@retval
*/
static void cli_print(cli_obj_t *obj, const char *format, ...)
{
va_list args;
int len;
char buf[CLI_MAX_CMD_LEN + CLI_MAX_CMD_LEN / 2];
va_start (args, format);
len = vsnprintf (buf, sizeof(buf), format, args);
va_end (args);
obj->write(buf, len);
}
/**
* @brief <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param[in] line - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return none
**/
static void process_line(cli_obj_t *obj)
{
char *argv[CLI_MAX_ARGS];
int argc, ret, isat = 0;
const cmd_item_t *it;
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (obj->guard && !obj->guard(obj->recvbuf))
return;
if (obj->echo) { //<2F><><EFBFBD><EFBFBD>
obj->print(obj,"%s\r\n",obj->recvbuf);
}
argc = strsplit(obj->recvbuf, ",",argv, CLI_MAX_ARGS);
const char *start, *end;
if (argv[0] == NULL)
return;
if (strcasecmp("AT", argv[0]) == 0) {
obj->print(obj, "OK\r\n");
return;
}
#if CLI_AT_ENABLE != 0
isat = strncasecmp(argv[0], "AT+", 3) == 0;
#endif
start= !isat ? argv[0] : argv[0] + 3;
if ((end = strchr(start, '=')) != NULL) {
obj->type = CLI_CMD_TYPE_SET;
} else if ((end = strchr(start, '?')) != NULL) {
obj->type = CLI_CMD_TYPE_QUERY;
} else {
obj->type = CLI_CMD_TYPE_EXEC;
end = start + strlen(argv[0]);
}
if (start == end)
return;
if ((it = find_cmd(start, end - start)) == NULL) {
obj->print(obj, "%s\r\n", isat ? "ERROR" : "");
return;
}
ret = it->handler(obj, argc, argv);
if (isat) {
obj->print(obj, "%s\r\n" ,ret ? "OK":"ERROR");
}
}
/**
* @brief <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>ֵ
*/
static int get_val(struct cli_obj *self)
{
char *p;
p = strchr(self->recvbuf, '=');
if ( p == NULL)
return 0;
return atoi(p + 1);
}
/**
* @brief cli <20><>ʼ<EFBFBD><CABC>
* @param[in] p - cli<6C><69><EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>
* @return none
*/
void cli_init(cli_obj_t *obj, const cli_port_t *p)
{
obj->read = p->read;
obj->write = p->write;
obj->print = cli_print;
obj->enable = true;
obj->get_val = get_val;
obj->guard = p->cmd_guard;
}
/**
* @brief <20><><EFBFBD><EFBFBD>cli<6C><69><EFBFBD><EFBFBD>ģʽ(cli<6C><69>ʱ<EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
* @param[in] none
* @return none
**/
void cli_enable(cli_obj_t *obj)
{
char a;
obj->enable = true;
obj->recvcnt = 0;
while (obj->read(&a, 1) > 0) {}
}
/**
* @brief <20>˳<EFBFBD>cli<6C><69><EFBFBD><EFBFBD>ģʽ(cli<6C><69>ʱ<EFBFBD><CAB1><EFBFBD>ٴ<EFBFBD><D9B4><EFBFBD><EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
* @param[in] none
* @return none
**/
void cli_disable (cli_obj_t *obj)
{
obj->enable = false;
}
/**
* @brief <20><><EFBFBD>Կ<EFBFBD><D4BF><EFBFBD>
* @param[in] echo - <20><><EFBFBD>Կ<EFBFBD><D4BF>ؿ<EFBFBD><D8BF><EFBFBD>(0/1)
* @return none
**/
void cli_echo_ctrl (cli_obj_t *obj, int echo)
{
obj->echo = echo;
}
/**
* @brief ִ<><D6B4>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28><><EFBFBD><EFBFBD>cli<6C>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD>ִ<EFBFBD><D6B4>)
* @param[in] none
* @return none
**/
void cli_exec_cmd(cli_obj_t *obj, const char *cmd)
{
int len = strlen(cmd);
if (len >= CLI_MAX_CMD_LEN - 1)
return;
strcpy(obj->recvbuf, cmd);
process_line(obj);
}
/**
* @brief <20><><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param[in] none
* @return none
**/
void cli_process(cli_obj_t *obj)
{
char buf[32];
int i, readcnt;
if (!obj->read || !obj->enable)
return;
readcnt = obj->read(buf, sizeof(buf));
if (readcnt) {
for (i = 0; i < readcnt; i++) {
if (buf[i] == '\r' || buf[i] == '\n' || buf[i] == '\0') {
obj->recvbuf[obj->recvcnt] = '\0';
if (obj->recvcnt > 1)
process_line(obj);
obj->recvcnt = 0;
} else {
obj->recvbuf[obj->recvcnt++] = buf[i];
if (obj->recvcnt >= CLI_MAX_CMD_LEN) /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֮<EFBFBD><D6AE>ǿ<EFBFBD><C7BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
obj->recvcnt = 0;
}
}
}
}
#if 1
/*******************************************************************************
* @brief <20><><EFBFBD><EFBFBD><EFBFBD>Ƚ<EFBFBD><C8BD><EFBFBD>
* @param[in] none
* @return <20>ο<EFBFBD>strcmp
*******************************************************************************/
static int cmd_item_comparer(const void *item1,const void *item2)
{
cmd_item_t *it1 = *((cmd_item_t **)item1);
cmd_item_t *it2 = *((cmd_item_t **)item2);
return strcmp(it1->name, it2->name);
}
#endif
/*
* @brief <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
static int do_help (struct cli_obj *s, int argc, char *argv[])
{
int i,j, count;
const cmd_item_t *item_start = &cmd_tbl_start + 1;
const cmd_item_t *item_end = &cmd_tbl_end;
const cmd_item_t *cmdtbl[CLI_MAX_CMDS];
if (argc == 2) {
if ((item_start = find_cmd(argv[1], strlen(argv[1]))) != NULL)
{
s->print(s, item_start->brief); /*<2A><><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9><EFBFBD><EFBFBD>Ϣ----*/
s->print(s, "\r\n");
}
return 0;
}
for (i = 0; i < item_end - item_start && i < CLI_MAX_ARGS; i++)
cmdtbl[i] = &item_start[i];
count = i;
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---------------------------------------------------------*/
qsort(cmdtbl, i, sizeof(cmd_item_t*), cmd_item_comparer);
s->print(s, "\r\n");
for (i = 0; i < count; i++) {
s->print(s, cmdtbl[i]->name); /*<2A><>ӡ<EFBFBD><D3A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>------*/
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
j = strlen(cmdtbl[i]->name);
if (j < 10)
j = 10 - j;
while (j--)
s->print(s, " ");
s->print(s, "- ");
s->print(s, cmdtbl[i]->brief); /*<2A><><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9><EFBFBD><EFBFBD>Ϣ----*/
s->print(s, "\r\n");
}
return 1;
}
/*ע<><D7A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---------------------------------------------------------------*/
cmd_register("help", do_help, "list all command.");
cmd_register("?", do_help, "alias for 'help'");