Giter Club home page Giter Club logo

letter-shell's People

Contributors

cctv180 avatar charlesjin6 avatar mrxsean avatar nevermindzzt avatar redoccheng avatar xukaihub avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

letter-shell's Issues

多线程打印log出现交叉打印的情况

1、使用的尾行模式
2、由于shell留出的接口是写1个字节,在这里添加互斥锁只能减少出现的概率,

不知道你们有没有遇到这个问题,怎么解决的

获取当前shell的问题

作者在3.0的版本中提供了一个Shell* shellGetCurrent(void)的函数用户获得当前活动的shell,在多进程的情况下,有可能激活的函数有多个,这样的话,此函数的返回值有可能存在错误

ps:
本来一直都没有用到多shell的情况,但是本次改版后shellExtParsePara()这个函数需要提供被调用的shell的信息后,才关注到这个问题.
这个地方其实有点蛋疼.之前我都是用main函数的方式调用,参数解析部分使用shellExtParsePara()来处理,但是这次改版后,需要提供被哪个shell调用,这个地方有点蛋疼了,按理说被调用的函数,是不可能知道被哪个shell来调用了,所以这里只能间接的使用shellGetCurrent()来解决.但执行看代码后发现,此处还是有一点点风险的,虽说是概率不大,但是用在产品上,是绝对会碰到的!

请问Linux环境下GCC编译器,支持尾行模式吗?

Log uartLog;

void shellLogWrite(char *buffer, short len)
{
    if (uartLog.shell)
    {
        shellWriteEndLine(uartLog.shell, buffer, len);
    }
}

static void *thread1(void *);
static void *thread2(void *);

int main(int argc, char **argv)
{
    printf("enter main\n");
    pthread_t tid1, tid2;
    int rc1 = 0, rc2 = 0;
    rc2 = pthread_create(&tid2, NULL, thread2, NULL);
    if (rc2 != 0)
        printf("%s: %d\n", __func__, strerror(rc2));

    rc1 = pthread_create(&tid1, NULL, thread1, &tid2);
    if (rc1 != 0)
        printf("%s: %d\n", __func__, strerror(rc1));

    while (1);
}

void *thread1(void *arg)
{
    uartLog.write = shellLogWrite;
    uartLog.active = 1;
    uartLog.level = LOG_DEBUG;
    userShellInit();
    logRegister(&uartLog, &shell);
    shellTask(&shell);
}

void *thread2(void *arg)
{
    while(1)
    {
        logInfo("AlarmClockUpdate");
        sleep(1);
    }
}

SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC) | SHELL_CMD_PARAM_NUM(1),
                 exit, exit, exit);
SHELL_EXPORT_KEY_AGENCY(SHELL_CMD_PERMISSION(0),
                        0x03000000, exit, exit, 0);

main函数形式和普通C函数形式合并的思路

建议普通C函数形式main函数形式和普通C函数形式合并,大体思路如下:
1.参照导出变量的方式在在导出的结构体上增加传参模式的参数选项
2.参照变量的结构体封装方式,让用户在导出命令时直接就选择好函数形式即可,比如main函数的用SHELL_EXPORT_CMD(XXX),C函数的用SHELL_EXPORT_CMD_EX(XXX)

关于--keep shellCommand的问题

大神,您好,请教一个问题:
在这个shell中建议用keil编译的时候加入--keep shellCommand的选项,我在keil5.26上测试,没有加这个选项,但依然能正常编译(代码优化从0~3都测试过),但给同事使用的时候就必须加上这个选项,请问在什么情况下会出现数据被优化掉?
另外在网上看到一篇文章(https://blog.csdn.net/sinat_33611142/article/details/52761220)说,将__arrtibute__((unused, secition("arm_cmd")))改为__arrtibute__((used, secition("arm_cmd"))),可以避免这个声明,不知道是否有效。

关于定义在shell.c文件外的命令不识别的问题

Hi NevermindZZT,
我使用的是1.8的版本,为了使文件结构看起来更舒服,我把新增加的命令从shell.c文件移到了单独的一个.c文件,但发现使用help命令无法识别这些命令,直接执行也提示找不到命令。
由于我没能理解SHELL_EXPORT_CMD命令是怎么运作的,不知道如何修改,还请帮忙指导,多谢!

无法显示欢迎页,Tab出现乱码

你好,我是stm32爱好者
使用芯片:STM32F103C8T6
编写环境:win10,keil5,已添加防止优化代码
烧录方式:FlyMcu串口
通讯:USART1,波特率无误,PC端测试能接收未移植前的串口数据
问题描述:使用串口助手(多款),单片机复位后无法显示欢迎界面,只显示“_ 0”等无意义数据,且按任何键都有出现乱码的可以能,特别是Tab键。
1.下图是连续按Tab的结果图示
9021B7B3-D1EF-484B-8B02-691FD1

2.连续复位的结果
03159E2F-34B5-490D-AD81-EE7DA1

希望可以帮助我解决这个问题,因为这个工具我很需要,如果能用起来将会对我以后写程序有莫大帮助,感谢!

问题已经自行解决,原因是写入串口函数用错了!打扰了~

密码的问题

密码的使用上感觉有几个问题:
1.输入密码的时候是明文显示的,是否可以改成显示*(即在未正确输入密码前,回显全部都是*即可)
2.密码不是应该作为一个独立的变量加入到SHELL_TypeDef中?要不然所有用户都是同一个密码,体现不出支持多shell的意义(可以把宏密码设定为默认密码,如果初始化前为提前配置密码则按默认密码处理)
3.既然设定了密码,跟着来的就是权限问题了,是否考虑导出密码时就设定命令的权限,然后输入不同的密码可以获得不同的权限,来使用不同的命令?(用户名是否添加感觉不是刚性需求,能区分权限就已经能非常好的满足工程化的需求了)

移植完成后,只能显示输入的数据,无法进入函数

移植到STM32,使用keil编译程序。接收和发送没有问题,也初始化函数了,在主循环中调用shellTask(&shell); 配置头文件如下,其他未修改,按照freertos的demo文件来的,实际是裸机运行
#define SHELL_TASK_WHILE 0 #define SHELL_USING_CMD_EXPORT 1
例程时使用的readme.md的普通C函数形式,输入letter:/$ func 666 'A' "hello world",屏幕显示letter:/$ func 666 'A' "hello world"。
请问这是哪里没有配置正确?

自动参数转化的问题

2.0.0版本中,提供了自动参数转化的功能,但启用后,有几个问题:
1、启用后,被调用的函数,无法再获得argc这个参数,也就不知道命令中输入的参数数量是多少,参数输入少了,判断不出来。
2、隐含的最大参数不能超过8个,也在一定程度上隐含的参数的输入顺序。

建议:
1、2.0.0中的自动参数转换,和之前的参数转换能同时提供给用户使用
2、shellExtParsePara()这个函数开放给被调用函数使用

变量相关操作

变量相关的操作,提几个建议:
1.能否显示变量的地址?好像没找到显示变量地址的功能
2.变量是否能增加一个写操作的属性,比如(0-只读,1-可写,其他视为非内存变量,需提供对应写操作函数进行修改),主要是目前没有相关的操作,有些flash中的变量调用修改的操作,会直接跑飞

SHELL_EXPORT_CMD宏定义错误

SHELL_EXPORT_CMD的宏定义中漏了一个逗号,导致编译错误

#else /** SHELL_LONG_HELP == 1 */
#define     SHELL_EXPORT_CMD(cmd, func, desc)                               \
            const char shellCmd##cmd[] = #cmd;                              \
            const char shellDesc##cmd[] = #desc;                            \
            const SHELL_CommandTypeDef                                      \
            shellCommand##cmd SECTION("shellCommand") =                     \
            {                                                               \
                shellCmd##cmd    (<----此处漏了逗号)                                           \
                (int (*)())func,                                            \
                shellDesc##cmd                                              \
            }

建议添加CTRL+C,CTRL+L两个默认快捷键

/**

  • @brief shell 快捷键CTRL+L清空控制台(shell调用)
    */
    void shellKeyClear(Shell *shell)
    {
    shellWriteString(shell, shellText[SHELL_TEXT_CLEAR_CONSOLE]);
    shellWriteCommandLine(shell);
    }
    SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
    0x0C000000, shellKeyClear, Ctrl+L);

。。。

看了README.md 不是很理解,请问如何添加命令实现功能?

比如我要实现串口发送一个数据 ,
实现功能函数已写好,命令使用 "send".
void usart_send(void){
}

我应该如何操作?

我使用main函数形式,但是编译报错:section attribute cannot be specified for local variables

func(int argc, char *agrv[])
{
printf("%dparameter(s)\r\n", argc);
for (char i = 1; i < argc; i++)
{
printf("%s\r\n", argv[i]);
}
}
SHELL_EXPORT_CMD(func, func, test)

V2.0.1新增功能请教

在跟进大神的V2.0.1,有些问题和建议:
1、新增的SHELL_EXPORT_CMD_EX(cmd, func, desc, help)导出方式,就是最后增加了一个长描述,这个长描述默认可以被help命令解析并显示出来?
2、SHELL_GET_TICK()这个宏定义需要用户自己额外实现吧?建议shellRead及shellWrite那样,在结构体中用函数指针来实现,这样用户在shell实例化的过程统一处理比较好。

建议:代码数据类型关键字使用

建议代码中不要出现具体的数据类型如char、int、short等等,因为这些具体的类型在不同的编译环境中的长度是不同的,尤其是char,有的编译器默认是无符号的、有的默认是有符号的,这会给移植带来问题。

数据类型一律统一定义、见其名知其意,如可定义:
#define u8 unsigned char
#define s8 signed char
... ...
代码中只用s8、或者u8,这样在移植时,只需要根据不同编译环境重新定义u8、s8即可,否则还要关心数据长度、char是否有符号等问题。

上下左右和删除键卡死

移植完成后,Tab键和其它按键都没有问题,但是一旦按下上下左右键之后(不管什么时候),Shell就无响应了,按什么就回什么。调试的时候发现上下左右获取不了键值。我是用的Xshell,查看了键值,是和程序预设值一样的。

关于SHELL_TypeDef的status中的位域定义

平台:TMS320C6748
编译器:TI C6000 v7.4.4
struct
{
char inputMode : 2; /< 输入模式 */
char tabFlag : 1; /
< tab标志 */
char authFlag : 1; /< 密码标志 */
} status; /
< shell状态 */
对于tagFlag和authFlag编译器会提示警告“#109-D signed bit field of length 1”,也就是定义了一个1bit的有符号数据,也就是说只有一个符号位。
而对于inputMode,相当于一个2bit有符号数,在完成shell->status.inputMode = SHELL_ANSI_CSI;之后,(unsigned char)(shell->status.inputMode)的值为-2,shellAnsi函数永远无法正确执行了,shell挂死。

测试场景,按上下键可以触发。

修改方式:
struct
{
unsigned char inputMode : 2; /< 输入模式 */
unsigned char tabFlag : 1; /
< tab标志 */
unsigned char authFlag : 1; /**< 密码标志 */
} status;

@NevermindZZT

hexdump 打印的部分处理异常,导致重复打印到buff,并且容易超出长度,如下内容是修改后的

void logHexDump(Log *log, void *base, unsigned int length)
{
unsigned char *address;
unsigned int len = length;
unsigned int printLen = 0;

if (length == 0)
{
    return;
}

logWrite(log, LOG_NONE, "memory of 0x%08x, size: %d:\r\n", (unsigned int)base, length);

address = (unsigned char *)((unsigned int)base & (~0x0000000F));
length += (unsigned int)base - (unsigned int)address;
length = (length + 15) & (~0x0000000F);

logWrite(log, LOG_NONE, memPrintHead"\r\n");

while (length)
{
    printLen += sprintf(logBuffer + printLen, memPrintAddr, (unsigned int)address);
    for (int i = 0; i < 16; i++)
    {
        if ((unsigned int)(address + i) < (unsigned int)base
            || (unsigned int)(address + i) >= (unsigned int)base + len)
        {
            logBuffer[printLen ++] = ' ';
            logBuffer[printLen ++] = ' ';
            logBuffer[printLen ++] = ' ';
        }
        else
        {
            printLen += sprintf(logBuffer + printLen, "%02x ", *(address + i));
        }
    }
    logBuffer[printLen ++] = '|';
    logBuffer[printLen ++] = ' ';
    for (int i = 0; i < 16; i++)
    {
        if ((unsigned int)(address + i) < (unsigned int)base
            || (unsigned int)(address + i) >= (unsigned int)base + len)
        {
            logBuffer[printLen ++] = ' ';
        }
        else
        {
            if (*(address + i) >= 32 && *(address + i) <= 126)
            {
                printLen += sprintf(logBuffer + printLen, "%c", *(address + i));
            }
            else
            {
                logBuffer[printLen ++] = '.';
            }
        }
    }
    logBuffer[printLen ++] = '|';
    logBuffer[printLen ++] = '\r';
    logBuffer[printLen ++] = '\n';
    logWriteBuffer(log, LOG_NONE, logBuffer, printLen);
    address += 16;
    length -= 16;
    **printLen = 0;**
}

}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC),
hexdump, logHexDump, hex dump\r\n hexdump [log] [base] [len]);

命令函数参数问题

命令函数的参数和终端里面输入的参数的对应关系是什么?比如定义如下函数:
void shellEepromRead(u16 addr)
{
printf("%d\r\n", addr); //如:串口终端输入65580(超出u16范围),这里依然能够正常打印,
//但是定义的是u16,范围是0 ~ 65535才对。
}
其中,u16即无符号16bit的整型,但是实际使用时发现,参数addr的范围可以超过65535,即可以超过u16类型可表示数的范围。

使用的开发环境是MDK5。

对于2.x版本兼容的问题

首先非常感谢作者提供的这个开源的shell,一直跟踪使用了1年多,对我的帮助非常大,调试和产品维护方便了许多,后续会一直跟进这作者的升级,谢谢啦 O(∩_∩)O哈哈~

作者这次3.0版本是做了比较大的改动了,对老版本完全不兼容了,移植方面到还好了,整体改动不大,主要是命令导出方式也做了调整,这就导致项目中很多地方要做修改,建议:

1.将新版本的命令导出改成:

SHELL_EXPORT_CMD_EX

2.新增兼容型宏:

    //老版本导出命令
    #define SHELL_EXPORT_CMD(cmd, func, desc)   \
            SHELL_EXPORT_CMD_EX(                \
            SHELL_CMD_PERMISSION(0)|            \
            SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|\
            SHELL_CMD_DISABLE_RETURN,           \
            cmd,                                \
            func,                               \
            desc                                \
            )  

使用其他串口助手无法正确显示

image

上图是配置触发,两种方式都试过,依然出现以下情况,使用了示例函数
image

但是使用Xshell工具就没有这个情况,是否因为使用的串口助手问题?那该如何兼容其他串口助手呢?不要求特殊键值,只需发送和接收

多用户登录的问题

设置多用户后,登录是必须先输入默认用户的命令后,才能进一步切换成其他用户,这里面有几个问题:
1.需要知道默认用户的密码才能切换用户,这个地方设计的时候不太合理
2.默认用户的权限默认是最高的,如果用户知道他的密码后,就没有必要做用户切换了
建议:
还是参照linux中的设定,登录时要同时输入用户名和密码

setVar 指令解析错误

setVar 这个指令必须配合SHELL_AUTO_PRASE来使用才正常,否则就无法解析,建议用宏定义区分开两种不同传参方式

另外shell内部集成的 Help 需要SHELL_AUTO_PRASE = 0 ,和 setVar 刚好相反,这样也就意味着无论SHELL_AUTO_PRASE 如何设置,都有会部分功能缺失

readme疑问

readme的说明第一条
对于中断方式使用shell,不用定义shell->read,但需要在中断中调用shellHandler

但是在shellTask()函数中就有这样一段代码

if` (shell->read == NULL)
    {
        shellDisplay(shell, "error: shell.read must be defined\r\n");
        while (1) ;
    }

不知道这里怎么理解

新功能建议

大神,提几个新功能建议,希望能集成到当前shell中(如果不集成也请指导一下如何实现):
1、增加登录密码,当前版本没有登录密码,只能自己测试用,产品投放现场后就不敢用了,希望能增加登录密码的设置。
2、增加变量查询的功能,便于在调试解决查看一些地址的异常情况。这个不知道如何实现比较好,最好能查结构体程序的值。

如何定义一个 SHELL_CommandTypeDef

我的定义如下:
void func(int i, char ch, char *str)
{
printf("input int: %d, char: %c, string: %s\r\n", i, ch, str);
}

SHELL_CommandTypeDef test = {
"test",
func,
"test com",
"test help"
};
SHELL_EXPORT_CMD(func, func, test);
但是报错:Error section attribute cannot be specified for local variables

tab键的功能调整建议

2.0.0中tab的功能做了调整,不是直接补齐命令,而是先显示可匹配的命令清单,在进行补全,是否能做一下小的调整:如果可匹配的命令只有一个的时候,直接补全命令,如果有多个可匹配命令时才列出命令清单

移植过程中,keil报跟结构体相关的错误

作者您好,看了您的shell十分强大,也想移植一份自己用。但是因为自己不是很熟悉软件,keil中有一报错与结构体有关,四处搜寻无果后无奈寻求帮助。

image
从报错信息来看,似乎是定义和声明的时候在参数里出现了数据格式,参数数量或形参名字的不一致导致的
image
但是无奈不知道如何修改此问题,希望高人能指点一下,谢谢了!

关于在shell中传递AT指令参数时不合理的参数解析

使用shell做AT调试时发现shell中使用,和"字符会被认定为参数分隔符,不知道作者在设计的时候这个是基于什么考虑,但是个人认为貌似不太合理,比如传递一个
AT AT+CIPOPEN=0,"114.114.114.114",1883,4001
此类参数时,shell自动分解成多个参数,如

AT 
AT+CIPOPEN=0
114.114.114.114
1883
4001

这就曲解了原本参数传递的意义,一次建议使用空格做分割符而不是,和“,基于原代码shellEnter函数我做了如下修改

for (unsigned short i = 0; i < shell->length; i++)
  {
      if ((quotes != 0 ||
          (*(shell->buffer + i) != ' ' &&
          *(shell->buffer + i) != '\t')) &&
       //   *(shell->buffer + i) != ',' &&
          *(shell->buffer + i) != 0)
      {
//            if (*(shell->buffer + i) == '\"')
//            {
//                quotes = quotes ? 0 : 1;
//            #if SHELL_AUTO_PRASE == 0
//                *(shell->buffer + i) = 0;
//                continue;
//            #endif
//            }
          if (record == 1)
          {
              shell->param[paramCount++] = shell->buffer + i;
              record = 0;
          }
          if (*(shell->buffer + i) == '\\' &&
              *(shell->buffer + i) != 0)
          {
              i++;
          }
      }

长帮助的处理建议

建议将长帮助和描述合并成一个参数,思路如下:
1.常规显示时,描述超出一定长度后,后面部分截断,显示为"..."
2.如需显示完整的的描述,使用help cmd 的指令模式

合并后整体程序处理会简单不少,而且感觉这样使用起来会更符合实际使用的习惯

配置有密码的情况下,初始化,shellSetUser函数shell->parser.param[1]还未赋值,导致崩溃。

static void shellSetUser(Shell *shell, const ShellCommand *user)
{
shell->info.user = user;
shell->status.isChecked = 1;
((user->data.user.password && strlen(user->data.user.password) != 0)
&& (shell->parser.paramCount == 1
|| strcmp(user->data.user.password, shell->parser.param[1]) != 0))
? 0 : 1;

#if SHELL_CLS_WHEN_LOGIN == 1
shellWriteString(shell, shellText[SHELL_TEXT_CLEAR_CONSOLE]);
#endif
#if SHELL_SHOW_INFO == 1
if (shell->status.isChecked)
{
shellWriteString(shell, shellText[SHELL_TEXT_INFO]);
}
#endif
}

配置有密码的情况下,初始化,该函数shell->parser.param[1]还未赋值,导致崩溃。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.