commit d24076e804571c12bf4c65a852f36550b12e08cb Author: NGnius (Graham) Date: Mon Sep 18 21:13:38 2023 -0400 Add initial PoE HAT functionality diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..74f7873 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +**/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..6aa0690 --- /dev/null +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a502e9e --- /dev/null +++ b/Cargo.toml @@ -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" ] } diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..593604d --- /dev/null +++ b/src/cli.rs @@ -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() + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..92ed328 --- /dev/null +++ b/src/main.rs @@ -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; + } +} diff --git a/waveshare-poe-hat/Cargo.lock b/waveshare-poe-hat/Cargo.lock new file mode 100644 index 0000000..9d4e3cf --- /dev/null +++ b/waveshare-poe-hat/Cargo.lock @@ -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", +] diff --git a/waveshare-poe-hat/Cargo.toml b/waveshare-poe-hat/Cargo.toml new file mode 100644 index 0000000..3892cb9 --- /dev/null +++ b/waveshare-poe-hat/Cargo.toml @@ -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" } diff --git a/waveshare-poe-hat/src/b/display.rs b/waveshare-poe-hat/src/b/display.rs new file mode 100644 index 0000000..c9e3e35 --- /dev/null +++ b/waveshare-poe-hat/src/b/display.rs @@ -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 { + 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(()) + } +} diff --git a/waveshare-poe-hat/src/b/fan.rs b/waveshare-poe-hat/src/b/fan.rs new file mode 100644 index 0000000..1f35e97 --- /dev/null +++ b/waveshare-poe-hat/src/b/fan.rs @@ -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 { + 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) + } +} diff --git a/waveshare-poe-hat/src/b/mod.rs b/waveshare-poe-hat/src/b/mod.rs new file mode 100644 index 0000000..5e616c5 --- /dev/null +++ b/waveshare-poe-hat/src/b/mod.rs @@ -0,0 +1,5 @@ +mod display; +mod fan; + +pub use display::{SSD1306, ALL_BLACK as BLACK, ALL_WHITE as WHITE}; +pub use fan::PCF8574; diff --git a/waveshare-poe-hat/src/lib.rs b/waveshare-poe-hat/src/lib.rs new file mode 100644 index 0000000..60dfab5 --- /dev/null +++ b/waveshare-poe-hat/src/lib.rs @@ -0,0 +1,11 @@ +pub mod b; + +#[cfg(test)] +mod tests { + //use super::*; + + #[test] + fn it_works() { + assert_eq!(1+1, 2); + } +}