use std::fs::File;
use std::io::{BufReader, BufRead};
use std::result;
const BCM2708_PERIPHERAL_BASE: u32 = 0x20000000;
const BCM2709_PERIPHERAL_BASE: u32 = 0x3f000000;
const GPIO_OFFSET: u32 = 0x200000;
quick_error! {
#[derive(Debug)]
pub enum Error {
UnknownSoC { description("unknown BCM SoC") }
UnknownModel { description("unknown Raspberry Pi model") }
CantAccessProcCPUInfo { description("can't access /proc/cpuinfo") }
}
}
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug, PartialEq)]
pub enum Model {
RaspberryPiA,
RaspberryPiAPlus,
RaspberryPiB,
RaspberryPiBPlus,
RaspberryPi2B,
RaspberryPi3B,
RaspberryPiCompute,
RaspberryPiZero,
Unknown,
}
#[derive(Debug, PartialEq)]
pub enum SoC {
BCM2835,
BCM2836,
BCM2837,
}
pub struct System {
pub model: Model,
pub soc: SoC,
pub peripheral_base: u32,
pub gpio_offset: u32,
}
impl System {
pub fn new() -> Result<System> {
let proc_cpuinfo = BufReader::new(match File::open("/proc/cpuinfo") {
Err(_) => return Err(Error::CantAccessProcCPUInfo),
Ok(file) => file,
});
let mut hardware: String = String::new();
let mut revision: String = String::new();
for line_result in proc_cpuinfo.lines() {
if let Some(line) = line_result.ok() {
if line.starts_with("Hardware\t: ") {
hardware = String::from(&line[11..]);
} else if line.starts_with("Revision\t: ") {
revision = String::from(&line[11..]);
}
}
}
match &hardware[..] {
"BCM2708" | "BCM2709" | "BCM2835" | "BCM2836" | "BCM2837" => {}
_ => return Err(Error::UnknownSoC),
}
let mut model = Model::Unknown;
if revision.len() >= 6 {
model = match &revision[revision.len() - 3..revision.len() - 1] {
"00" => Model::RaspberryPiA,
"01" => Model::RaspberryPiB,
"02" => Model::RaspberryPiAPlus,
"03" => Model::RaspberryPiBPlus,
"04" => Model::RaspberryPi2B,
"06" => Model::RaspberryPiCompute,
"08" => Model::RaspberryPi3B,
"09" => Model::RaspberryPiZero,
_ => Model::Unknown,
};
} else if revision.len() == 4 {
model = match &revision[..] {
"0007" | "0008" | "0009" => Model::RaspberryPiA,
"0002" | "0003" | "0004" | "0005" | "0006" | "000d" | "000e" | "000f" => {
Model::RaspberryPiB
}
"0012" => Model::RaspberryPiAPlus,
"0010" | "0013" => Model::RaspberryPiBPlus,
"0011" => Model::RaspberryPiCompute,
_ => Model::Unknown,
};
}
match model {
Model::RaspberryPiA |
Model::RaspberryPiAPlus |
Model::RaspberryPiB |
Model::RaspberryPiBPlus |
Model::RaspberryPiCompute |
Model::RaspberryPiZero => {
Ok(System {
model: model,
soc: SoC::BCM2835,
peripheral_base: BCM2708_PERIPHERAL_BASE,
gpio_offset: GPIO_OFFSET,
})
}
Model::RaspberryPi2B => {
Ok(System {
model: model,
soc: SoC::BCM2836,
peripheral_base: BCM2709_PERIPHERAL_BASE,
gpio_offset: GPIO_OFFSET,
})
}
Model::RaspberryPi3B => {
Ok(System {
model: model,
soc: SoC::BCM2837,
peripheral_base: BCM2709_PERIPHERAL_BASE,
gpio_offset: GPIO_OFFSET,
})
}
_ => Err(Error::UnknownModel),
}
}
}