cleans up lifetimes and ownership
This commit is contained in:
25
Cargo.lock
generated
25
Cargo.lock
generated
@@ -85,6 +85,12 @@ version = "0.8.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "critical-section"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embedded-hal"
|
name = "embedded-hal"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
@@ -101,6 +107,16 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
|
checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-hal-bus"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "513e0b3a8fb7d3013a8ae17a834283f170deaf7d0eeab0a7c1a36ad4dd356d22"
|
||||||
|
dependencies = [
|
||||||
|
"critical-section",
|
||||||
|
"embedded-hal 1.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embedded-hal-mock"
|
name = "embedded-hal-mock"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
@@ -243,13 +259,14 @@ dependencies = [
|
|||||||
"anyhow",
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
"embedded-hal 1.0.0",
|
"embedded-hal 1.0.0",
|
||||||
|
"embedded-hal-bus",
|
||||||
"embedded-hal-mock",
|
"embedded-hal-mock",
|
||||||
"fern",
|
"fern",
|
||||||
"hex",
|
"hex",
|
||||||
"log",
|
"log",
|
||||||
"nalgebra",
|
"nalgebra",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"rppal",
|
"rpi-pal",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -401,10 +418,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rppal"
|
name = "rpi-pal"
|
||||||
version = "0.22.1"
|
version = "0.22.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c1ce3b019009cff02cb6b0e96e7cc2e5c5b90187dc1a490f8ef1521d0596b026"
|
checksum = "aed1991fa7d497e81f82b7eac494ad7d1f58d3b5f7fd1a13e30867375dfbc553"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embedded-hal 0.2.7",
|
"embedded-hal 0.2.7",
|
||||||
"embedded-hal 1.0.0",
|
"embedded-hal 1.0.0",
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ fern = "0.7.1"
|
|||||||
log = "0.4.27"
|
log = "0.4.27"
|
||||||
chrono = "0.4.40"
|
chrono = "0.4.40"
|
||||||
embedded-hal = "1.0.0"
|
embedded-hal = "1.0.0"
|
||||||
|
embedded-hal-bus = { version = "0.3.0", features = ["std"] }
|
||||||
embedded-hal-mock = { version = "0.11.1", optional = true }
|
embedded-hal-mock = { version = "0.11.1", optional = true }
|
||||||
rppal = { version = "0.22.1", features = ["hal"], optional = true }
|
rpi-pal = { version = "0.22.2", features = ["hal"], optional = true }
|
||||||
nalgebra = "0.33.2"
|
nalgebra = "0.33.2"
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
thiserror = "2.0.12"
|
thiserror = "2.0.12"
|
||||||
@@ -20,5 +21,5 @@ num-traits = "0.2.19"
|
|||||||
embedded-hal-mock = { version = "0.11.1" }
|
embedded-hal-mock = { version = "0.11.1" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
raspi = ["dep:rppal"]
|
raspi = ["dep:rpi-pal"]
|
||||||
sim = ["dep:embedded-hal-mock"]
|
sim = ["dep:embedded-hal-mock"]
|
||||||
|
|||||||
@@ -1,15 +1,30 @@
|
|||||||
|
use std::fmt::{Debug, Formatter};
|
||||||
|
use std::time::Instant;
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use embedded_hal::i2c::I2c;
|
use embedded_hal::i2c::I2c;
|
||||||
|
use log::{info, trace};
|
||||||
use crate::hardware::error::I2cError;
|
use crate::hardware::error::I2cError;
|
||||||
|
|
||||||
pub struct Mcp23017<I2C> {
|
pub trait Mcp23017 {
|
||||||
|
fn init(&mut self) -> Result<()>;
|
||||||
|
fn set_pin(&mut self, pin: u8, value: bool) -> Result<()>;
|
||||||
|
fn flush(&mut self) -> Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Mcp23017Driver<I2C> {
|
||||||
i2c: I2C,
|
i2c: I2C,
|
||||||
address: u8,
|
address: u8,
|
||||||
bank: [u8; 2],
|
bank: [u8; 2],
|
||||||
dirty: bool,
|
dirty: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I2C> Mcp23017<I2C>
|
impl<I2C> Debug for Mcp23017Driver<I2C> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Mcp23017Driver {{ address: {} }}", self.address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I2C> Mcp23017Driver<I2C>
|
||||||
where
|
where
|
||||||
I2C: I2c,
|
I2C: I2c,
|
||||||
I2C::Error : Send,
|
I2C::Error : Send,
|
||||||
@@ -17,6 +32,7 @@ where
|
|||||||
I2C::Error : 'static
|
I2C::Error : 'static
|
||||||
{
|
{
|
||||||
pub fn new(i2c: I2C, address: u8) -> Self {
|
pub fn new(i2c: I2C, address: u8) -> Self {
|
||||||
|
trace!("Mcp23017Driver::new(i2c, address: {address:07b})");
|
||||||
Self {
|
Self {
|
||||||
i2c,
|
i2c,
|
||||||
address,
|
address,
|
||||||
@@ -24,12 +40,27 @@ where
|
|||||||
dirty: false,
|
dirty: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<I2C> Mcp23017 for Mcp23017Driver<I2C>
|
||||||
|
where
|
||||||
|
I2C: I2c,
|
||||||
|
I2C::Error : Send,
|
||||||
|
I2C::Error : Sync,
|
||||||
|
I2C::Error : 'static
|
||||||
|
{
|
||||||
|
fn init(&mut self) -> Result<()> {
|
||||||
|
trace!("Mcp23017Driver::init(self: {self:?})");
|
||||||
|
// Set each pin as an output (Addresses 0x00 & 0x01)
|
||||||
|
let data: [u8; _] = [0x00, 0x00, 0x00];
|
||||||
|
self.i2c.write(self.address, &data).map_err(I2cError)?;
|
||||||
|
|
||||||
pub fn init(&self) -> Result<()> {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_pin(&mut self, pin: u8, value: bool) -> Result<()> {
|
fn set_pin(&mut self, pin: u8, value: bool) -> Result<()> {
|
||||||
|
trace!("Mcp23017Driver::set_pin(self: {self:?}, pin: {pin}, value: {value})");
|
||||||
let (pin_bank, dirty_flag, pin_index) = match pin {
|
let (pin_bank, dirty_flag, pin_index) = match pin {
|
||||||
0..8 => {
|
0..8 => {
|
||||||
(&mut self.bank[0], &mut self.dirty, pin as u32)
|
(&mut self.bank[0], &mut self.dirty, pin as u32)
|
||||||
@@ -53,9 +84,11 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flush(&mut self) -> Result<()> {
|
fn flush(&mut self) -> Result<()> {
|
||||||
|
trace!("Mcp23017Driver::flush(self: {self:?})");
|
||||||
if self.dirty {
|
if self.dirty {
|
||||||
let data: [u8; _] = [0x12, self.bank[0], self.bank[1]];
|
let data: [u8; _] = [0x12, self.bank[0], self.bank[1]];
|
||||||
|
// This blocks while writing
|
||||||
self.i2c.write(self.address, &data).map_err(I2cError)?;
|
self.i2c.write(self.address, &data).map_err(I2cError)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
use embedded_hal::spi::{Operation, SpiDevice};
|
use std::fmt::{Debug, Formatter};
|
||||||
use anyhow::{ensure, Result};
|
|
||||||
use crate::hardware::error::SpiError;
|
use crate::hardware::error::SpiError;
|
||||||
|
use anyhow::{ensure, Result};
|
||||||
|
use embedded_hal::spi::SpiDevice;
|
||||||
|
use log::trace;
|
||||||
|
|
||||||
pub struct Mcp3208<SPI> {
|
pub struct Mcp3208<SPI> {
|
||||||
spi: SPI,
|
spi: SPI,
|
||||||
vref: f64
|
vref: f64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<SPI> Debug for Mcp3208<SPI> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Mcp3208 {{ vref: {} }}", self.vref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<SPI> Mcp3208<SPI>
|
impl<SPI> Mcp3208<SPI>
|
||||||
where
|
where
|
||||||
SPI : SpiDevice<u8>,
|
SPI : SpiDevice<u8>,
|
||||||
@@ -15,6 +23,7 @@ where
|
|||||||
SPI::Error : 'static,
|
SPI::Error : 'static,
|
||||||
{
|
{
|
||||||
pub fn new(spi: SPI, vref: f64) -> Self {
|
pub fn new(spi: SPI, vref: f64) -> Self {
|
||||||
|
trace!("Mcp3208::new(spi, vref: {vref})");
|
||||||
Self {
|
Self {
|
||||||
spi,
|
spi,
|
||||||
vref
|
vref
|
||||||
@@ -22,6 +31,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_single(&mut self, channel: u8) -> Result<f64> {
|
pub fn read_single(&mut self, channel: u8) -> Result<f64> {
|
||||||
|
trace!("Mcp3208::read_single(self: {self:?}, channel: {channel})");
|
||||||
ensure!(channel < 8, "Invalid Channel {channel}");
|
ensure!(channel < 8, "Invalid Channel {channel}");
|
||||||
|
|
||||||
// We don't care what the third byte written is
|
// We don't care what the third byte written is
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
|
use crate::hardware::mcp23017::Mcp23017;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use embedded_hal::i2c::I2c;
|
|
||||||
|
|
||||||
pub trait Hardware {
|
pub trait Hardware {
|
||||||
fn set_mcp0_pin(&self, pin: u8, value: bool) -> Result<()>;
|
|
||||||
|
fn get_mcp23017_a(&self) -> impl Mcp23017;
|
||||||
|
fn get_mcp23017_b(&self) -> impl Mcp23017;
|
||||||
|
|
||||||
fn get_battery_voltage(&self) -> Result<f64>;
|
fn get_battery_voltage(&self) -> Result<f64>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,5 +37,5 @@ mod bno085;
|
|||||||
mod imu;
|
mod imu;
|
||||||
mod error;
|
mod error;
|
||||||
|
|
||||||
mod mcp23017;
|
pub mod mcp23017;
|
||||||
mod mcp3208;
|
mod mcp3208;
|
||||||
|
|||||||
@@ -1,49 +1,52 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::sync::Mutex;
|
||||||
use crate::hardware::Hardware;
|
use crate::hardware::Hardware;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use embedded_hal::i2c::SevenBitAddress;
|
use embedded_hal_bus::i2c::MutexDevice;
|
||||||
use log::{debug, info};
|
use log::{debug, info, trace};
|
||||||
use rppal::gpio::Gpio;
|
// use rpi_pal::gpio::Gpio;
|
||||||
use rppal::i2c::I2c;
|
use rpi_pal::i2c::I2c;
|
||||||
use rppal::spi::{Bus, Mode, SlaveSelect, Spi};
|
use rpi_pal::spi::{Bus, Mode, SlaveSelect, Spi};
|
||||||
use crate::hardware::mcp23017::Mcp23017;
|
use crate::hardware::mcp23017::{Mcp23017, Mcp23017Driver};
|
||||||
use crate::hardware::mcp3208::Mcp3208;
|
use crate::hardware::mcp3208::Mcp3208;
|
||||||
use rppal::spi::SimpleHalSpiDevice;
|
use rpi_pal::spi::SimpleHalSpiDevice;
|
||||||
|
|
||||||
const CLOCK_1MHZ: u32 = 1_000_000;
|
const CLOCK_1MHZ: u32 = 1_000_000;
|
||||||
|
|
||||||
pub struct RaspiHardware {
|
pub struct RaspiHardware {
|
||||||
gpio: Gpio,
|
// gpio: Gpio,
|
||||||
mcp23017_a: RefCell<Mcp23017<I2c>>,
|
i2c_bus: Mutex<I2c>,
|
||||||
mcp3208: RefCell<Mcp3208<SimpleHalSpiDevice>>,
|
mcp3208: RefCell<Mcp3208<SimpleHalSpiDevice>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RaspiHardware {
|
impl RaspiHardware {
|
||||||
pub fn new() -> Result<Self> {
|
pub fn new() -> Result<Self> {
|
||||||
let device = rppal::system::DeviceInfo::new()?;
|
trace!("RaspiHardware::new()");
|
||||||
|
|
||||||
|
let device = rpi_pal::system::DeviceInfo::new()?;
|
||||||
info!("Running on {}", device.model());
|
info!("Running on {}", device.model());
|
||||||
debug!("SOC: {}", device.soc());
|
debug!("SOC: {}", device.soc());
|
||||||
|
|
||||||
let mut i2c = I2c::with_bus(1u8)?;
|
|
||||||
i2c.set_timeout(1000)?;
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
gpio: Gpio::new()?,
|
// gpio: Gpio::new()?,
|
||||||
mcp23017_a: Mcp23017::new(i2c, 0b0100000).into(),
|
i2c_bus: Mutex::new(I2c::with_bus(0u8)?),
|
||||||
mcp3208: Mcp3208::new(SimpleHalSpiDevice::new(Spi::new(
|
mcp3208: Mcp3208::new(SimpleHalSpiDevice::new(Spi::new(
|
||||||
Bus::Spi1,
|
Bus::Spi1,
|
||||||
SlaveSelect::Ss1,
|
SlaveSelect::Ss1,
|
||||||
CLOCK_1MHZ,
|
CLOCK_1MHZ,
|
||||||
Mode::Mode0,
|
Mode::Mode0,
|
||||||
)?), 3.3f64).into()
|
)?), 3.3f64).into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hardware for RaspiHardware {
|
impl Hardware for RaspiHardware {
|
||||||
fn set_mcp0_pin(&self, pin: u8, value: bool) -> Result<()> {
|
fn get_mcp23017_a(&self) -> impl Mcp23017 {
|
||||||
self.mcp23017_a.borrow_mut().set_pin(pin, value)?;
|
Mcp23017Driver::new(MutexDevice::new(&self.i2c_bus), 0b0100000)
|
||||||
self.mcp23017_a.borrow_mut().flush()
|
}
|
||||||
|
|
||||||
|
fn get_mcp23017_b(&self) -> impl Mcp23017 {
|
||||||
|
Mcp23017Driver::new(MutexDevice::new(&self.i2c_bus), 0b0100001)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_battery_voltage(&self) -> Result<f64> {
|
fn get_battery_voltage(&self) -> Result<f64> {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use crate::logger::setup_logger;
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use log::info;
|
use log::info;
|
||||||
use crate::hardware::Hardware;
|
use crate::hardware::Hardware;
|
||||||
|
use crate::hardware::mcp23017::Mcp23017;
|
||||||
|
|
||||||
mod hardware;
|
mod hardware;
|
||||||
mod logger;
|
mod logger;
|
||||||
@@ -18,14 +19,36 @@ pub fn run() -> Result<()> {
|
|||||||
|
|
||||||
let hal = initialize()?;
|
let hal = initialize()?;
|
||||||
|
|
||||||
for i in 0..100 {
|
let mut mcp23017_a = hal.get_mcp23017_a();
|
||||||
sleep(Duration::from_millis(1000));
|
let mut mcp23017_b = hal.get_mcp23017_b();
|
||||||
info!("Battery Voltage: {}", hal.get_battery_voltage()?);
|
|
||||||
}
|
|
||||||
|
|
||||||
// hal.set_mcp0_pin(15u8, true)?;
|
info!("Battery Voltage: {}", hal.get_battery_voltage()?);
|
||||||
// sleep(Duration::from_secs(1));
|
|
||||||
// hal.set_mcp0_pin(15u8, false)?;
|
mcp23017_a.init()?;
|
||||||
|
mcp23017_b.init()?;
|
||||||
|
|
||||||
|
mcp23017_a.set_pin(7u8, true)?;
|
||||||
|
mcp23017_a.flush()?;
|
||||||
|
|
||||||
|
sleep(Duration::from_secs(1));
|
||||||
|
|
||||||
|
mcp23017_b.set_pin(7u8, true)?;
|
||||||
|
mcp23017_b.flush()?;
|
||||||
|
|
||||||
|
sleep(Duration::from_secs(1));
|
||||||
|
|
||||||
|
mcp23017_a.set_pin(7u8, false)?;
|
||||||
|
mcp23017_a.flush()?;
|
||||||
|
|
||||||
|
sleep(Duration::from_secs(1));
|
||||||
|
|
||||||
|
mcp23017_b.set_pin(7u8, false)?;
|
||||||
|
mcp23017_b.flush()?;
|
||||||
|
|
||||||
|
// Explicitly drop these to allow the borrow checker to be sure that
|
||||||
|
// dropping the hal is safe
|
||||||
|
drop(mcp23017_a);
|
||||||
|
drop(mcp23017_b);
|
||||||
|
|
||||||
drop(hal);
|
drop(hal);
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use anyhow::Result;
|
|||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::create_dir_all;
|
use std::fs::create_dir_all;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use log::trace;
|
use log::debug;
|
||||||
|
|
||||||
pub fn setup_logger() -> Result<()> {
|
pub fn setup_logger() -> Result<()> {
|
||||||
let log_file = env::var("LOG_FILE").or_else(|_| {
|
let log_file = env::var("LOG_FILE").or_else(|_| {
|
||||||
@@ -37,6 +37,6 @@ pub fn setup_logger() -> Result<()> {
|
|||||||
.chain(fern::log_file(log_file.clone())?)
|
.chain(fern::log_file(log_file.clone())?)
|
||||||
.apply()?;
|
.apply()?;
|
||||||
|
|
||||||
trace!("Logging to {} at level {}", log_file, log_level);
|
debug!("Logging to {} at level {}", log_file, log_level);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user