对于嵌入式系统的命令行实现,是否有任何好的参考实现?

发布于 2024-08-14 17:59:07 字数 161 浏览 2 评论 0 原文

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

I am aware that this is nothing new and has been done several times. But I am looking for some reference implementation (or even just reference design) as a "best practices guide". We have a real-time embedded environment and the idea is to be able to use a "debug shell" in order to invoke some commands. Example: "SomeDevice print reg xyz" will request the SomeDevice sub-system to print the value of the register named xyz.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

烟酒忠诚 2024-08-21 17:59:07

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

  • 一个收集命令行的函数 - 它很简单;没有命令行历史记录或任何东西,只有退格键或按转义键放弃整个内容的能力。但如果我认为需要更高级的编辑功能,那么在这里添加它们也不会太难。
  • 解析一行文本 argc/argv 样式的函数(请参阅 将字符串解析为 argv/argc 有关于此的一些想法)
  • 一个函数,它采用解析的命令行上的第一个参数并在命令表中查找它&函数指针来确定命令调用哪个函数,因此命令处理程序只需要匹配原型即可:

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

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

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

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

I have a small set of routines that is essentially made up of 3 functions and a lookup table:

  • a function that gathers a command line - it's simple; there's no command line history or anything, just the ability to backspace or press escape to discard the whole thing. But if I thought fancier editing capabilities were needed, it wouldn't be too hard to add them here.
  • a function that parses a line of text argc/argv style (see Parse string into argv/argc for some ideas on this)
  • a function that takes the first arg on the parsed command line and looks it up in a table of commands & function pointers to determine which function to call for the command, so the command handlers just need to match the prototype:

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

Then that function is called with the appropriate argc/argv parameters.

Actually, the lookup table also has pointers to basic help text for each command, and if the command is followed by '-?' or '/?' that bit of help text is displayed. Also, if 'help' is used for a command, the command table is dumped (possible only a subset if a parameter is passed to the 'help' command).

Sorry, I can't post the actual source - but it's pretty simple and straight forward to implement, and functional enough for pretty much all the command line handling needs I've had for embedded systems development.

献世佛 2024-08-21 17:59:07

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

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

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

You might bristle at this response, but many years ago we did something like this for a large-scale embedded telecom system using lex/yacc (nowadays I guess it would be flex/bison, this was literally 20 years ago).

Define your grammar, define ranges for parameters, etc... and then let lex/yacc generate the code.

There is a bit of a learning curve, as opposed to rolling a 1-off custom implementation, but then you can extend the grammar, add new commands & parameters, change ranges, etc... extremely quickly.

浮世清欢 2024-08-21 17:59:07

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

You could check out libcli. It emulates Cisco's CLI and apparently also includes a telnet server. That might be more than you are looking for, but it might still be useful as a reference.

颜漓半夏 2024-08-21 17:59:07

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

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

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

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

If your needs are quite basic, a debug menu which accepts simple keystrokes, rather than a command shell, is one way of doing this.

For registers and RAM, you could have a sub-menu which just does a memory dump on demand.

Likewise, to enable or disable individual features, you can control them via keystrokes from the main menu or sub-menus.

One way of implementing this is via a simple state machine. Each screen has a corresponding state which waits for a keystroke, and then changes state and/or updates the screen as required.

转身以后 2024-08-21 17:59:07

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

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

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

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

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

vxWorks includes a command shell, that embeds the symbol table and implements a C expression evaluator so that you can call functions, evaluate expressions, and access global symbols at runtime. The expression evaluator supports integer and string constants.

When I worked on a project that migrated from vxWorks to embOS, I implemented the same functionality. Embedding the symbol table required a bit of gymnastics since it does not exist until after linking. I used a post-build step to parse the output of the GNU nm tool for create a symbol table as a separate load module. In an earlier version I did not embed the symbol table at all, but rather created a host-shell program that ran on the development host where the symbol table resided, and communicated with a debug stub on the target that could perform function calls to arbitrary addresses and read/write arbitrary memory. This approach is better suited to memory constrained devices, but you have to be careful that the symbol table you are using and the code on the target are for the same build. Again that was an idea I borrowed from vxWorks, which supports both teh target and host based shell with the same functionality. For the host shell vxWorks checksums the code to ensure the symbol table matches; in my case it was a manual (and error prone) process, which is why I implemented the embedded symbol table.

Although initially I only implemented memory read/write and function call capability I later added an expression evaluator based on the algorithm (but not the code) described here. Then after that I added simple scripting capabilities in the form of if-else, while, and procedure call constructs (using a very simple non-C syntax). So if you wanted new functionality or test, you could either write a new function, or create a script (if performance was not an issue), so the functions were rather like 'built-ins' to the scripting language.

To perform the arbitrary function calls, I used a function pointer typedef that took an arbitrarily large (24) number of arguments, then using the symbol table, you find the function address, cast it to the function pointer type, and pass it the real arguments, plus enough dummy arguments to make up the expected number and thus create a suitable (if wasteful) maintain stack frame.

On other systems I have implemented a Forth threaded interpreter, which is a very simple language to implement, but has a less than user friendly syntax perhaps. You could equally embed an existing solution such as Lua or Ch.

陈年往事 2024-08-21 17:59:07

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

免责声明:我不关心 Forth,但是 openboot 和 PCI 总线确实如此,而且我已经使用过它们并且它们工作得非常好。

替代 UI

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

如果您确实需要 CLI,那么您可以指向一个链接并获取 telnet。

For a small lightweight thing you could use forth. Its easy to get going ( forth kernels are SMALL)
look at figForth, LINa and GnuForth.

Disclaimer: I don't Forth, but openboot and the PCI bus do, and I;ve used them and they work really well.

Alternative UI's

Deploy a web sever on your embedded device instead. Even serial will work with SLIP and the UI can be reasonably complex ( or even serve up a JAR and get really really complex.

If you really need a CLI, then you can point at a link and get a telnet.

晨与橙与城 2024-08-21 17:59:07

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

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

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

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

One alternative is to use a very simple binary protocol to transfer the data you need, and then make a user interface on the PC, using e.g. Python or whatever is your favourite development tool.

The advantage is that it minimises the code in the embedded device, and shifts as much of it as possible to the PC side. That's good because:

  • It uses up less embedded code space—much of the code is on the PC instead.
  • In many cases it's easier to develop a given functionality on the PC, with the PC's greater tools and resources.
  • It gives you more interface options. You can use just a command line interface if you want. Or, you could go for a GUI, with graphs, data logging, whatever fancy stuff you might want.
  • It gives you flexibility. Embedded code is harder to upgrade than PC code. You can change and improve your PC-based tool whenever you want, without having to make any changes to the embedded device.

If you want to look at variables—If your PC tool is able to read the ELF file generated by the linker, then it can find out a variable's location from the symbol table. Even better, read the DWARF debug data and know the variable's type as well. Then all you need is a "read-memory" protocol message on the embedded device to get the data, and the PC does the decoding and displaying.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文