first commit

This commit is contained in:
pandacraft 2025-03-21 16:04:17 +01:00
commit a5a0434432
1126 changed files with 439481 additions and 0 deletions

32
Software/Rust/README.md Normal file
View file

@ -0,0 +1,32 @@
# Rust support for GrovePi
## Introduction
Rust Crate support for using GrovePi with Rust.
Examples can be found in the relevant directories as `main.rs`.
Check them out for usage.
## Dependencies
* Rust version above 1.65 is known to work.
* The Rust crate [**rppal**](https://github.com/golemparts/rppal) is required and is referenced in the `Cargo.toml` file.
## Current State
As the initial state of this module the following features are implemented and tested:
* Read/write data to I2C slave device [**Grove-LCD RGB Backlight**](https://wiki.seeedstudio.com/Grove-LCD_RGB_Backlight/) V. 4.0 present on ports I2C-1, I2C-2 or I2C-3.
* Tested on Raspberry Pi 3, Model B and Raspberry Pi, Model B, Rev 2
with Raspbian version: September 2022
## Cross compile for Rasbperry Pi
Follow the setup instructions from - (https://github.com/cross-rs/cross)
Then `cross build --target arm-unknown-linux-gnueabi`. A pi-ready
and transfer the binary (`target/arm-unknown-linux-gnueabi/debug/airq`) to the Pi.
Run the binary `grove_rgb_lcd` on the Pi and observe a couple debug messages and changing colors.
## Add the module `grove_rgb_lcd` to your projects
Be sure to add the `rppal` dependency to your `Cargo.toml`

View file

@ -0,0 +1,2 @@
[target.armv7-unknown-linux-gnueabi]
linker = "arm-linux-gnueabi-gcc"

View file

@ -0,0 +1,27 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug executable 'grove_rgb'",
"cargo": {
"args": [
"build",
"--bin=grove_rgb",
"--package=grove_rgb"
],
"filter": {
"name": "grove_rgb",
"kind": "bin"
}
},
"program": "${workspaceFolder}/target/debug/grove_rgb",
"args": [],
"cwd": "${workspaceFolder}"
}
]
}

74
Software/Rust/grove_rgb/Cargo.lock generated Normal file
View file

@ -0,0 +1,74 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
name = "either"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "grove_rgb"
version = "0.1.0"
dependencies = [
"itertools",
"regex",
"rppal",
]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "libc"
version = "0.2.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "regex"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "rppal"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "612e1a22e21f08a246657c6433fe52b773ae43d07c9ef88ccfc433cc8683caba"
dependencies = [
"libc",
]

View file

@ -0,0 +1,9 @@
[package]
name = "grove_rgb"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rppal = "0"

View file

@ -0,0 +1,184 @@
use std::io;
use std::{thread, time};
use rppal::i2c;
// device structure for Grove RGB LCD Display
#[derive(Debug)]
pub struct GroveRgbLcd
{
i2c: i2c::I2c,
// row_cursor keeps track of NEXT ROW to be written -- internal state
// logic in #write_row will clear/reset the display when next row is 0
// the #write_line method will advance to the next row on column wrap
// -OR- on newlines in the input text
//
// This means that long inputs will just overwrite and may not be seen
// if this behavior is NOT desired, manage input to the LINE_LENGTH
// and add delays, etc.
row_cursor: u8,
}
pub const DISPLAY_RGB_ADDR: u16 = 0x62;
pub const DISPLAY_TEXT_ADDR: u16 = 0x3e;
const PROGRAM_MODE: u8 = 0x80;
const CLEAR_DISPLAY: u8 = 0x01;
const DISPLAY_ON: u8 = 0x08;
const NO_CURSOR: u8 = 0x04;
const ENABLE_2ROWS: u8 = 0x28;
const LINE_LENGTH: usize = 16;
pub const DISPLAY_CHAR: u8 = 0x40;
pub const NEW_ROW: u8 = 0xc0;
impl GroveRgbLcd
{
pub fn set_text(&mut self, text: &str) -> Result<(), io::Error>
{
match self.impl_set_text(text)
{
Err(err) => Err(io::Error::new(io::ErrorKind::Other, err)),
Ok(_) => Ok(())
}
}
pub fn set_rgb(&mut self, (r, g, b): (u8, u8, u8)) -> Result<(), io::Error>
{
match self.impl_set_rgb((r, g, b))
{
Err(err) => Err(io::Error::new(io::ErrorKind::Other, err)),
Ok(_) => Ok(())
}
}
}
impl GroveRgbLcd
{
fn select_slave(&mut self, addr: u16) -> i2c::Result<()>
{
println!("set slave {:x}", addr );
self.i2c.set_slave_address(addr)
}
fn clear_display(&mut self) -> i2c::Result<()>
{
println!("set display");
self.i2c.block_write(PROGRAM_MODE, &[CLEAR_DISPLAY])?;
thread::sleep(time::Duration::from_millis(50));
self.row_cursor = 0;
Ok(())
}
fn display_on_no_cursor(&mut self) -> i2c::Result<()>
{
self.i2c.block_write(PROGRAM_MODE, &[DISPLAY_ON | NO_CURSOR])
}
fn enable_2rows(&mut self) -> i2c::Result<()>
{
self.i2c.block_write(PROGRAM_MODE, &[ENABLE_2ROWS])?;
thread::sleep(time::Duration::from_millis(50));
Ok(())
}
fn new_row(&mut self) -> i2c::Result<()>
{
self.i2c.block_write(PROGRAM_MODE, &[NEW_ROW])?;
self.row_cursor = (self.row_cursor + 1)%2;
Ok(())
}
// writes a row of chars -- no checking for line length or newline
fn write_row(&mut self, row: &[u8]) -> i2c::Result<()>
{
if self.row_cursor == 0
{
self.clear_display()?;
}
for ch in row
{
self.i2c.block_write(DISPLAY_CHAR, &[*ch])?;
}
Ok(())
}
// write_line()
// a line has no '\n's in it... but will be wrapped at the display length
// and written on two rows
// Display is cleared before writing the line
fn write_line(&mut self, line: &str) -> i2c::Result<()>
{
println!("writing line: {}", line) ;
for row in line.as_bytes().chunks(LINE_LENGTH)
{
self.write_row(row)?;
self.new_row()?;
}
Ok(())
}
fn impl_set_text(&mut self, text: &str) -> Result<(), i2c::Error>
{
self.select_slave(DISPLAY_TEXT_ADDR)?;
self.clear_display()?;
self.display_on_no_cursor()?;
self.enable_2rows()?;
// spool out text one char at a time
// First split on newlines (user formatting) with .lines()
// then split those lines a line length (wrapped lines) with .chunks()
println!("ready to write {}", text);
for line in text.lines()
{
self.write_line(line)?;
}
Ok(())
}
fn impl_set_rgb(&mut self, (r, g, b): (u8, u8, u8)) -> Result<(), i2c::Error>
{
self.select_slave(DISPLAY_RGB_ADDR)?;
self.i2c.block_write(0x00, &[0x00])?;
self.i2c.block_write(0x01, &[0x00])?;
self.i2c.block_write(0x08, &[0xAA])?;
self.i2c.block_write(0x04, &[r])?;
self.i2c.block_write(0x03, &[g])?;
self.i2c.block_write(0x02, &[b])?;
Ok(())
}
}
pub fn connect() -> Result<GroveRgbLcd, io::Error>
{
println!("connecting I2C bus");
match i2c::I2c::new()
{
Err(err) => Err(io::Error::new(io::ErrorKind::Other, err)),
Ok(i2c) => Ok(GroveRgbLcd{i2c: i2c, row_cursor: 0}),
}
}

View file

@ -0,0 +1,26 @@
use std::error::Error;
use std::{thread, time};
mod grove_rgb_lcd;
fn main() -> Result<(), Box<dyn Error>> {
println!("Hello, LCD");
let mut display: grove_rgb_lcd::GroveRgbLcd = grove_rgb_lcd::connect()?;
println!("{:?}", display);
display.set_rgb((0x80, 0x00, 0x00))?; // red
display.set_text("FUBAR!\n@@snafu\nline1\nline2\n0123456789ABCDEF0123456789abcdef")?;
thread::sleep(time::Duration::from_millis(5000));
display.set_rgb((0x20, 0xA0, 0x40))?;
display.set_text("dunno what color this is")?;
thread::sleep(time::Duration::from_millis(5000));
display.set_rgb((0x00, 0x40, 0xFF))?;
display.set_text("now i'm bright BLUE - like my ballz!")?;
thread::sleep(time::Duration::from_millis(5000));
Ok(())
}