And the projects come and go, talking of Michelangelo...

A project log for NYETduinoPlusLua

Wherein a Netduino Plus 2 is repurposed with alternative firmware based on Lua

ziggurat29ziggurat29 05/17/2018 at 16:140 Comments


Time to Rise and Resurrect work on this project after languishing a few months.  When I left off, I was having a Devil of a time getting eLua to work with absolute stability on my NetDuino/STM32Workbench/FreeRTOS platform.  I am taking a step back (for now at least), and trying a straight port of Lua 5.3.4 for now.


When I left off, I had eLua somewhat working, however it had a tendency to crash all the time.  I know it must be something dumb that I am doing, but I really have to say it should be simple to do a platform adaption, and I guess for some reason for me in this case it is not.  Again, 'it probably is just me', but I'm tired of reverse-engineering the code to try to guess what is going on.  So, I'm taking a step back to the beginning, and porting the Lua 5.3.4.

Ultimately, I wanted 5.3.4, anyway, and eLua (as with other projects like LuaJIT) are stuck in the past with 5.1.x.  I'm not sure why, but it is pretty common.  I mainly want 5.3 because it has bitwise operators, and why not be on the latest if you're doing new work.  The upside is that I have already integrated 5.3 in other (desktop) projects, so I am familiar with it, and the downside is that it does not have the eLua optimizations for memory constrained devices -- the so-called "Lua Tiny RAM" patch.  'So-called' because I don't see a patch file anywhere.  Rather there is just the resulting patched source.  Anyway, I've decided for the moment that I'll save analysing what that is and make a proper 'patch' to the 5.3 source as a future exercise.  For now, I want an unconditionally stable Lua running in FreeRTOS with the STM32Workbench toolchain on the NetDuino board.

So, I made a new branch, 'elua002' (named before I decided to abort elua for now), and transferred over my memory manager and wired in the Lua 5.3.4 source.  I modified the 'lua.c' which contains a 'main()' that needs some minor changes so as to be invoked from a FreeRTOS task, and built.  I didn't bother trying to run it since I know it is not going to work without more support.

The STM32Workbench toolchain uses newlib-nano.  Newlib expects to have a bottom edge ('syscalls and 'stubs') realized that provides platform-specific implementation for things like open(), close(), fork(), kill(), etc.  This makes some sense, but to my great vexation, the STM32Workbench build of newlib-nano has some sort of default implementation of those lower-edge functions.  What do they do?  I can tell you what they don't do:  they don't interface with my board's serial ports or filesystem implementation.  So I gots some works to dos.  But what, precisely?

My first attempt was to #define my self out of reality.  There is a master header 'lua.h' that all the lua modules include, and it has a section marked at the end stating 'here be your dragons', so I made a 'redirection' header which #defined all the stdio/stdlib stuff that I thought I would need into my own implementations, cleverly named with a prefix if 'my-'.  This was a fairly surgical change, and that aesthetic appealed to me.  However, studying the resulting map file showed that some libc things were still getting hoisted in, so I ditched this approach.  I probably could have continued analying it and got it working, but it gave me the heebie-jeebies as far as being unconditionally stable in the case of evolving more code.  So I gave this up, and went back to bit the bullet by implementing the newlib bottom-edge functions properly.  This should be unconditionally stable, though potentially more, or awkward, work.


I would have preferred many things, but we get what we get, and we have to carry on.  Sometimes we can leave things better than we found them.  Anyway, I collated all the data in the newlib doc mention, and fixed the pertinent function signatures, and included what was required for the definitions, and turned it into a header 'newlibsupport.h'.  Now I can at least use this in future projects using newlib.

For my next amazing feat, I produced a 'stub' implementation 'newlibsupport.c' which implements all those methods, but deliberately has that implementation reference a method 'NEEDS_IMPL()' which is specifically not implemented.  This lets me first prove upon attempted linkage that the linker is trying to use my implementations instead of the defaults unfortunately baked into newlib, and also have a skeleton implementation with a 'your code here' sign posted.

De gustibus non est disputandum?  Perhaps.


Anyway, that being out of the way I did validate many sensible things need to be implemented; e.g. all the open/close/read/write methods that I was fully expecting, but also seek(?)/stat(?)/link(?)/unlink(?)/exit(?) need to be as well.  So I stubbed those for the moment to get a link to succeed, and now I am off to implementing that stuff.

It will be a little bit of a hassle, since I'll have to implement some sort of file descriptor system, with a v-table of the methods that forward into device-specific implementations, and maintain errno (a separate peculiarity of newlib and requiring some FreeRTOS tweaks to support.  I won't bore you, but you can google 'freertos newlib support' and find out more.  It has to do with maintaining the 'struct _reent' object.)  In the end it will probably be worth it, since then libc will work as expected, and if nothing else I can reuse it in other projects based on this toolchain.

"Heigh-ho, heigh-ho, it's off to work we go..." [sic]


Wherein I implement some stubby-stubs to smooth-over the newlib nubby-nubs.