diff --git a/src/args.rs b/src/args.rs index fff65ea..de05e6d 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,8 +1,5 @@ use clap::Parser; -// Size of EDID binary block -pub const BLOCK_SIZE: usize = 128; - fn hex_address(a: &str) -> Result { u16::from_str_radix(a.trim_start_matches("0x"), 16) } @@ -18,7 +15,7 @@ pub struct Args { #[arg(short, long, default_value = "0x50", value_parser = hex_address)] pub address: u16, - /// Number of 128-byte blocks to read, defaults to reading the base block. - #[arg(short, long, default_value_t = 1)] - pub blocks: usize, + /// Number of 128-byte blocks to read, defaults to autodetect from data + #[arg(short, long, default_value = None)] + pub blocks: Option, } diff --git a/src/bin/edidread.rs b/src/bin/edidread.rs index d8bf505..13ad739 100644 --- a/src/bin/edidread.rs +++ b/src/bin/edidread.rs @@ -1,16 +1,18 @@ use clap::Parser; use rwedid::args::*; use rwedid::i2c::*; -use std::io::{self, Write}; +use rwedid::misc::*; +use rwedid::std::*; fn main() -> Result<(), std::io::Error> { // Parse command line arguments let args = Args::parse(); // Read the data from the chip - let bytes = read_from_bus(&args.device, args.address, BLOCK_SIZE * args.blocks)?; + let bytes = block_by_block_read(args.blocks, |o, l| { + read_from_bus(&args.device, args.address, o, l) + })?; // Write binary blob to stdout - let mut stdout = io::stdout().lock(); - stdout.write_all(&bytes) + write_to_std(&bytes) } diff --git a/src/bin/edidwrite.rs b/src/bin/edidwrite.rs index 7a5285c..0777320 100644 --- a/src/bin/edidwrite.rs +++ b/src/bin/edidwrite.rs @@ -1,18 +1,15 @@ use clap::Parser; use rwedid::args::*; use rwedid::i2c::*; -use std::io::{self, Read}; +use rwedid::misc::*; +use rwedid::std::*; fn main() -> Result<(), std::io::Error> { // Parse command line arguments let args = Args::parse(); // Read binary from stdin - let data_length = args.blocks * BLOCK_SIZE; - let mut data = vec![0; data_length]; - - // Read binary blob from stdin - io::stdin().read_exact(data.as_mut_slice())?; + let data = block_by_block_read(args.blocks, |_, l| read_from_std(l))?; // Write the data to the chip write_to_bus(&args.device, args.address, data.as_slice()) diff --git a/src/i2c.rs b/src/i2c.rs index b2d8938..ba87bc5 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -7,6 +7,7 @@ use std::time::Duration; pub fn read_from_bus( i2c_device: &str, slave_address: u16, + memory_address: u8, data_length: usize, ) -> Result, std::io::Error> { let mut data = vec![0; data_length]; @@ -14,7 +15,7 @@ pub fn read_from_bus( let mut dev = LinuxI2CDevice::new(i2c_device, slave_address)?; let mut msgs = [ // Address to read from - LinuxI2CMessage::write(&[0x00]), + LinuxI2CMessage::write(&[memory_address]), // Read data into buffer LinuxI2CMessage::read(&mut data), ]; @@ -34,9 +35,8 @@ pub fn write_to_bus( // Write 8 bytes at a time for (i, chunk) in data.chunks_exact(8).into_iter().enumerate() { - // Memory address - let memory_address : u8 = (i as u8) * 8; + let memory_address: u8 = (i as u8) * 8; let mut msgs = [ // Address to write to LinuxI2CMessage::write(&[memory_address]), @@ -47,7 +47,7 @@ pub fn write_to_bus( dev.transfer(&mut msgs)?; thread::sleep(Duration::from_millis(20)); - }; + } Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 3acbfe0..918188e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,4 @@ pub mod args; pub mod i2c; +pub mod misc; +pub mod std; diff --git a/src/misc.rs b/src/misc.rs new file mode 100644 index 0000000..7876574 --- /dev/null +++ b/src/misc.rs @@ -0,0 +1,31 @@ +// Size of EDID binary block +pub const BLOCK_SIZE: usize = 128; + +pub fn block_by_block_read( + blocks: Option, + read: impl Fn(u8, usize) -> Result, std::io::Error>, +) -> Result, std::io::Error> { + match blocks { + // Default: autodetect number of extension blocks + None => { + // Read first block (128 bytes) + let data_base = read(0x00, BLOCK_SIZE)?; + // Try to read remaining bytes + let data_extensions = match data_base.len() { + // Proper 128 byte block + BLOCK_SIZE => { + // Number of extension blocks that should follow + let num_extensions: usize = data_base[BLOCK_SIZE - 2].into(); + // Read remaining blocks + read(BLOCK_SIZE as u8, num_extensions * BLOCK_SIZE)? + } + // Something else, obviously broken + _ => vec![], + }; + // Return complete byte stream + Ok([data_base, data_extensions].concat()) + } + // Explicitly read as many blocks as specified by user + Some(blocks) => read(0x00, blocks * BLOCK_SIZE), + } +} diff --git a/src/std.rs b/src/std.rs new file mode 100644 index 0000000..7b8e8bd --- /dev/null +++ b/src/std.rs @@ -0,0 +1,15 @@ +use std::io::{self, Read, Write}; + +pub fn read_from_std(data_length: usize) -> Result, std::io::Error> { + // Buffer to read into + let mut data = vec![0; data_length]; + // Read from stdin + io::stdin().read_exact(data.as_mut_slice())?; + Ok(data) +} + +pub fn write_to_std(data: &[u8]) -> Result<(), std::io::Error> { + // Write data to stdout + let mut stdout = io::stdout().lock(); + stdout.write_all(&data) +}