Rust + Raspberry Pi Tide Clock
Source code for a digital tide clock with accurate and location specific tidal readings. This maker project conceived as heartwarming birthday present, you can read more about the build and construction on my blog.
I provide no guarantees about idiomatic usage or correct code conventions, in particular as my Rust exposure was limited at the time of writing. The code is merely provided as a sample for the curious, however there are some bits that may be of interest to wider audience.
src/ssd1305.rs is a working reference implementation of communicating to a Waveshare SSD1305 by use of the
rppal crate. This may be of use to other makers working on similar embedded projects.
In order to build your own working version, you will need a worldtides.info API key. Duplicate
resources/Secrets.toml and substitute your API key.
To change the location, you can use the WorldTiles console to find accurate Lat and Lon values. These can then be populated in
resources/Settings.toml. By default the project will make an API call approximately every 3 days.
Cross Platform Development
On Raspberry Pi, assuming you've got the appropriate screen attached, all display logic will be output to the screen via the GPIO pins. On other platforms (e.g. Windows), output will instead be saved to
tide-clock/resources/display.bmp. Visual Studio Code will hot reload images on change, which allows effective development on other platforms
Cross Platform Compilation
If you're building on Raspberry Pi 3, running the project is simply a matter of installing rustup and calling
Gitlab CI cross compilation
This is the orignal method used during development. This blog post provides a guide to the considerations. The
.gitlab-ci.yml file provides a working implementation of this on Gitlab (this is hosted on Github for distribution purposes only). You will need to host your own repository on gitlab in order to enable the ci script.
Local cross compilation
Generously contributed by @BartMassey, this details building for both Raspberry Pi Zero and Raspberry Pi from a local environment. Note: This method hasn't been tested in production, no guarantees included.
You'll need a directory containing a
libopenssl-1.1.0g installation targeted at
arm-unknown-linux-gnueabihf. You can build this from source following the instructions in the
README, but you might want to check the status of Issue #1354 to see if you need to patch the source before trying to build. Then
./Configure --prefix=/foo linux-armv4 -fPIC make make install
Once you've done that, you'll need to tell
rust-openssl to use that for cross compilation via
OPENSSL_DIR=/foo export OPENSSL_DIR
You can then build via
cargo build --target arm-unknown-linux-gnueabihf and find the binary in
target/arm-unknown-linux-gnueabihf/debug/tide-clock to copy to the Pi.
The licence is GNU GPL v3. Any makers and other non-commercial users are encouraged to use the code as they wish. Any commercial usage should contact me directly for a commercial licence.
The following excerpts from my personal notes are provided for reference only. They do however contain some additional context that might prove useful.
Restarting the program on Pi boot
There seem to be multiple ways to do this. I'm using
/etc/rc.local which is a shell script called on startup. This needs to be executable, which it already is on Raspian Noobs build I'm using
Change to home folder (otherwise you might run into paths issues) and then execute the program
cd /home/pi/Projects/TideClock/rust/tide-clock/target/arm-unknown-linux-musleabihf/release/ ./tide-clock
This is a good resource on how to start the program as a service, and is probably the method I prefer if starting again http://segfaultsourcery.s3-website.eu-central-1.amazonaws.com/snippets/rust/rust-to-raspi/landing.html
The OLED screen is manufactured by Waveshare, is docs are located here https://www.waveshare.com/wiki/2.23inch_OLED_HAT
Given the translation levels, the docs can be a bit confusing. It refers to samples which are buried at the bottom of the page: https://www.waveshare.com/w/upload/c/c5/2.23inch-OLED-HAT-Code.7z
The samples actually are multiply redundant, and show many different ways of achieve the same result. Platforms:
- Raspberry Pi
- STM32 (another hardware platform)
Obviously we are interested in the Raspberry PI. Here they are further broken down by protocol
The screen doesn't do I2C without being resoldered (at least as far as I understand it). So obviously we're using SPI
There are three language examples
As far as I understand, bcm is the Broadcom controller for the the Pi's GPIO pins. This 3rd party C library needs to be compiled and built, and then speaks to the controller natively.
I was dissuaded from this by the fact that the library needs to be compiled.
This would be the most convenient option, however I can't tell why it doesn't work. Not knowing enough about the Pi and it's environment I've abandoned this
WiringPI is an open source C effort that seems to be distributed with Raspbian. This makes it the "defacto", however it seems the maintainer has (recently) stepped down from the library, so it's unclear how long it will stay viable for.
For reasons I'm not quite sure of, each approach labels the pin numbers differently. A reference can be found here in the Waveshare samples:
rppal uses BCM numbering)
Otherwise this examples seems to work well and is easy to understand.
My efforts are centred around porting this example to rust.
In order update the screen first call make
$ sudo ./oled
If you just try run the sample directly it will error as it was presumably built for a different architecture
SPI and GPIO
I'll admit my understanding of this isn't stellar, however I know SPI is a format for sending packed data in an efficient format. However the SSD1305 is mostly sending pixel data over
SPI, while most of the other controller data is sent directly to GPIO pins, which follow a simple Arduino high/low convention.
With version 0.10.0 the library changed it's API to per pin access. From what I can understand this brings technical benefits (thread safety etc), however it also includes advanced rust type shenannigans I struggled with.
Originally the project used
rppal v0.9.0, the last version before the refactor. Again thanks to @BartMassey for contributing the updgrade to
Extra usage samples here https://github.com/ha-shine/rustagram/blob/master/src/rustaops/mod.rs