use std::error::Error;
use std::fmt;
use std::process;
use rpi_embedded::gpio::Gpio;
use rpi_embedded::system::{DeviceInfo, Model};
enum PinType {
Gpio(u8),
Ground,
Power3v3,
Power5v,
}
impl fmt::Display for PinType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
PinType::Gpio(pin) => write!(f, "GPIO{}", pin),
PinType::Ground => write!(f, "{:<5}", "GND"),
PinType::Power3v3 => write!(f, "{:<5}", "3.3 V"),
PinType::Power5v => write!(f, "{:<5}", "5 V"),
}
}
}
const HEADER: [PinType; 40] = [
PinType::Power3v3, PinType::Power5v, PinType::Gpio(2), PinType::Power5v, PinType::Gpio(3), PinType::Ground, PinType::Gpio(4), PinType::Gpio(14), PinType::Ground, PinType::Gpio(15), PinType::Gpio(17), PinType::Gpio(18), PinType::Gpio(27), PinType::Ground, PinType::Gpio(22), PinType::Gpio(23), PinType::Power3v3, PinType::Gpio(24), PinType::Gpio(10), PinType::Ground, PinType::Gpio(9), PinType::Gpio(25), PinType::Gpio(11), PinType::Gpio(8), PinType::Ground, PinType::Gpio(7), PinType::Gpio(0), PinType::Gpio(1), PinType::Gpio(5), PinType::Ground, PinType::Gpio(6), PinType::Gpio(12), PinType::Gpio(13), PinType::Ground, PinType::Gpio(19), PinType::Gpio(16), PinType::Gpio(26), PinType::Gpio(20), PinType::Ground, PinType::Gpio(21), ];
const MAX_PINS_SHORT: usize = 26;
const MAX_PINS_LONG: usize = 40;
fn format_pin(
buf: &mut String,
pin: usize,
gpio: impl fmt::Display,
mode: impl fmt::Display,
level: impl fmt::Display,
) {
if pin % 2 != 0 {
buf.push_str(&format!(
"| {:>4} | {:<5} | {:>1} | {:>2} |",
gpio, mode, level, pin
));
} else {
buf.push_str(&format!(
" {:>2} | {:>1} | {:<5} | {:>4} |\n",
pin, level, mode, gpio
));
}
}
fn print_header(header: &[PinType]) -> Result<(), Box<dyn Error>> {
let gpio = Gpio::new()?;
let mut buf = String::with_capacity(1600);
buf.push_str("+------+-------+---+---------+---+-------+------+\n");
buf.push_str("| GPIO | Mode | L | Pin | L | Mode | GPIO |\n");
buf.push_str("+------+-------+---+----+----+---+-------+------+\n");
for (idx, pin_type) in header.iter().enumerate() {
match pin_type {
PinType::Gpio(bcm_gpio) => {
let pin = gpio.get(*bcm_gpio)?;
format_pin(
&mut buf,
idx + 1,
bcm_gpio,
format!("{}", pin.mode()).to_uppercase(),
pin.read() as u8,
);
}
_ => format_pin(&mut buf, idx + 1, "", pin_type, ""),
};
}
buf.push_str("+------+-------+---+----+----+---+-------+------+\n");
print!("{}", buf);
Ok(())
}
fn main() -> Result<(), Box<dyn Error>> {
match DeviceInfo::new()?.model() {
Model::RaspberryPiBRev1 => {
let mut header_rev1 = HEADER;
header_rev1[2] = PinType::Gpio(0);
header_rev1[4] = PinType::Gpio(1);
header_rev1[12] = PinType::Gpio(21);
print_header(&header_rev1[..MAX_PINS_SHORT])
}
Model::RaspberryPiA | Model::RaspberryPiBRev2 => print_header(&HEADER[..MAX_PINS_SHORT]),
Model::RaspberryPiAPlus
| Model::RaspberryPiBPlus
| Model::RaspberryPi2B
| Model::RaspberryPi3APlus
| Model::RaspberryPi3B
| Model::RaspberryPi3BPlus
| Model::RaspberryPi4B
| Model::RaspberryPiZero
| Model::RaspberryPiZeroW => print_header(&HEADER[..MAX_PINS_LONG]),
model => {
eprintln!("Error: No GPIO header information available for {}", model);
process::exit(1);
}
}
}