Close
0%
0%

Louia ObScura

A Smolnet Spartan Server and Obscure Multitasking OS with Coroutines in MicroLua on a Pi Pico 2 W and Pico W

Similar projects worth following
Louia ObScura is a multitasking TCP/IP-based server and web-like OS using Lua coroutines. It was written in MicroLua and Lua 5.5 for the Pi Pico 2 W and Pico W that provides CGI-like capabilities over the Spartan Small-Internet protocol. Even if you're technically-fluent, if you've never heard of some of what I've just mentioned, don't worry and you're not alone, as that's the reason I've created this page. Welcome to the Desert of the ObScure.

Louia ObScura is not recommended for real-world use, although I did put it into real-world operation on November 18th, 2025 on a Pico 2 WH board that I bought at a local computer store in September 2025 (my first Pico), as that was its intended purpose for me.  I later released the source on November 27th, 2025 for perusal and inspiration and published a summary of this project here to specifically draw more attention to 5 obscure and underappreciated technologies and/or concepts that made this possible:

Like the more-popular Raspberry Pi Picos, Lua, of course, is not obscure to many, especially Roblox or NodeMCU programmers or those that use it in gaming or networking contexts, but it never gets near the top of the TIOBE index, which saddens me.  But even so, I have yet to see someone else write a program on the Picos in MicroLua (and Lua is currently my favorite general-purpose programming language), which is likely due to the lack of NodeMCU for those RP2350/RP2040 MCUs (unlike the ESP8266/ESP32 series) along with the more popular MicroPython and C, which are officially supported on the Picos.

In order to port my Linux and Pi Zero-based Louia Spartan server that I wrote in early 2025 to run on Lua 5.1/LuaJIT to a smaller MCU, I first identified the Pico 2 W and MicroLua as being well-suited to this task (the header version of the board only cost me $7.99 at a local computer store) and even reminds me of my old Commodore 128 in some ways, a futuristic 8-bit computer that I received for Christmas in 1985, as the Pico 2 series has multiple CPUs of different architectures inside and is faster and has double the RAM of its popular predecessor.  However, the Pico 2 W is not officially supported by MicroLua to date, another reason why it likely hasn't gained traction, and the fact that the developer does not accept code contributions directly likely slows its acceptance as well.

But MicroLua is a work of art, in my opinion, and I did manage to get it working on both the Pico 2 W (with some limitations) and the well-supported original Pico W (albeit with half the memory and flash), and I hope the developer stays with it.  Python 3's asyncio tasks within built-in event loops is analogous to what I did in Lua (although I have never used them in Python, only its multithreading and multiprocessing).  And coroutines are such a simple way to incorporate cooperative multithreading without the overhead, ideal for a small MCU, and yet they still remain fairly obscure, since most of the examples I see online and even the official Lua programming examples, are on the client side, often smartphone clients.

Well web servers, or Spartan servers which are analogous, need such multithreading for concurrent processing of multiple TCP/IP requests.  They're often called "threads" for simplicity when what is really meant here is coroutine.  If you've never used Lua's coroutines, something it had during its inception before other languages like Python even incorporated them, I highly suggest you take a look at them.  Or if your preferred language supports them, try them there just to familiarize yourself with the concept; they're like subroutines that simply allow you to pause them in mid-process and jump out of them and jump back into them later where you left off, even passing variables, solving blocking issues by their very nature.  Of course, preemptive operating systems saved us from the fallacy of relying on cooperation with 3rd party or buggy tasks that failed to yield, but if it is for something highly-controlled, small, and non-critical, it can be very efficient.

But once you've got Lua and coroutines understood, getting them working on a Pico under MicroLua has its own technical hurdle, which I had to solve before even getting a full successful compile, and embedded programming in general is very opaque and obscure in its own right in comparison with...

Read more »

LouiaObScura-1.2.tgz

Louia ObScura Version 1.2 licensed under GPL 3.0

x-compressed-tar - 65.76 kB - 12/06/2025 at 03:12

Download

LouiaObScura-1.1.tgz

Louia ObScura Version 1.1, licensed under GPL 3.0

x-compressed-tar - 65.06 kB - 11/29/2025 at 10:18

Download

  • Added Powersave Modes to Version 1.2 and Louia 1.4

    Lee Djavaherian12/06/2025 at 02:03 0 comments

    I added what I learned and did with Louia ObScura over the last 2 1/2 months on the Pi Picos to my original Linux-based Louia, releasing version 1.4 today which also contains a new, experimental powersave mode, turned on by default (although I probably should have kept it off).  I also added that powersave mode to this Pico-based project, and released version 1.2 of Louia ObScura today under GPLv3, the tarball attached in the Files section.

    I've got both the Pico 2 W version and the Linux-based version running simultaneously over at spartan://greatfractal.com now on different ports, the default Spartan port still directed to the Pico 2 W.  The Linux-based version has always been many times faster running on a single-core 32-bit Pi Zero, but of course that is at 1 GHz with 512 MB RAM, and it gets to use all of the CPU, Linux, and LuaJIT optimizations, too.  The Pico 2's RP2350 is also 32-bit (even dual-core with two more RISC-V cores), and similarly, I only use one of its two ARM cores, but it only runs at 150 MHz with almost a thousand times less RAM.  Using Lua 5.5 to also implement its own OS, the code got 3x larger on the Pico so the server is running a lot more interpreted code per request which also slows it down, as I have not optimized it.

    But I did take the time to add one optimization lately to reduce power.  In both versions, I had previously turned off blocking for TCP/IP sockets and just quickly looped through the socket function checking to see if there was a new connection before spawning a new coroutine.  Since I needed to loop anyway to allow my main dispatch loop (a sort of "kernel") to process multiple, concurrent requests so that I could avoid actual blocking of the socket for other requests, I had to use a lot more CPU cycles when I turned off the blocking on those socket checks.  In my early versions of Louia, I used something like the Unix select() function under LuaSocket's socket.select() to check for new or changed connections or block if nothing was happening.  But once I got a connection and the dispatch loop returned around to that socket check again, a lack of network activity would block its concurrency, becoming network IO bound and not CPU bound.  So I had to time it out quickly, negating much of the reason to use select in the first place, which would have saved me a lot of CPU cycles and power otherwise.

    But in working with them lately I realized that there is no good reason to keep the socket check unblocked if there is no concurrency in progress (no running coroutines).  So during the idle periods where there are no connections coming in and the last coroutine has ended, it starts blocking again which stops the main dispatch loop to save CPU power.  So on the Linux-based version, I just did a simple check to see if there are any coroutines running, and if not, set the socket.select() timeout variable to nil (blocking indefinitely until network activity).  It works in testing although I'm not sure yet if the socket itself is timing out after long periods of inactivity since I'm not calling it anymore, as I've gotten occasional locks with 1.4, so I may have to add a (long) timeout or periodic watchdog anyway.  Nevertheless, this new feature can be turned off.  But if there are coroutines running, or this feature is turned off, it sets it instead to the TIMEOUTCHECKSECS variable, a short delay that I use to control the dispatch loop speed and CPU.  On the Pi Zero when running atop Void Linux, when the powersave mode was turned on, the CPU use for louia.lua dropped so low during idle it was off the screen where I couldn't even see it.  Great!

    Yet... when I tried to do the same thing for the Pico 2 W, I ran into some problems.  Firstly, select(), of course, is a Unix-like construct that does not usually exist if you have no Unix-like OS (which is what I have here).  MicroPython (which I've never...

    Read more »

View project log

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates