The Inside Story of Meadow.Linux

About a year ago I was working on a project for an NVIDIA Jetson Nano that used four pretty common and easy to find peripheral devices. As a long-time embedded .NET developer, I decided that using the .NET IoT library was probably the route to go, but I could only find an existing .NET driver for one of the peripherals I needed. This was a bit frustrating, since we had support for all four of them in Meadow.Foundation.  

The obvious first step was to try to port the Meadow drivers over to the .NET IoT format, but after spending time browsing source code for several existing drivers in the framework, I was only confused and dissatisfied. Few of the .NET IoT drivers followed any sort of coding or usage patterns, so it was not obvious exactly what the surface of my new drivers would look like. Even worse, I absolutely hate duplicating work that was already done, and the Meadow.Foundation drivers were done. If I duplicated them into the .NET IoT format, then they’d start to diverge and I’d have 2 code bases to deal with for the exact same peripheral.

What if I could somehow use the Meadow.Foundation driver exactly as-is, right from Nuget on the Jetson? They are, after all, just .NET Standard 2.1 assemblies, so they wouldn’t need recompiling, and the actual hardware interfaces, like the I2C bus and GPIOs were already pretty well abstracted out. I then decided to do a couple tests.  What would it look like if I created a minimal implementation of the Meadow.Core assembly that would let me turn on and off a single GPIO, but that would run on a Jetson under Linux? Basically what would the effort be to make Meadow as a software stack run practically anywhere?

I spent a couple days refactoring things to get a clean split between Meadow.Core and the underlying Meadow.OS platform and got it working pretty cleanly.  If you’re been a Meadow developer for a while, you might have noticed the appearance of a Meadow.F7 assembly a few months back, and that was some of the outgrowth of that work. Another great side effect was that it made the existing Meadow.Core bits more atomic and testable as well.

Once I had a single GPIO working on the Jetson, I figured I should extend the idea and get it to work on the Raspberry Pi as well. The code base was clean enough that it was only a couple hours of work. This was serious progress! I had application code that could run on a Meadow F7, a Jetson Nano or a Raspberry Pi 4 and the only difference was in how the physical pinouts were defined.

I spent some more time expanding the code base to work with all pins on both boards, and then tackled getting an implementation for the I2C driver up and working. Again, it was pretty easy to get working, and the code base was falling into place nicely, telling me that the architecture was right. I now had the ability to write an application that with just very minor modifications (again, because the physical hardware is different) could run on our Meadow platform as well as a Jetson Nano or a Raspberry Pi and I had access to well over 100 working and actively maintained peripheral drivers from Meadow.Foundation!

The value was pretty obvious, and the entire Wilderness Labs team was excited about the new capability. It wasn’t ready for production deployments, but it was definitely good enough to release into the wild and see if the community would be interested, and if they might even jump in and start helping extend it. We decided to open source the entire project as Meadow.Linux so we put it up on GitHub. Shortly after publishing it, we announced it at Wilderness Labs DevCamp 2021 and into the world it went!

There’s still a lot to do with the library. It still needs some fundamental driver implementations like SPI, but those efforts are ongoing. The important thing is that we as the .NET community creating IoT applications now have a portable framework using modern APIs that are designed specifically for hardware and that framework comes complete with drivers for a ton of existing peripherals (and more becoming available all the time). We can continue to focus our efforts on developing products and solutions that provide unique value and not have to be consistently re-inventing the wheel creating new implementations of drivers that already exist. I firmly believe it’s going to be useful for a lot of developers, and it’s going to save a lot of collective time as more and more developers use it for their own projects.  

So whether you have some existing and ongoing IoT projects, or you’re a maker that just likes to tinker around with hardware, I encourage you to take a look at it.  I’d also encourage you to provide feedback on what works, what doesn’t, and what features you need us to add to it for you to be successful.  Together we can all make .NET a first-class IoT citizen on all of the popular hardware.