mirror of
https://gitee.com/moluo-tech/CodeBrick.git
synced 2025-01-16 04:32:51 +08:00
319 lines
8.6 KiB
C
319 lines
8.6 KiB
C
/******************************************************************************
|
||
* @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'");
|