Add initial PoE HAT functionality

This commit is contained in:
NGnius (Graham) 2023-09-18 21:13:38 -04:00
commit d24076e804
11 changed files with 545 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
**/target

284
Cargo.lock generated Normal file
View file

@ -0,0 +1,284 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "anstream"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46"
[[package]]
name = "anstyle-parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1d7b8d5ec32af0fadc644bf1fd509a688c2103b185644bb1e29d164e0703136"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5179bb514e4d7c2051749d8fcefa2ed6d06a9f4e6d69faf3805f5d80b8cf8d56"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "i2cdev"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597f56d08cebc0fb3e67d49f48124f49e1c7ac297a21d60bc90a28b9482fb35c"
dependencies = [
"bitflags 2.4.0",
"byteorder",
"libc",
"nix",
]
[[package]]
name = "libc"
version = "0.2.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
[[package]]
name = "ng-sbc-tools"
version = "0.1.0"
dependencies = [
"clap",
"waveshare-poe-hat",
]
[[package]]
name = "nix"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
dependencies = [
"bitflags 1.3.2",
"cfg-if",
"libc",
]
[[package]]
name = "proc-macro2"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "2.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "waveshare-poe-hat"
version = "0.1.0"
dependencies = [
"i2cdev",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"

13
Cargo.toml Normal file
View file

@ -0,0 +1,13 @@
[package]
name = "ng-sbc-tools"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
# project (internal)
waveshare-poe-hat = { version = "0.1", path = "./waveshare-poe-hat" }
# external
clap = { version = "4.4", features = [ "derive" ] }

14
src/cli.rs Normal file
View file

@ -0,0 +1,14 @@
use clap::Parser;
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
pub struct Cli {
/// I2C port to use for display
pub port: u16,
}
impl Cli {
pub fn params() -> Self {
Self::parse()
}
}

29
src/main.rs Normal file
View file

@ -0,0 +1,29 @@
mod cli;
use waveshare_poe_hat::b::{BLACK, SSD1306, PCF8574};
fn main() {
let params = cli::Cli::params();
let mut display = SSD1306::new(params.port).expect("failed to open/init display");
let mut screen_buf = BLACK.clone();
let mut fan = PCF8574::new(params.port).expect("failed to open fan");
println!("Let's try some patterns!");
let mut pattern_count: usize = 0;
loop {
if (pattern_count >> 4) % 2 == 0 {
fan.disable().expect("Failed to disable fan");
} else {
fan.enable().expect("Failed to enable fan");
}
for pixel_i in 0..screen_buf.len() {
let cur_pixel = screen_buf[pixel_i];
screen_buf[pixel_i] = (((pixel_i ^ pattern_count) << (pattern_count % 7)) as u8) ^ cur_pixel << (pattern_count % 5) ^ cur_pixel >> (cur_pixel % 5);
//let height = pixel_i / 128;
//screen_buf[pixel_i] = (((pattern_count >> 3) % 4 == height) as u8) << (pattern_count % 8);
}
println!("Displaying pattern #{}", pattern_count);
display.image(&screen_buf).expect("Error displaying pattern");
std::thread::sleep(std::time::Duration::from_millis(100));
pattern_count += 1;
}
}

63
waveshare-poe-hat/Cargo.lock generated Normal file
View file

@ -0,0 +1,63 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "i2cdev"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597f56d08cebc0fb3e67d49f48124f49e1c7ac297a21d60bc90a28b9482fb35c"
dependencies = [
"bitflags 2.4.0",
"byteorder",
"libc",
"nix",
]
[[package]]
name = "libc"
version = "0.2.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
[[package]]
name = "nix"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
dependencies = [
"bitflags 1.3.2",
"cfg-if",
"libc",
]
[[package]]
name = "waveshare-poe-hat"
version = "0.1.0"
dependencies = [
"i2cdev",
]

View file

@ -0,0 +1,11 @@
[package]
name = "waveshare-poe-hat"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
#linux-embedded-hal = { version = "0.3" }
#embedded-hal = { version = "0.2" }
i2cdev = { version = "0.6" }

View file

@ -0,0 +1,88 @@
use i2cdev::core::I2CDevice;
use i2cdev::linux::{LinuxI2CDevice, LinuxI2CError};
const ADDRESS: u16 = 0x3C;
const SCREEN_WIDTH: u8 = 128;
const SCREEN_HEIGHT: u8 = 32;
type ScreenBuf = [u8; SCREEN_HEIGHT as usize * SCREEN_WIDTH as usize];
pub const ALL_WHITE: ScreenBuf = [0xff; SCREEN_HEIGHT as usize * SCREEN_WIDTH as usize];
pub const ALL_BLACK: ScreenBuf = [0x00; SCREEN_HEIGHT as usize * SCREEN_WIDTH as usize];
pub struct SSD1306 {
smbus: LinuxI2CDevice,
}
impl SSD1306 {
pub fn new(port: u16) -> Result<Self, LinuxI2CError> {
let smbus = LinuxI2CDevice::new(format!("/dev/i2c-{}", port), ADDRESS)?;
let mut new_self = Self { smbus };
new_self.init()?;
Ok(new_self)
}
fn command(&mut self, data: u8) -> Result<(), LinuxI2CError> {
self.smbus.smbus_write_byte_data(0x00, data)
}
fn data(&mut self, data: &[u8]) -> Result<(), LinuxI2CError> {
self.smbus.smbus_write_block_data(0x40, data)
}
fn init(&mut self) -> Result<(), LinuxI2CError> {
self.command(0xAE)?;
self.command(0x40)?; // set low column address
self.command(0xB0)?; // set high column address
// horizontal init
self.command(0xC8)?; // not offset
self.command(0x81)?;
self.command(0xff)?;
self.command(0xa1)?;
self.command(0xa6)?;
self.command(0xa8)?;
self.command(0x1f)?;
self.command(0xd3)?;
self.command(0x00)?;
self.command(0xd5)?;
self.command(0xf0)?;
self.command(0xd9)?;
self.command(0x22)?;
self.command(0xda)?;
self.command(0x02)?;
self.command(0xdb)?;
self.command(0x49)?;
self.command(0x8d)?;
self.command(0x14)?;
self.command(0xaf)?;
Ok(())
}
pub fn image(&mut self, buf: &ScreenBuf) -> Result<(), LinuxI2CError> {
for i in 0..SCREEN_HEIGHT/8 {
self.command(0xB0 + i)?; // set page address
self.command(0x00)?; // set low column address
self.command(0x10)?; // set high column address
let line = &buf[(SCREEN_WIDTH as usize * i as usize) .. (SCREEN_WIDTH as usize * (i as usize + 1))];
for chunk in line.chunks(32) {
self.data(chunk)?;
}
}
Ok(())
}
}

View file

@ -0,0 +1,25 @@
use i2cdev::core::I2CDevice;
use i2cdev::linux::{LinuxI2CDevice, LinuxI2CError};
const ADDRESS: u16 = 0x20;
pub struct PCF8574 {
smbus: LinuxI2CDevice,
}
impl PCF8574 {
pub fn new(port: u16) -> Result<Self, LinuxI2CError> {
let smbus = LinuxI2CDevice::new(format!("/dev/i2c-{}", port), ADDRESS)?;
Ok(Self { smbus })
}
pub fn enable(&mut self) -> Result<(), LinuxI2CError> {
let read = self.smbus.smbus_read_byte()?;
self.smbus.smbus_write_byte(0xFE & read)
}
pub fn disable(&mut self) -> Result<(), LinuxI2CError> {
let read = self.smbus.smbus_read_byte()?;
self.smbus.smbus_write_byte(0x01 | read)
}
}

View file

@ -0,0 +1,5 @@
mod display;
mod fan;
pub use display::{SSD1306, ALL_BLACK as BLACK, ALL_WHITE as WHITE};
pub use fan::PCF8574;

View file

@ -0,0 +1,11 @@
pub mod b;
#[cfg(test)]
mod tests {
//use super::*;
#[test]
fn it_works() {
assert_eq!(1+1, 2);
}
}