…or, how Adam decided that the C in C25K stood for… well, C.

I decided a while back to start running again. It’s been a few years since I broke my ankle, I’m not getting any younger, and there’s some vague glimmer of hope that we might get a bit of a cricket season in here in Vancouver1, so it felt like it was time.

Unfortunately, a combination of being old, lazy, and beer mean that I probably can’t just go run several kilometres any more, so I’ve been doing something I’ve always hated: intervals. Specifically, the Couch to 5K programme. Which means that I need to time things, and remember things like how many reps I’ve done.

I am, in related news, really bad at remembering things like that when exercising.

I also don’t really want to be holding a phone when I exercise, so I dusted off my old Pebble Time2 and went hunting for apps. There are two apps on the Rebble store. They’re both functional, but have a significant flaw for me: you don’t get much of a sense of how you’re doing overall. Since I’ve never had an endorphin from exercise ever, in order to convince my body that idle exercise is worth it I badly need to know that there is a finish line after which the pain will subside.3

Therefore, I decided to also dust off my Pebble app making skills4 and see where that led. Specifically, it led here:

A watch app showing a running activity represented using a clock-style ring

I built a thing!. It is, naturally, open source. It has not been submitted to the Rebble store as yet, mostly because I don’t really like Discord or bugging people and the submission process involves both.

I hadn’t used the Pebble SDK since the version 2 days. By the time Pebble folded, they were up to version 4.5, and there was a pre-release 4.6 out there.5 This was a huge improvement on the early days of Pebble development: there were emulators! The build process only involved one weird Python thing! The API had lost most of its rough edges and allowed you to pass userdata to almost all the callbacks!6

And, as it turns out, writing basic graphics code is still fun. The Pebble SDK provides a bunch of drawing primitives for things like arcs, circles, and rectangles, and you can also just grab the framebuffer and bitbang that if you really want to. Of course, it’s running on a Cortex-M3 or Cortex-M4 with a few hundred kilobytes of RAM, so you can’t go too crazy, but it’s nice to just have the possibility.

In the end, I really only hit two problems:

  1. I wanted to use Rust, because obviously. A couple of people have tried and apparently succeeded with trivial apps, but I wasn’t able to join their ranks: with a lot of swearing and excursions into corners of the Rust toolchain I’d never been to before7, I could get something to link and be apparently valid, but not something that would do anything other than (a) crash on startup, or (b) lock up the watch.8

    I wrote it off as a bad job after a couple of evenings, but it’s bugging me. It’s a bog standard THUMB chipset running a hacked up version of FreeRTOS, and the interesting bits of generating code for that are all in LLVM once you disable the Rust standard library and accept that unsafe will be your best friend. I’m annoyed I couldn’t get it to work, even given some of the weirdness in the Pebble app build process.9

  2. I got sad about Pebble. After they failed, they were bought by Fitbit, who were pretty generous with the grace period but eventually shut all the online services and support down.

    But the Pebble’s actually still a really handy device. The battery life is great, and it’s in a weird spot where it’s not quite a true smartwatch, but it nailed the things I actually want a device to do on my wrist: my phone can provide the smarts; I just need something that’s in a nice form factor and can perform a small number of actions.

    Plus, it’s actually pretty fun to develop for. The SDK really was quite good by the end, and it’s a full featured enough environment to not feel like you’re constantly running into arbitrary limitations, unless you need more than 64 kB of heap. (Nobody needs more than 64 kB, right?)

    In retrospect, Pebble’s biggest failing seemed to be that they didn’t quite know what they wanted to be. Pebbles were absolutely niche devices, but there was a period where Pebble (the company) was trying to take them mainstream — into brick and mortar stores, and into the consciousness. And maybe that’s what they had to do if they were going to make the economics work.

    But it feels like there’s a hole in the market for a modern Pebble-like device, and it almost makes me want to look into it. (Until I remember all the blog posts Pebble posted at the start of the process about how hard it was to get stuff manufactured, anyway.) It wouldn’t be a huge seller, but I’d buy one. You wouldn’t sell millions, but you’d sell thousands. Probably tens of thousands.

    I wish there was room for that in the modern tech world.

So, when people ask me what I did during COVID-19, I can say — hand on heart — that I did something productive10 and didn’t spend the whole time drinking beer.

Except for the parts where I was drinking beer while working on this.

Which was the whole development process.

Better get back to running to offset that, I guess.

  1. Oddly, unlike the NHL, cities do not seem to be falling over themselves to host the British Columbia Mainland Cricket League in quarantine. 

  2. Pebble was a relatively short lived company that made low power watches with e-ink displays, battery life measured in days (if not weeks), and enough Bluetooth smarts to at least show you notifications. 

  3. At least until the next day, at which point I will almost fall down the stairs because my quads stopped working sometime during the night. (That only happened once, in fairness.) 

  4. Last seen several years ago to build a ball counter for use when umpiring a cricket match, because it was easier than ordering a real one to Canada. 

  5. Which, oddly enough, is the actual version that’s in the Arch User Repository, even though it claims to be 4.5

  6. The one thing I hit that you still need to use global state for is the TickTimerService, which… uh, feels kinda fundamental for a watch. I hacked around it by repeatedly setting 500 ms timeouts, but I doubt that’s good for battery life. 

  7. Hi, cargo rustc and your collection of fun arguments you can pass directly to rustc and LLVM. 

  8. On the bright side, Pebbles have a watchdog that reboots the watch if the UI is unresponsive for a few seconds. On the darker side, if you trigger that too often, you get punted into recovery mode and have to restore. As I found out. Twice. 

  9. For example, you build a perfectly good ELF binary for each model, and then there’s a weird action that pulls it apart, looks for symbols, and then somehow injects metadata into the ELF binary to turn it into a binary blob that is actually uploaded to the watch. I’m sure there’s a good reason for all this, but it does feel a touch overwrought. 

  10. Lots of other people have said this, but I’ll reiterate it: it’s also OK to have done nothing during COVID-19. It hasn’t been a fun time.