【问题标题】:Are there any good reference implementations available for command line implementations for embedded systems?嵌入式系统的命令行实现是否有任何好的参考实现?
【发布时间】:2009-12-16 13:02:10
【问题描述】:

我知道这不是什么新鲜事,而且已经做过好几次了。但我正在寻找一些参考实现(甚至只是参考设计)作为“最佳实践指南”。我们有一个实时嵌入式环境,其想法是能够使用“调试外壳”来调用一些命令。示例:“SomeDevice print reg xyz”将请求 SomeDevice 子系统打印名为 xyz 的寄存器的值。

【问题讨论】:

  • 您在寻找什么功能?解析几个词和调用函数一点都不难,但是如果你想引用等,就变得更加困难了。
  • 我不知道什么是“引用”。我主要寻找“解析关键字和调用函数”部分。但是,它需要是通用的和可扩展的。我们还希望有历史记录、帮助、制表符补全等。但其核心仍然应该是解析单词和调用函数。可能会有一个主模块解析前一个或两个关键字,然后将控制权传递给另一个模块进行其余的解析和命令完成等。没什么复杂的。但是我可以看看现有的实现吗?
  • 在我建议的实现中,历史和帮助只是简单地实现为函数(因为您可以调用具有全局范围的任何函数)。 shell 表达式求值器维护一个历史缓冲区和 h() 函数(括号对于简单的调用是可选的,因此在命令行中只有“h”),提供缓冲区的编号列表并提示选择。 vxWorks 还使用类似 vi 的光标控制来允许滚动历史缓冲区;我选择不这样做。
  • “引用等”!?那是什么?
  • 我假设“引用”是指能够引用命令行参数,例如带有空格的文件名、转义序列(例如 \n、\t、\r)和类似的“智能”解析命令行时的解释。

标签: shell command-line embedded


【解决方案1】:

我有一小组例程,基本上由 3 个函数和一个查找表组成:

  • 一个收集命令行的函数——它很简单;没有命令行历史或任何东西,只有退格或按转义键丢弃整个内容的能力。但如果我认为需要更高级的编辑功能,在这里添加它们也不会太难。
  • 一个解析一行文本 argc/argv 样式的函数(有关这方面的一些想法,请参阅 Parse string into argv/argc
  • 一个函数,它获取已解析命令行上的第一个 arg,并在命令和函数指针表中查找它以确定为该命令调用哪个函数,因此命令处理程序只需要匹配原型:

    int command_handler( int argc, char* argv[]);

然后使用适当的 argc/argv 参数调用该函数。

实际上,查找表还有指向每个命令的基本帮助文本的指针,如果该命令后跟“-?”或者 '/?'显示那段帮助文本。此外,如果“help”用于命令,则命令表将被转储(如果将参数传递给“help”命令,则可能只有一个子集)。

抱歉,我无法发布实际源代码 - 但它的实现非常简单直接,并且功能足以满足我在嵌入式系统开发方面的几乎所有命令行处理需求。

【讨论】:

  • 虽然这里没有一个答案是完美匹配的,但我意识到迈克尔的回答最接近。我同意任何人编写的 CLI 的早期版本可能看起来像这样。然而,在一段时间内,由于以下考虑(a)可扩展性(b)通用性(c)良好的编程和/或设计实践等,人们会期望一些改进必须悄悄出现。基本上,我正在寻找一些东西这随着年龄/经验等而有所改善,而不是一个非常基本的版本。任何输入/指针都会很有帮助。
  • 例如,对上述设计(对于大型系统)的一个非常直接的改进是有一个约定,即第一个 arg 应该始终是潜在非常大系统。然后,第一级逻辑将仅关注第一个 arg 并将整个命令传递给预期的子系统。然后每个子系统将负责查找自己的函数表指针等。
【解决方案2】:

您可能会对此反应感到愤怒,但多年前我们为使用 lex/yacc 的大型嵌入式电信系统做了类似的事情(现在我猜它会是 flex/bison,这确实是 20 年前的事了)。

定义你的语法,定义参数的范围等等......然后让 lex/yacc 生成代码。

与滚动一次自定义实现相比,有一点学习曲线,但随后您可以非常快速地扩展语法、添加新命令和参数、更改范围等。

【讨论】:

【解决方案3】:

您可以查看libcli。它模拟 Cisco 的 CLI,显然还包括一个 telnet 服务器。这可能超出了您的预期,但它仍然可以作为参考。

【讨论】:

  • 我打算推荐同样的东西。它的直接适用程度取决于您的嵌入式平台的复杂程度。
  • 谢谢。 libcli 很好,但使用套接字等,这对我们来说可能是一种矫枉过正。
【解决方案4】:

如果您的需求非常基本,那么接受简单击键的调试菜单(而不是命令外壳)是一种方法。

对于寄存器和 RAM,您可以有一个子菜单来按需进行内存转储。

同样,要启用或禁用个别功能,您可以通过主菜单或子菜单中的按键来控制它们。

实现这一点的一种方法是通过一个简单的状态机。每个屏幕都有一个相应的状态,等待击键,然后根据需要更改状态和/或更新屏幕。

【讨论】:

  • 这样做的问题是,如果你后来发现它过于严格(菜单永远没有成熟命令行的表现力),那么返回并重新 -编写所有内容以使用命令行代替。如果您认为您可能需要命令行的灵活性,那么最好第一次就做好。
  • @Dan:同意。这在很大程度上取决于您认为您的要求是什么。
【解决方案5】:

vxWorks 包含一个命令 shell,它嵌入符号表并实现 C 表达式求值器,以便您可以在运行时调用函数、求值表达式和访问全局符号。表达式求值器支持整数和字符串常量。

当我从事从 vxWorks 迁移到 embOS 的项目时,我实现了相同的功能。嵌入符号表需要一些技巧,因为它在链接之后才存在。我使用构建后步骤来解析 GNU nm 工具的输出,以创建符号表作为单独的加载模块。在早期版本中,我根本没有嵌入符号表,而是创建了一个主机外壳程序,该程序在符号表所在的开发主机上运行,​​并与目标上的调试存根通信,该存根可以执行任意函数调用地址和读/写任意内存。这种方法更适合内存受限的设备,但您必须注意您正在使用的符号表和目标上的代码是针对同一构建的。这也是我从 vxWorks 借来的一个想法,它支持具有相同功能的基于目标和主机的 shell。对于主机外壳,vxWorks 对代码进行校验和以确保符号表匹配;就我而言,这是一个手动(且容易出错)的过程,这就是我实现嵌入式符号表的原因。

虽然最初我只实现了内存读/写和函数调用功能,但后来我添加了一个基于here 描述的算法(但不是代码)的表达式评估器。然后,我以 if-else、while 和过程调用结构的形式添加了简单的脚本功能(使用非常简单的非 C 语法)。因此,如果您想要新功能或进行测试,您可以编写一个新函数,或者创建一个脚本(如果性能不是问题的话),因此这些函数更像是脚本语言的“内置”。

为了执行任意函数调用,我使用了一个函数指针 typedef,它带有任意大 (24) 个参数,然后使用符号表,找到函数地址,将其转换为函数指针类型,然后传递它是真正的参数,加上足够的虚拟参数来组成预期的数量,从而创建一个合适的(如果浪费的话)维护堆栈框架。

在其他系统上,我实现了一个 Forth 线程解释器,这是一种实现起来非常简单的语言,但可能语法不太友好。您同样可以嵌入现有的解决方案,例如 Lua 或 Ch。

【讨论】:

    【解决方案6】:

    对于一个小而轻的东西,你可以使用。它很容易上手(第四个内核很小) 看看 figForth、LINa 和 GnuForth。

    免责声明:我不使用 Forth,但 openboot 和 PCI 总线可以,而且我使用过它们并且它们工作得非常好。

    替代用户界面

    改为在您的嵌入式设备上部署网络服务器。甚至串行也可以与 SLIP 一起使用,并且 UI 可能相当复杂(甚至提供一个 JAR 并变得非常复杂。

    如果您真的需要 CLI,那么您可以指向一个链接并获得一个 telnet。

    【讨论】:

      【解决方案7】:

      另一种方法是使用非常简单的二进制协议来传输您需要的数据,然后在 PC 上制作用户界面,例如使用Python 或任何你最喜欢的开发工具。

      优点是它最大限度地减少了嵌入式设备中的代码,并将尽可能多的代码转移到 PC 端。这很好,因为:

      • 它占用的嵌入式代码空间更少——大部分代码都在 PC 上。
      • 在许多情况下,使用 PC 的更多工具和资源,在 PC 上开发给定的功能会更容易。
      • 它为您提供了更多的界面选项。如果需要,您可以只使用命令行界面。或者,您可以选择 GUI,包括图表、数据记录,以及您可能想要的任何花哨的东西。
      • 它为您提供了灵活性。嵌入式代码比 PC 代码更难升级。您可以随时更改和改进基于 PC 的工具,而无需对嵌入式设备进行任何更改。

      如果您想查看变量——如果您的 PC 工具能够读取链接器生成的 ELF 文件,那么它可以从符号表中找到变量的位置。更好的是,阅读 DWARF 调试数据并了解变量的类型。那么您只需要嵌入式设备上的“读取内存”协议消息来获取数据,PC 进行解码和显示。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-01-23
        • 1970-01-01
        • 2010-11-21
        • 2010-11-25
        • 1970-01-01
        • 1970-01-01
        • 2011-03-16
        相关资源
        最近更新 更多