A while ago I was a mobile developer. I made apps for iOS and had to constantly worry about memory consumption, performance, you know, all the boring stuff that makes computers hard.
Then I became a web developer. I kicked up my feet and let the VM do the work for me. Memory? Psh, buy more ram cheapskate. Memory leaks? Who keeps a web page open long enough to have leaks anyway? Stop streaming videos from your work laptop and use a Chromecast, that’s an at-home-so-no-one-knows-you-love-the-bachelor type activity anyway.
I also have two dogs. They’re awesome, but I always felt like they didn’t have enough cool shit to call their own. Sure they have toys that they enjoy eating and later pooping out, but I’m a tech guy, and they’re tech-less dogs, which is a little embarrassing.
So, naturally, I started trying to make a badass dog collar for the little luddite fluff balls. I picked up a few Particle Photons (which are awesome, highly recommend,) and was off to the races, programming in baby C and C++ just like data structures in college, except without the hangover, and the video games. Okay, still with the hangover, just without the video games. Okay, still with the video games.
Programming in those old languages wasn’t so bad, they have pretty normal features, Strings are a pain, but the included libraries provide some good support there. Then, when I thought everything was going well, Bachelor in Paradise went and got shut down — oh, also my program kept crashing mysteriously. Turns out the issue was a memory leak in the code because, of course, I haven’t concerned myself with manual memory management in years.
I continued on, trying to remember to alloc and dealloc like a champion, until my good friend, Will, suggested I try out Rust. He described it as “The right way to do memory management,” and I can now say I agree.
That’s when I started trying to port my dog collar code to Rust.
A big, huge, enormous shoutout to Jorge Aparicio, who helped me a ton through all of this. The guy has the patience of Chris Harrison during a rose ceremony.
I started at Jorge’s awesome quickstart readme, and was able to get my code up and running quickly. I was honestly surprised at how easy it was. I also needed to use a couple of libraries that were written in C/C++ to get the basic functionality going. That’s when I stumbled and fell down the rabbit hole.
I had some good guidance from Jorge on how to do this, basically there were a few steps to take:
- Get the C/C++ library
- Add the
gcccrates to your project.
- Make a build.rs file
- Add your build.rs file under
[package]in the cargo.toml file like so:
build = "build.rs"
bindgen, generate the rust bindings from the header file of the library you want to import. In other words, add something like this to your build file’s main function:
let bindings = bindgen::Builder::default()
.expect("Unable to generate bindings");
let out_path = PathBuf::from("src");
.expect("Couldn't write bindings!");
My code just happens to reside in
- Finally, add the step that actually compiles the C/C++ code into a lib and puts it in your build target:
.cpp(true) // Switch to C++ library compilation.
If you’re lucky, that’s it! The library you’re including doesn’t have any references to the particle firmware and you’re all hunky dory. You can use it like a normal module now or require it in as an external crate, go crazy.
If you didn’t get that ring, don’t worry, you can still go on Bachelor in Paradise to find true love, it’s just a little harder and you have to get really drunk in Mexico — I mean, add a bunch of compiler flags.
Rust on the photon is great, but, like Bachelor in Paradise, it lacks standard(s)… libraries (got ‘em.) That’s fine, until you realize that practically everything relies on the standard library. That means that you have to be very careful after running your compile commands to audit the outputted rust code.
I tried the process out with the Adafruit Neopixel Library and this is what my build.rs looked like after some tinkering:
You’ll notice a few things here:
- There are a metric shit-ton of flags. Those are all the flags I threw in so that gcc would use the correct libraries and compile based on the Photon firmware build process. I basically ran the build process and copied the gcc step manually.
- I commented out the bindgen steps. This is because I used them to generate the rust bindings with basic types (being new to rust, this seemed like the safest thing,) and then I removed anything referencing the standard library or that seemed extraneous. There were, for example, a lot of things generated that were used by the Photon library, but not the bindings.
This all seems well and good, and I believe that it was a great start, but, alas, like the proposals in the bachelor, the code crashed as soon as I tried it out for realsies. I’m still not sure what the issue was, perhaps it was that the Neopixel library uses raw assembly and Rust didn’t like that. Regardless, I ended up writing most of the functionality from scratch in Rust, but perhaps I found a new love in embedded Rust. I accept this rose — I mean Rust.