nevermindzzt / letter-shell Goto Github PK
View Code? Open in Web Editor NEWletter shell
License: MIT License
letter shell
License: MIT License
1、使用的尾行模式
2、由于shell留出的接口是写1个字节,在这里添加互斥锁只能减少出现的概率,
不知道你们有没有遇到这个问题,怎么解决的
作者在3.0的版本中提供了一个Shell* shellGetCurrent(void)的函数用户获得当前活动的shell,在多进程的情况下,有可能激活的函数有多个,这样的话,此函数的返回值有可能存在错误
ps:
本来一直都没有用到多shell的情况,但是本次改版后shellExtParsePara()这个函数需要提供被调用的shell的信息后,才关注到这个问题.
这个地方其实有点蛋疼.之前我都是用main函数的方式调用,参数解析部分使用shellExtParsePara()来处理,但是这次改版后,需要提供被哪个shell调用,这个地方有点蛋疼了,按理说被调用的函数,是不可能知道被哪个shell来调用了,所以这里只能间接的使用shellGetCurrent()来解决.但执行看代码后发现,此处还是有一点点风险的,虽说是概率不大,但是用在产品上,是绝对会碰到的!
你好,我跟着博客Mculover666移植letter-shell,出现三个报错,都集中在shell.c
博客地址:http://www.mculover666.cn/posts/131757493/#toc-heading-14
IAR与GCC都出现一样的报错。
github上目前上传图片有问题,我在微云分享了报警的截图:https://share.weiyun.com/xfSNo8f7
谢谢!
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);
宏SHELL_AUTO_PRASE = 0情况下,设置参数命令在函数void shellSetVariable(char *var, int value);中无法正常解析出var和value值。当选择SHELL_AUTO_PRASE = 1情况下正常。
建议普通C函数形式main函数形式和普通C函数形式合并,大体思路如下:
1.参照导出变量的方式在在导出的结构体上增加传参模式的参数选项
2.参照变量的结构体封装方式,让用户在导出命令时直接就选择好函数形式即可,比如main函数的用SHELL_EXPORT_CMD(XXX),C函数的用SHELL_EXPORT_CMD_EX(XXX)
大神,您好,请教一个问题:
在这个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"))),可以避免这个声明,不知道是否有效。
Hi NevermindZZT,
我使用的是1.8的版本,为了使文件结构看起来更舒服,我把新增加的命令从shell.c文件移到了单独的一个.c文件,但发现使用help命令无法识别这些命令,直接执行也提示找不到命令。
由于我没能理解SHELL_EXPORT_CMD命令是怎么运作的,不知道如何修改,还请帮忙指导,多谢!
密码的使用上感觉有几个问题:
1.输入密码的时候是明文显示的,是否可以改成显示*(即在未正确输入密码前,回显全部都是*即可)
2.密码不是应该作为一个独立的变量加入到SHELL_TypeDef中?要不然所有用户都是同一个密码,体现不出支持多shell的意义(可以把宏密码设定为默认密码,如果初始化前为提前配置密码则按默认密码处理)
3.既然设定了密码,跟着来的就是权限问题了,是否考虑导出密码时就设定命令的权限,然后输入不同的密码可以获得不同的权限,来使用不同的命令?(用户名是否添加感觉不是刚性需求,能区分权限就已经能非常好的满足工程化的需求了)
大佬,是否考虑集成一下YMODEM等常用的传输协议,我已经移植了,另外还有2048小游戏也移植过来了,给您的邮箱发了邮件。
Letter shell 3.0 全新出发说明中在 变量声明 SHELL_CMD_VAR写错了吧?应该是 SHELL_EXPORT_VAR
移植到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的宏定义中漏了一个逗号,导致编译错误
#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 \
}
使用 SHELL_EXPORT_CMD 编译报error: attribute "section" does not apply to automatic variables。
其实本人对如何添加命令不是很理解,可否有详细例程说明一下。非常感谢,这是一个很棒的项目。
命令在什么地方实现?如何添加命令?
我是在博客MCUlover666看到移植letter-shell到STM32上的.
网址:http://www.mculover666.cn/posts/131757493/#toc-heading-14
/**
。。。
目前我用DMA发送一个字节很不稳定,想用DMA方式发送多个字符,以减少中断次数,不知道怎么处理?
shellWriteString()函数也没有字符长度参数。
比如我要实现串口发送一个数据 ,
实现功能函数已写好,命令使用 "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,有些问题和建议:
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是否有符号等问题。
你好作者:
最近移植了最新版本,发现在终端中键盘输入上下左右会出现 ABCD字母,无法上下翻使用历史命令,这令人很困惑,不知道那方面的原因。
移植完成后,Tab键和其它按键都没有问题,但是一旦按下上下左右键之后(不管什么时候),Shell就无响应了,按什么就回什么。调试的时候发现上下左右获取不了键值。我是用的Xshell,查看了键值,是和程序预设值一样的。
把老版本的clear移植上来后,发现执行后整个shell就不工作了
2.0.0版本中,参数识别部分函数,没有实现float类型的转换。
测试了两天,移植3.0.3 不成功,最后把__attribute__(section(x)),改成__attribute__((used,section(x))) 最终成功了,使用AC 6编译器的小伙伴一定要修改。
shell.h 中第71行
平台: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;
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]);
同时关闭SHELL_USING_VAR和SHELL_DISPLAY_RETURN后,产生编译告警
..\Src\shell.c(326): warning: #177-D: function "shellDisplayValue" was declared but never referenced
能否进一步增加二级制类参数的转换?
命令函数的参数和终端里面输入的参数的对应关系是什么?比如定义如下函数:
void shellEepromRead(u16 addr)
{
printf("%d\r\n", addr); //如:串口终端输入65580(超出u16范围),这里依然能够正常打印,
//但是定义的是u16,范围是0 ~ 65535才对。
}
其中,u16即无符号16bit的整型,但是实际使用时发现,参数addr的范围可以超过65535,即可以超过u16类型可表示数的范围。
使用的开发环境是MDK5。
首先非常感谢作者提供的这个开源的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 \
)
设置多用户后,登录是必须先输入默认用户的命令后,才能进一步切换成其他用户,这里面有几个问题:
1.需要知道默认用户的密码才能切换用户,这个地方设计的时候不太合理
2.默认用户的权限默认是最高的,如果用户知道他的密码后,就没有必要做用户切换了
建议:
还是参照linux中的设定,登录时要同时输入用户名和密码
这是一个很棒的工程,但是GCC编译会有些问题希望能有更好的支持。
STM32 gcc 编译后,输入命令会卡死,跳到HardFault_Handler中断.
MDK编译,正常。
setVar 这个指令必须配合SHELL_AUTO_PRASE来使用才正常,否则就无法解析,建议用宏定义区分开两种不同传参方式
另外shell内部集成的 Help 需要SHELL_AUTO_PRASE = 0 ,和 setVar 刚好相反,这样也就意味着无论SHELL_AUTO_PRASE 如何设置,都有会部分功能缺失
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、增加变量查询的功能,便于在调试解决查看一些地址的异常情况。这个不知道如何实现比较好,最好能查结构体程序的值。
我的定义如下:
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
RT-Thread 也有个 shell ,但有些地方好像没有 letter-shell 做的好,例如:多shell支持
如果有时间,可以做一个 RT-Thread 的软件包,兼容原生的 shell ,在 RT-Thread 平台上实现开箱即用。
未来可能也会吸引更多的使用 RT-Thread 平台的用户来用 letter-shell。
2.0.0中tab的功能做了调整,不是直接补齐命令,而是先显示可匹配的命令清单,在进行补全,是否能做一下小的调整:如果可匹配的命令只有一个的时候,直接补全命令,如果有多个可匹配命令时才列出命令清单
shellExtParsePara()中的value未使用
shellExtParseNumber()中的valueFloat未使用
使用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 的指令模式
合并后整体程序处理会简单不少,而且感觉这样使用起来会更符合实际使用的习惯
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]还未赋值,导致崩溃。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.