Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions drmemd/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use tracing::{error, field, info, info_span, warn, Instrument};

mod counter;
mod cycle;
mod integrate;
mod latch;
mod map;
mod memory;
Expand Down Expand Up @@ -175,6 +176,19 @@ impl<R: Reporter> DriverDb<R> {
);
}

{
use integrate::Instance;

table.insert(
Instance::NAME.into(),
(
Instance::SUMMARY,
Instance::DESCRIPTION,
manage_instance::<Instance, R>,
),
);
}

{
use latch::Instance;

Expand Down
5 changes: 5 additions & 0 deletions drmemd/src/driver/integrate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod config;
mod device;
mod driver;

pub use driver::Instance;
12 changes: 12 additions & 0 deletions drmemd/src/driver/integrate/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use drmem_api::{driver::DriverConfig, Error};

#[derive(serde::Deserialize)]
pub struct Params;

impl TryFrom<DriverConfig> for Params {
type Error = Error;

fn try_from(_cfg: DriverConfig) -> std::result::Result<Self, Self::Error> {
Ok(Params)
}
}
44 changes: 44 additions & 0 deletions drmemd/src/driver/integrate/device.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use drmem_api::{
device::Path,
driver::{self, Reporter, ResettableState},
Result,
};

use super::config;

pub struct Set<R: Reporter> {
pub d_sum: driver::ReadOnlyDevice<f64, R>,
pub d_data: driver::ReadWriteDevice<f64, R>,
pub d_reset: driver::ReadWriteDevice<bool, R>,
}

impl<R: Reporter> driver::Registrator<R> for Set<R> {
type Config = config::Params;

async fn register_devices(
core: &mut driver::RequestChan<R>,
subpath: Option<&Path>,
_cfg: &Self::Config,
max_history: Option<usize>,
) -> Result<Self> {
// Define the devices managed by this driver.

let d_sum = core
.add_ro_device("sum", subpath, None, max_history)
.await?;
let d_data = core
.add_rw_device("data", subpath, None, max_history)
.await?;
let d_reset = core
.add_rw_device("reset", subpath, None, max_history)
.await?;

Ok(Set {
d_sum,
d_data,
d_reset,
})
}
}

impl<R: Reporter> ResettableState for Set<R> {}
122 changes: 122 additions & 0 deletions drmemd/src/driver/integrate/driver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use drmem_api::{
driver::{self, Reporter},
Result,
};
use std::convert::Infallible;

use super::{config, device};

// The state of a driver instance.

pub enum Instance {
Primed(f64),
Reset(f64),
}

impl Instance {
pub const NAME: &'static str = "integrate";

pub const SUMMARY: &'static str = "Accumulates values that have occurred";

pub const DESCRIPTION: &'static str = include_str!("drv_integrate.md");

/// Creates a new, idle `Instance`.
pub fn new() -> Instance {
Instance::Primed(0.0)
}

pub fn accumulate(&mut self, val: f64) {
match self {
Instance::Primed(v) | Instance::Reset(v) => *v = *v + val,
}
}

pub fn reset(&mut self, val: bool) -> bool {
match self {
Instance::Primed(_) => {
if val {
*self = Instance::Reset(0.0);
true
} else {
false
}
}
Instance::Reset(v) => {
if !val {
*self = Instance::Primed(*v);
true
} else {
false
}
}
}
}

pub fn get_sum(&self) -> f64 {
match self {
Instance::Primed(v) => *v,
Instance::Reset(v) => *v,
}
}
}

impl<R: Reporter> driver::API<R> for Instance {
type Config = config::Params;
type HardwareType = device::Set<R>;

async fn create_instance(_cfg: &Self::Config) -> Result<Box<Self>> {
Ok(Box::new(Instance::new()))
}

async fn run(&mut self, devices: &mut Self::HardwareType) -> Infallible {
devices.d_sum.report_update(self.get_sum()).await;

loop {
let mut report = true;

#[rustfmt::skip]
tokio::select! {
Some((b, reply)) = devices.d_data.next_setting() => {
reply.ok(b);
devices.d_data.report_update(b).await;
self.accumulate(b);
}
Some((b, reply)) = devices.d_reset.next_setting() => {
reply.ok(b);
devices.d_reset.report_update(b).await;
report = self.reset(b);
}
}

if report {
devices.d_sum.report_update(self.get_sum()).await
}
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_state_changes() {
let mut accum = Instance::new();

assert_eq!(accum.get_sum(), 0.0);
accum.accumulate(1.0);
assert_eq!(accum.get_sum(), 1.0);
accum.accumulate(2.0);
assert_eq!(accum.get_sum(), 3.0);
accum.reset(false);
assert_eq!(accum.get_sum(), 3.0);
accum.reset(true);
assert_eq!(accum.get_sum(), 0.0);
accum.accumulate(1.0);
assert_eq!(accum.get_sum(), 1.0);
accum.accumulate(2.0);
assert_eq!(accum.get_sum(), 3.0);
accum.reset(true);
assert_eq!(accum.get_sum(), 3.0);
}
}
23 changes: 23 additions & 0 deletions drmemd/src/driver/integrate/drv_integrate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# drmem-drv-integrate

Implements a floating point accumulator that sums every value applied to the `data` device. The `output` device reports the latest sum as a floating point value. `data` accepts floating point values. Boolean values are converted to `0` and `1`. When the `reset` device is set to `true`, the sum is reset to `0.0`.

This driver is always available in DrMem.

## Configuration

This driver has no configuration parameters.

## Devices

The driver creates these devices:

| Base Name | Type | Units | Comment |
|-----------|----------|-------|--------------------------------------------------------|
| `data` | float, RW | | Value is added to sum. |
| `reset` | bool, RW | | A `false` to `true` transition resets the sum to 0. |
| `output` | float, RO | | The current sum. |

## History

Added in v0.8.0.