Initial node implementation (#4)
Reviewed-on: #4 Co-authored-by: Zack <zack@bfpower.io> Co-committed-by: Zack <zack@bfpower.io>
This commit is contained in:
31
peripheral-components/ads1256/node/Cargo.toml
Normal file
31
peripheral-components/ads1256/node/Cargo.toml
Normal file
@ -0,0 +1,31 @@
|
||||
[package]
|
||||
name = "physical-ads1256"
|
||||
description = "Shared node abstractions for ADS1256 components."
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
repository.workspace = true
|
||||
readme.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[features]
|
||||
embassy-sync = ["dep:embassy-sync", "ads1256/embassy-sync", "physical-node/embassy-sync"]
|
||||
poll = ["standard-multiplexer", "embassy-sync"]
|
||||
standard-multiplexer = []
|
||||
|
||||
[dependencies.physical-node]
|
||||
path = "../../../node"
|
||||
[dependencies.node-poll-variants]
|
||||
path = "../../../macros/node-poll-variants"
|
||||
[dependencies.ads1256]
|
||||
workspace = true
|
||||
[dependencies.embedded-hal]
|
||||
workspace = true
|
||||
[dependencies.embedded-hal-async]
|
||||
workspace = true
|
||||
[dependencies.defmt]
|
||||
workspace = true
|
||||
[dependencies.uom]
|
||||
workspace = true
|
||||
[dependencies.embassy-sync]
|
||||
workspace = true
|
||||
optional = true
|
4
peripheral-components/ads1256/node/src/lib.rs
Normal file
4
peripheral-components/ads1256/node/src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
||||
#![no_std]
|
||||
#![feature(async_fn_in_trait, impl_trait_projections)]
|
||||
|
||||
pub mod standard;
|
2
peripheral-components/ads1256/node/src/standard/mod.rs
Normal file
2
peripheral-components/ads1256/node/src/standard/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
#[cfg(feature = "standard-multiplexer")]
|
||||
pub mod multiplexer;
|
@ -0,0 +1,4 @@
|
||||
mod sync;
|
||||
|
||||
#[cfg(feature = "embassy-sync")]
|
||||
pub use sync::*;
|
@ -0,0 +1,2 @@
|
||||
#[cfg(feature = "poll")]
|
||||
pub mod poll;
|
@ -0,0 +1,382 @@
|
||||
use ads1256::{
|
||||
AdControl, Ads1256, BlockingDelay, DataRate, Gain, Multiplexer, OutputPin, SpiBus, Status, Wait,
|
||||
};
|
||||
use core::ops::DerefMut;
|
||||
use embassy_sync::blocking_mutex::raw::RawMutex;
|
||||
use embassy_sync::mutex::Mutex;
|
||||
use node_poll_variants::PollVariants;
|
||||
use physical_node::transducer::input::Poll;
|
||||
use physical_node::CriticalError;
|
||||
use uom::si::f32;
|
||||
|
||||
#[derive(PollVariants)]
|
||||
#[value_type = "f32::ElectricPotential"]
|
||||
#[error_type = "CriticalError"]
|
||||
pub struct AutocalPoll<'a, DeviceMutexT, ModInT, DelayerT, SST, DrdyT, SpiT>
|
||||
where
|
||||
DeviceMutexT: RawMutex,
|
||||
ModInT: ModInput,
|
||||
DelayerT: BlockingDelay,
|
||||
SST: OutputPin,
|
||||
DrdyT: Wait,
|
||||
SpiT: SpiBus,
|
||||
{
|
||||
input_mod: ModInT,
|
||||
ads1256: &'a Mutex<DeviceMutexT, Ads1256<DelayerT, SST, DrdyT>>,
|
||||
spi: &'a Mutex<DeviceMutexT, SpiT>,
|
||||
}
|
||||
|
||||
impl<'a, DeviceMutexT, ModInT, DelayerT, SST, DrdyT, SpiT>
|
||||
AutocalPoll<'a, DeviceMutexT, ModInT, DelayerT, SST, DrdyT, SpiT>
|
||||
where
|
||||
DeviceMutexT: RawMutex,
|
||||
ModInT: ModInput,
|
||||
DelayerT: BlockingDelay,
|
||||
SST: OutputPin,
|
||||
DrdyT: Wait,
|
||||
SpiT: SpiBus,
|
||||
{
|
||||
#[inline(always)]
|
||||
pub fn new(
|
||||
input_mod: ModInT,
|
||||
ads1256: &'a Mutex<DeviceMutexT, Ads1256<DelayerT, SST, DrdyT>>,
|
||||
spi: &'a Mutex<DeviceMutexT, SpiT>,
|
||||
) -> Self {
|
||||
Self {
|
||||
input_mod,
|
||||
ads1256,
|
||||
spi,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, DeviceMutexT, ModInT, DelayerT, SST, DrdyT, SpiT> Poll
|
||||
for AutocalPoll<'a, DeviceMutexT, ModInT, DelayerT, SST, DrdyT, SpiT>
|
||||
where
|
||||
DeviceMutexT: RawMutex,
|
||||
ModInT: ModInput,
|
||||
DelayerT: BlockingDelay,
|
||||
SST: OutputPin,
|
||||
DrdyT: Wait,
|
||||
SpiT: SpiBus,
|
||||
{
|
||||
type Value = f32::ElectricPotential;
|
||||
type Error = CriticalError;
|
||||
|
||||
async fn poll(&self) -> Result<Self::Value, CriticalError> {
|
||||
let mut ads1256_guard = self.ads1256.lock().await;
|
||||
let ads1256 = ads1256_guard.deref_mut();
|
||||
//TODO: ADS1256 documentation seems to say we should be waiting for drdy low after
|
||||
// issuing standby command but it never goes low.
|
||||
|
||||
let result = ads1256
|
||||
.autocal_convert_m(
|
||||
self.spi,
|
||||
self.input_mod.multiplexer(),
|
||||
self.input_mod.status(),
|
||||
self.input_mod.ad_control(),
|
||||
self.input_mod.data_rate(),
|
||||
true,
|
||||
)
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(conversion) => Ok(conversion.to_voltage(self.input_mod.gain())),
|
||||
Err(_) => Err(CriticalError::Communication),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ModInput: Copy {
|
||||
fn multiplexer(self) -> Multiplexer;
|
||||
|
||||
fn gain(self) -> Gain;
|
||||
|
||||
fn status(self) -> Option<Status>;
|
||||
|
||||
fn ad_control(self) -> Option<AdControl>;
|
||||
|
||||
fn data_rate(self) -> Option<DataRate>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub struct ModInputOnly {
|
||||
pub multiplexer: Multiplexer,
|
||||
/// Only used for converting to voltage, this value must match what is set on the ADS1256, it
|
||||
/// will not *be* set unlike the other fields.
|
||||
pub gain: Gain,
|
||||
}
|
||||
|
||||
impl ModInput for ModInputOnly {
|
||||
fn multiplexer(self) -> Multiplexer {
|
||||
self.multiplexer
|
||||
}
|
||||
|
||||
fn gain(self) -> Gain {
|
||||
self.gain
|
||||
}
|
||||
|
||||
fn status(self) -> Option<Status> {
|
||||
None
|
||||
}
|
||||
|
||||
fn ad_control(self) -> Option<AdControl> {
|
||||
None
|
||||
}
|
||||
|
||||
fn data_rate(self) -> Option<DataRate> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// buffer
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub struct ModInStatus {
|
||||
pub multiplexer: Multiplexer,
|
||||
/// Only used for converting to voltage, this value must match what is set on the ADS1256, it
|
||||
/// will not *be* set unlike the other fields.
|
||||
pub gain: Gain,
|
||||
pub status: Status,
|
||||
}
|
||||
|
||||
impl ModInput for ModInStatus {
|
||||
#[inline(always)]
|
||||
fn multiplexer(self) -> Multiplexer {
|
||||
self.multiplexer
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn gain(self) -> Gain {
|
||||
self.gain
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn status(self) -> Option<Status> {
|
||||
Some(self.status)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ad_control(self) -> Option<AdControl> {
|
||||
None
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn data_rate(self) -> Option<DataRate> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// gain
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub struct ModInAdControl {
|
||||
pub multiplexer: Multiplexer,
|
||||
pub ad_control: AdControl,
|
||||
}
|
||||
|
||||
impl ModInput for ModInAdControl {
|
||||
#[inline(always)]
|
||||
fn multiplexer(self) -> Multiplexer {
|
||||
self.multiplexer
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn gain(self) -> Gain {
|
||||
self.ad_control.gain()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn status(self) -> Option<Status> {
|
||||
None
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ad_control(self) -> Option<AdControl> {
|
||||
Some(self.ad_control)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn data_rate(self) -> Option<DataRate> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// data rate
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub struct ModInDataRate {
|
||||
pub multiplexer: Multiplexer,
|
||||
/// Only used for converting to voltage, this value must match what is set on the ADS1256, it
|
||||
/// will not *be* set unlike the other fields.
|
||||
pub gain: Gain,
|
||||
pub data_rate: DataRate,
|
||||
}
|
||||
|
||||
impl ModInput for ModInDataRate {
|
||||
#[inline(always)]
|
||||
fn multiplexer(self) -> Multiplexer {
|
||||
self.multiplexer
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn gain(self) -> Gain {
|
||||
self.gain
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn status(self) -> Option<Status> {
|
||||
None
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ad_control(self) -> Option<AdControl> {
|
||||
None
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn data_rate(self) -> Option<DataRate> {
|
||||
Some(self.data_rate)
|
||||
}
|
||||
}
|
||||
|
||||
/// buffer, gain
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub struct ModInStatAdc {
|
||||
pub multiplexer: Multiplexer,
|
||||
pub status: Status,
|
||||
pub ad_control: AdControl,
|
||||
}
|
||||
|
||||
impl ModInput for ModInStatAdc {
|
||||
#[inline(always)]
|
||||
fn multiplexer(self) -> Multiplexer {
|
||||
self.multiplexer
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn gain(self) -> Gain {
|
||||
self.ad_control.gain()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn status(self) -> Option<Status> {
|
||||
Some(self.status)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ad_control(self) -> Option<AdControl> {
|
||||
Some(self.ad_control)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn data_rate(self) -> Option<DataRate> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// buffer, data rate
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub struct ModInStatDrate {
|
||||
pub multiplexer: Multiplexer,
|
||||
/// Only used for converting to voltage, this value must match what is set on the ADS1256, it
|
||||
/// will not *be* set unlike the other fields.
|
||||
pub gain: Gain,
|
||||
pub status: Status,
|
||||
pub data_rate: DataRate,
|
||||
}
|
||||
|
||||
impl ModInput for ModInStatDrate {
|
||||
#[inline(always)]
|
||||
fn multiplexer(self) -> Multiplexer {
|
||||
self.multiplexer
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn gain(self) -> Gain {
|
||||
self.gain
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn status(self) -> Option<Status> {
|
||||
Some(self.status)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ad_control(self) -> Option<AdControl> {
|
||||
None
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn data_rate(self) -> Option<DataRate> {
|
||||
Some(self.data_rate)
|
||||
}
|
||||
}
|
||||
|
||||
// gain, data rate
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub struct ModInAdcDrate {
|
||||
pub multiplexer: Multiplexer,
|
||||
pub ad_control: AdControl,
|
||||
pub data_rate: DataRate,
|
||||
}
|
||||
|
||||
impl ModInput for ModInAdcDrate {
|
||||
#[inline(always)]
|
||||
fn multiplexer(self) -> Multiplexer {
|
||||
self.multiplexer
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn gain(self) -> Gain {
|
||||
self.ad_control.gain()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn status(self) -> Option<Status> {
|
||||
None
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ad_control(self) -> Option<AdControl> {
|
||||
Some(self.ad_control)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn data_rate(self) -> Option<DataRate> {
|
||||
Some(self.data_rate)
|
||||
}
|
||||
}
|
||||
|
||||
/// buffer, gain, data rate
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub struct ModInAll {
|
||||
pub multiplexer: Multiplexer,
|
||||
pub status: Status,
|
||||
pub ad_control: AdControl,
|
||||
pub data_rate: DataRate,
|
||||
}
|
||||
|
||||
impl ModInput for ModInAll {
|
||||
#[inline(always)]
|
||||
fn multiplexer(self) -> Multiplexer {
|
||||
self.multiplexer
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn gain(self) -> Gain {
|
||||
self.ad_control.gain()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn status(self) -> Option<Status> {
|
||||
Some(self.status)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ad_control(self) -> Option<AdControl> {
|
||||
Some(self.ad_control)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn data_rate(self) -> Option<DataRate> {
|
||||
Some(self.data_rate)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user