Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into feature/serial-settin…
Browse files Browse the repository at this point in the history
…gs-release

* origin/main:
  signal_generator -> source
  serial-settings: manifest fields
  bump ad9959, fix gitignores
  v0.10.0 prep
  style
  stream_target -> stream, livestream -> stream
  comments/docs update (clippy), add thermostat-eem stream id
  • Loading branch information
jordens committed Aug 28, 2024
2 parents 74ee2e1 + 3c7da0c commit fe927ca
Show file tree
Hide file tree
Showing 18 changed files with 77 additions and 85 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
/target
/dsp/target
vpy/
/py/build
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased](https://github.com/quartiq/stabilizer/compare/v0.9.0...main)
## [v0.10.0](https://github.com/quartiq/stabilizer/compare/v0.9.0...v0.10.0)

### Added
* Serial terminal is available on USB for settings configurations
Expand All @@ -29,7 +29,7 @@ console.
### Fixed
* Fixed an issue where the device would sometimes not enumerate on Windows

## [0.9.0](https://github.com/quartiq/stabilizer/compare/v0.8.1...v0.9.0)
## [v0.9.0](https://github.com/quartiq/stabilizer/compare/v0.8.1...v0.9.0)

### Fixed

Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "stabilizer"
# Keep versions in Cargo.toml and py/setup.py synchronized.
version = "0.9.0"
version = "0.10.0"
resolver = "2"
authors = [
"Robert Jördens <[email protected]>",
Expand All @@ -16,7 +16,6 @@ readme = "README.md"
documentation = "https://docs.rs/stabilizer/"
edition = "2021"
exclude = [
".gitignore",
"doc/",
"doc/*"
]
Expand Down Expand Up @@ -50,7 +49,7 @@ embedded-hal = "0.2.7"
num_enum = { version = "0.7.3", default-features = false }
paste = "1"
idsp = "0.15.1"
ad9959 = { path = "ad9959", version = "0.2.1" }
ad9959 = { path = "ad9959", version = "0.3.0" }
serial-settings = { version = "0.1", path = "serial-settings" }
mcp230xx = "1.0"
mutex-trait = "0.2"
Expand Down
2 changes: 1 addition & 1 deletion ad9959/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ad9959"
version = "0.2.1"
version = "0.3.0"
authors = ["Ryan Summers <[email protected]>"]
license = "MIT OR Apache-2.0"
edition = "2018"
Expand Down
17 changes: 6 additions & 11 deletions book/src/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,12 @@ form `dt/sinara/<app>/<mac-address>`, where `<app>` is the name of the applicati
Settings have a `path` and a `value` being configured. The `value` parameter is JSON-encoded data
and the `path` value is a path-like string.

As an example, for configuring `dual-iir`'s `stream_target`, the following information would be
used:
* `path` = `stream_target`
* `value` = `{"ip": [192, 168, 0, 1], "port": 4000}`

```
python -m miniconf --broker 10.34.16.1 dt/sinara/dual-iir/00-11-22-33-44-55 stream_target='{"ip": [10, 34, 16, 123], "port": 4000}'
Where `10.34.16.1` is the MQTT broker address that matches the one configured in the source code and `10.34.16.123` and `4000` are the desire stream target IP and port.
python -m miniconf --broker 10.34.16.1 dt/sinara/dual-iir/00-11-22-33-44-55 stream='"10.34.16.123:4000"'
```

Where `10.34.16.1` is the MQTT broker address that matches the one used by the application and `10.34.16.123` and `4000` are the desire stream target IP and port.

The prefix can be found for a specific device by looking at the topic on which telemetry that is
being published. It can also be automatically discovered if there is only one
device alive.
Expand Down Expand Up @@ -111,13 +106,13 @@ digital input states.

Refer to the respective [application documentation](overview.md#applications) for more information on telemetry.

# Livestream
# Stream

Stabilizer supports livestream capabilities for streaming real-time data over UDP. The livestream is
Stabilizer supports streaming real-time data over UDP. The stream is
intended to be a high-bandwidth mechanism to transfer large amounts of data from Stabilizer to a
host computer for further analysis.

Livestreamed data is sent with "best effort" - it's possible that data may be lost either due to
Streamed data is sent with "best effort" - it's possible that data may be lost either due to
network congestion or by Stabilizer.

Refer to the the respective [application documentation](overview.md#applications) for more information.
2 changes: 1 addition & 1 deletion hitl/loopback.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ async def test_loopback(stabilizer, telemetry_queue, set_point, gain=1, channel=
await stabilizer.set(f"/iir_ch/{channel}/0", static_iir_output(set_point))

# Configure signal generators to not affect the test.
await stabilizer.set("/signal_generator/0/amplitude", 0)
await stabilizer.set("/source/0/amplitude", 0)

# Wait for telemetry to update.
await telemetry_queue.__anext__()
Expand Down
2 changes: 1 addition & 1 deletion hitl/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,5 @@ python3 -m stabilizer.iir_coefficients -p $PREFIX -c 0 -v pid --Ki 10 --Kp 1
# Test the ADC/DACs connected via loopback.
python3 hitl/loopback.py $PREFIX

# Test the livestream capabilities
# Test the stream capabilities
python3 hitl/streaming.py $PREFIX
6 changes: 3 additions & 3 deletions hitl/streaming.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/python3
"""HITL testing of Stabilizer data livestream capabilities"""
"""HITL testing of Stabilizer data stream capabilities"""

import asyncio
import logging
Expand Down Expand Up @@ -58,7 +58,7 @@ async def _main():
args.ip = get_local_ip(args.broker)

logger.info("Starting stream")
await conf.set("/stream_target", f"{args.ip}:{args.port}", retain=False)
await conf.set("/stream", f"{args.ip}:{args.port}", retain=False)

try:
logger.info("Testing stream reception")
Expand All @@ -70,7 +70,7 @@ async def _main():
raise RuntimeError("High frame loss", loss)
finally:
logger.info("Stopping stream")
await conf.set("/stream_target", "0.0.0.0:0", retain=False)
await conf.set("/stream", "0.0.0.0:0", retain=False)

logger.info("Draining queue")
await asyncio.sleep(0.1)
Expand Down
2 changes: 1 addition & 1 deletion py/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Stabilizer Python Utilities

This directory contains common Python utilities for Stabilizer, such as livestream data receivers.
This directory contains common Python utilities for Stabilizer, such as stream data receivers.

To install this module locally (in editable mode):
```
Expand Down
2 changes: 1 addition & 1 deletion py/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ text = "MIT"
[project]
name = "stabilizer"
# Note: keep this in sync with Cargo.toml
version = "0.9.0"
version = "0.10.0"
description = "Utilities for configuring Stabilizer"
authors = [
{ name = "Robert Jördens", email = "[email protected]" },
Expand Down
2 changes: 1 addition & 1 deletion serial-settings/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ name = "serial-settings"
version = "0.1.0"
edition = "2021"
readme = "README.md"
description = "Embedded device settings management over serial terminal and flash"
authors = [
"Robert Jördens <[email protected]>",
"Ryan Summers <[email protected]>",
]
description = "Persistent settings management over serial interfaces"
categories = ["embedded", "no-std", "config", "command-line-interface"]
license = "MIT OR Apache-2.0"
keywords = ["serial", "settings", "cli", "management", "async"]
Expand Down
2 changes: 2 additions & 0 deletions serial-settings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -601,8 +601,10 @@ impl<'a, P: Platform<Y>, const Y: usize> Runner<'a, P, Y> {
/// # Args
/// * `platform` - The platform associated with the serial settings, providing the necessary
/// context and API to manage device settings.
///
/// * `line_buf` - A buffer used for maintaining the serial menu input line. It should be at
/// least as long as the longest user input.
///
/// * `serialize_buf` - A buffer used for serializing and deserializing settings. This buffer
/// needs to be at least as big as twice the biggest serialized setting plus its path.
pub fn new(
Expand Down
51 changes: 24 additions & 27 deletions src/bin/dual-iir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
//! ## Telemetry
//! Refer to [Telemetry] for information about telemetry reported by this application.
//!
//! ## Livestreaming
//! ## Stream
//! This application streams raw ADC and DAC data over UDP. Refer to
//! [stabilizer::net::data_stream](../stabilizer/net/data_stream/index.html) for more information.
#![no_std]
Expand Down Expand Up @@ -159,26 +159,26 @@ pub struct DualIir {
/// Any non-zero value less than 65536.
telemetry_period: u16,

/// Specifies the target for data livestreaming.
/// Specifies the target for data streaming.
///
/// # Path
/// `stream_target`
/// `stream`
///
/// # Value
/// See [StreamTarget#miniconf]
stream_target: StreamTarget,
stream: StreamTarget,

/// Specifies the config for signal generators to add on to DAC0/DAC1 outputs.
///
/// # Path
/// `signal_generator/<n>`
/// `source/<n>`
///
/// * `<n>` specifies which channel to configure. `<n>` := [0, 1]
///
/// # Value
/// See [signal_generator::BasicConfig#miniconf]
#[tree(depth = 2)]
signal_generator: [signal_generator::BasicConfig; 2],
source: [signal_generator::BasicConfig; 2],
}

impl Default for DualIir {
Expand All @@ -188,7 +188,7 @@ impl Default for DualIir {
i.set_max(SCALE);
Self {
// Analog frontend programmable gain amplifier gains (G1, G2, G5, G10)
afe: [Gain::G1, Gain::G1],
afe: Default::default(),
// IIR filter tap gains are an array `[b0, b1, b2, a1, a2]` such that the
// new output is computed as `y0 = a1*y1 + a2*y2 + b0*x0 + b1*x1 + b2*x2`.
// The array is `iir_state[channel-index][cascade-index][coeff-index]`.
Expand All @@ -203,9 +203,9 @@ impl Default for DualIir {
// The default telemetry period in seconds.
telemetry_period: 10,

signal_generator: [signal_generator::BasicConfig::default(); 2],
source: Default::default(),

stream_target: StreamTarget::default(),
stream: Default::default(),
}
}
}
Expand All @@ -221,7 +221,7 @@ mod app {
settings: Settings,
active_settings: DualIir,
telemetry: TelemetryBuffer,
signal_generator: [SignalGenerator; 2],
source: [SignalGenerator; 2],
}

#[local]
Expand Down Expand Up @@ -266,14 +266,14 @@ mod app {
network,
active_settings: stabilizer.settings.dual_iir.clone(),
telemetry: TelemetryBuffer::default(),
signal_generator: [
source: [
SignalGenerator::new(
stabilizer.settings.dual_iir.signal_generator[0]
stabilizer.settings.dual_iir.source[0]
.try_into_config(SAMPLE_PERIOD, DacCode::FULL_SCALE)
.unwrap(),
),
SignalGenerator::new(
stabilizer.settings.dual_iir.signal_generator[1]
stabilizer.settings.dual_iir.source[1]
.try_into_config(SAMPLE_PERIOD, DacCode::FULL_SCALE)
.unwrap(),
),
Expand Down Expand Up @@ -332,13 +332,13 @@ mod app {
///
/// Because the ADC and DAC operate at the same rate, these two constraints actually implement
/// the same time bounds, meeting one also means the other is also met.
#[task(binds=DMA1_STR4, local=[digital_inputs, adcs, dacs, iir_state, generator], shared=[active_settings, signal_generator, telemetry], priority=3)]
#[task(binds=DMA1_STR4, local=[digital_inputs, adcs, dacs, iir_state, generator], shared=[active_settings, source, telemetry], priority=3)]
#[link_section = ".itcm.process"]
fn process(c: process::Context) {
let process::SharedResources {
active_settings,
telemetry,
signal_generator,
source,
..
} = c.shared;

Expand All @@ -351,8 +351,8 @@ mod app {
..
} = c.local;

(active_settings, telemetry, signal_generator).lock(
|settings, telemetry, signal_generator| {
(active_settings, telemetry, source).lock(
|settings, telemetry, source| {
let digital_inputs =
[digital_inputs.0.is_high(), digital_inputs.1.is_high()];
telemetry.digital_inputs = digital_inputs;
Expand All @@ -371,7 +371,7 @@ mod app {
adc_samples[channel]
.iter()
.zip(dac_samples[channel].iter_mut())
.zip(&mut signal_generator[channel])
.zip(&mut source[channel])
.map(|((ai, di), signal)| {
let x = f32::from(*ai as i16);
let y = settings.iir_ch[channel]
Expand Down Expand Up @@ -400,7 +400,7 @@ mod app {
}

// Stream the data.
const N: usize = BATCH_SIZE * core::mem::size_of::<i16>();
const N: usize = BATCH_SIZE * size_of::<i16>();
generator.add(|buf| {
for (data, buf) in adc_samples
.iter()
Expand Down Expand Up @@ -458,20 +458,18 @@ mod app {
}
}

#[task(priority = 1, local=[afes], shared=[network, settings, active_settings, signal_generator])]
#[task(priority = 1, local=[afes], shared=[network, settings, active_settings, source])]
async fn settings_update(mut c: settings_update::Context) {
c.shared.settings.lock(|settings| {
c.local.afes.0.set_gain(settings.dual_iir.afe[0]);
c.local.afes.1.set_gain(settings.dual_iir.afe[1]);

// Update the signal generators
for (i, &config) in
settings.dual_iir.signal_generator.iter().enumerate()
{
for (i, &config) in settings.dual_iir.source.iter().enumerate() {
match config.try_into_config(SAMPLE_PERIOD, DacCode::FULL_SCALE)
{
Ok(config) => {
c.shared.signal_generator.lock(|generator| {
c.shared.source.lock(|generator| {
generator[i].update_waveform(config)
});
}
Expand All @@ -485,7 +483,7 @@ mod app {

c.shared
.network
.lock(|net| net.direct_stream(settings.dual_iir.stream_target));
.lock(|net| net.direct_stream(settings.dual_iir.stream));

c.shared
.active_settings
Expand All @@ -496,8 +494,7 @@ mod app {
#[task(priority = 1, shared=[network, settings, telemetry], local=[cpu_temp_sensor])]
async fn telemetry(mut c: telemetry::Context) {
loop {
let telemetry: TelemetryBuffer =
c.shared.telemetry.lock(|telemetry| *telemetry);
let telemetry = c.shared.telemetry.lock(|telemetry| *telemetry);

let (gains, telemetry_period) =
c.shared.settings.lock(|settings| {
Expand Down
Loading

0 comments on commit fe927ca

Please sign in to comment.