Some thoughts on Zephyr Console API
Paul Sokolovsky
Hello,
I would like to share some thoughts/woes with using Zephyr console API, based on the experience with (initial) porting of two console application to Zephyr, both are scripting languages, JerryScript and MicroPython. As those are scripting languages, interactive prompt (aka REPL) play important role for them. Both JrS and uPy are intended for embedded usage, and both share a similar architecture, where there's "unix" port, which can serve as a demo, and as a starting port for a port to specific RTOS/hardware. Both of these projects for reading a console input require classical K&R-style getchar()-like function, with a semantics of "read a single char from console, block if not available". Alternatively, they can interpret a whole line at once, that's classical gets() with semantics of "block until whole line from console is available, then return it". Using gets()-like call has a benefit that line-editing capabilities can be provided, and transparent to an application. Let's see what effort was required to port them to Zephyr: 1. JerryScript port was originally done by Sergio Rodriguez (Zephyr team member or at least member of another team in Intel which uses Zephyr closely). Instead of pull-style gets(), it uses push-style whole line delivery via callback from Zephyr shell subsystem. Works well, and there's line editing, completion support offered by Zephyr shell, which is really nice. And while not as easy as a single gets(), set up of it is pretty easy and high-level. And it works nice, until you try to enter a line with at least 10 spaces, e.g.: for (var i = 0; i < 10000; i++) { a.push("foo"); } That ends up with "Too many parameters (max 10)" error. That's because shell unconditionally tokenizes an input lines into space-separate tokens, and the default (non-configurable) limit is 10. And of course, JerryScript then needs to join them back. 2. With MicroPython, I decided to follow "getchar" approach, especially that uPy has an own readline-like implementation with more capabilities then Zephyr. So, I started to look how to make Zephyr pass me input chars. I saw drivers/console/uart_pipe.c, and thought that's the best approach, as it allows the leanest way to do that. Unfortunately, playing with for few hours, I couldn't make it work. I then followed another lead - using uart_irq_input_hook. With some extra effort I was able to make it work, and created a standalone module which just exposes zephyr_getchar() function: https://github.com/pfalcon/zephyr_getchar Conclusions: Getting console input with Zephyr is *HARD*. I originally reported an issue #1 above as https://jira.zephyrproject.org/browse/ZEP-532 , and suggested that I could fork console_handler_shell.c, remove tokenizing and would get what I want. But arguably, that's a lot of work to just gets() which is just there on a lot of other systems. However, with "getchar" trial, I essentially did just that - coded simple, but not exactly trivial code on top of what Zephyr. So, I guess I could do similar for "gets" too, but one problem is that it unlikely to help many other people - it really would be nice to have that in the main Zephyr repo, and engineered properly (for example, zephyr_getchar module above isn't compatible with Zephyr shell). Would that make sense for Zephyr? Requirements would be simple: 1. Add ability to receive a single char from a console; also, a single line (with editing and other niceties). 2. Push-style interface with a callback is probably OK, but having pull-style interface would make porting a lot of software easier. And with a push-style, a multiple consumers problem immediately manifests itself. Thanks, Paul Linaro.org | Open source software for ARM SoCs Follow Linaro: http://www.facebook.com/pages/Linaro http://twitter.com/#!/linaroorg - http://www.linaro.org/linaro-blog |
|