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:
2023-07-19 18:09:13 +00:00
committed by Zachary Sunforge
parent 886fbf0020
commit 6fc828e864
40 changed files with 2079 additions and 44 deletions

View 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

View File

@ -0,0 +1,4 @@
#![no_std]
#![feature(async_fn_in_trait, impl_trait_projections)]
pub mod standard;

View File

@ -0,0 +1,2 @@
#[cfg(feature = "standard-multiplexer")]
pub mod multiplexer;

View File

@ -0,0 +1,4 @@
mod sync;
#[cfg(feature = "embassy-sync")]
pub use sync::*;

View File

@ -0,0 +1,2 @@
#[cfg(feature = "poll")]
pub mod poll;

View File

@ -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)
}
}