Skip to content

Hack project to build a digital tide clock using Rust and Raspberry Pi.

License

Notifications You must be signed in to change notification settings

thefuntastic/rust-tide-clock

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 

Repository files navigation

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.

In particular 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.

Usage

In order to build your own working version, you will need a worldtides.info API key. Duplicate resources/Secrets-Template.toml to 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 cargo run.

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 rust-openssl 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.

Licence

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.


Personal Anecdata

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 https://unix.stackexchange.com/questions/473901/execute-script-at-startup

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

WaveShare SSD1305

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:

  1. Arduino
  2. Raspberry Pi
  3. STM32 (another hardware platform)

Obviously we are interested in the Raspberry PI. Here they are further broken down by protocol

  1. I2C
  2. SPI

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

  1. bcm2835
  2. python
  3. wiringPi

BCM2835

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.

Python

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

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: Raspberry Pi/SPI/wiringPi/readme.txt (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

$ make

Followed by

$ 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.

Rust

Rppal Crate

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 rppal v0.11.

Image Crate

https://docs.rs/image/0.23.8/image/

Extra usage samples here https://github.com/ha-shine/rustagram/blob/master/src/rustaops/mod.rs

https://github.com/image-rs/image/blob/master/src/lib.rs

About

Hack project to build a digital tide clock using Rust and Raspberry Pi.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages