Skip to content

Commit

Permalink
Cleaning up examples. Added timeouts to buffer examples.
Browse files Browse the repository at this point in the history
  • Loading branch information
fpagliughi committed Dec 28, 2019
1 parent 4c2430a commit 8b885ac
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 74 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ nix = "0.16"
schedule_recv = "0.1"
clap = "2.33"
chrono = "0.4"
ctrlc = "3.1"
62 changes: 41 additions & 21 deletions examples/riio_bufavg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@
#[macro_use] extern crate clap;
extern crate industrial_io as iio;
extern crate chrono;
extern crate ctrlc;

use std::process;
use std::{process, cmp};
use std::any::TypeId;
use std::time::{SystemTime, Duration, UNIX_EPOCH};
use std::thread::{spawn, JoinHandle};
use std::sync::mpsc::{channel, Sender, Receiver, SendError};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use clap::{Arg, App};
use chrono::offset::Utc;
use chrono::DateTime;
Expand All @@ -40,9 +43,9 @@ type RawSampleType = i16;
type TsDataBuffer = (u64, Vec<RawSampleType>);

// The defaults device and channel if none specified
const DFLT_DEV_NAME: &'static str = "ads1015";
const DFLT_CHAN_NAME: &'static str = "voltage0";
const DFLT_TRIG_NAME: &'static str = "trigger0";
const DFLT_DEV_NAME: &str = "ads1015";
const DFLT_CHAN_NAME: &str = "voltage0";
const DFLT_TRIG_NAME: &str = "trigger0";

const DFLT_FREQ: i64 = 100;
const DFLT_NUM_SAMPLE: usize = 100;
Expand Down Expand Up @@ -165,19 +168,19 @@ fn main() {
let chan_name = matches.value_of("channel").unwrap_or(DFLT_CHAN_NAME);
let trig_name = matches.value_of("trigger").unwrap_or(DFLT_TRIG_NAME);

let ctx = if let Some(hostname) = matches.value_of("host") {
iio::Context::create_network(hostname)
}
else if let Some(uri) = matches.value_of("uri") {
iio::Context::create_from_uri(uri)
}
else {
iio::Context::new()
}
.unwrap_or_else(|_err| {
println!("Couldn't open IIO context.");
process::exit(1);
});
let mut ctx = if let Some(hostname) = matches.value_of("host") {
iio::Context::create_network(hostname)
}
else if let Some(uri) = matches.value_of("uri") {
iio::Context::create_from_uri(uri)
}
else {
iio::Context::new()
}
.unwrap_or_else(|_err| {
println!("Couldn't open IIO context.");
process::exit(1);
});

let mut dev = ctx.find_device(dev_name).unwrap_or_else(|| {
println!("No IIO device named '{}'", dev_name);
Expand All @@ -202,8 +205,6 @@ fn main() {
process::exit(1);
});

//let dfmt = sample_chan.data_format();
//println!("Using channel: {} [{:?}]", chan_name, dfmt);
println!("Using channel: {}", chan_name);

if sample_chan.type_of() != Some(TypeId::of::<RawSampleType>()) {
Expand Down Expand Up @@ -256,14 +257,31 @@ fn main() {
process::exit(3);
});

// Make sure the timeout is more than enough to gather each buffer
// Give 50% extra time, or at least 5sec.
let ms = cmp::max(5000, 1500 * (n_sample as u64) / (freq as u64));
if let Err(err) = ctx.set_timeout_ms(ms) {
eprintln!("Error setting timeout of {}ms: {}", ms, err);
}

// ----- Create the averager -----

let avg = Averager::new(offset, scale);

// ---- Handle ^C since we want a graceful shutdown -----

let quit = Arc::new(AtomicBool::new(false));
let q = quit.clone();

ctrlc::set_handler(move || {
q.store(true, Ordering::SeqCst);
}).expect("Error setting Ctrl-C handler");

// ----- Capture data into the buffer -----

println!("Started capturing data...");
loop {

while !quit.load(Ordering::SeqCst) {
if let Err(err) = buf.refill() {
eprintln!("Error filling the buffer: {}", err);
break;
Expand All @@ -272,7 +290,7 @@ fn main() {
// Get the timestamp. Use the time of the _last_ sample.

let ts: u64 = if let Some(ref chan) = ts_chan {
buf.channel_iter::<u64>(chan).skip(n_sample-1).next().unwrap_or_default()
buf.channel_iter::<u64>(chan).nth(n_sample-1).unwrap_or_default()
}
else {
timestamp()
Expand Down Expand Up @@ -306,6 +324,8 @@ fn main() {

// ----- Shut down -----

println!("\nExiting...");
avg.quit();
println!("Done");
}

2 changes: 1 addition & 1 deletion examples/riio_free_scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use std::process;
use std::any::TypeId;
use clap::{Arg, App};

const DFLT_DEV_NAME: &'static str = "44e0d000.tscadc:adc";
const DFLT_DEV_NAME: &str = "44e0d000.tscadc:adc";

fn main() {
let matches = App::new("riio_free_scan")
Expand Down
121 changes: 74 additions & 47 deletions examples/riio_tsbuf.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// industrial-io/examples/riio_tsbuf.rs
//
// Simple Rust IIO example for time-stamped, buffered, reading.
// This does buffered reading with a trigger.
// Simple Rust IIO example for time-stamped, buffered, reading
// using a trigger.
//
// This example requires a A/D with a timestamp channel.
// This example requires a device with a timestamp channel.
//
// Copyright (c) 2018-2019, Frank Pagliughi
//
Expand All @@ -17,22 +17,28 @@
extern crate industrial_io as iio;
extern crate chrono;

use std::process;
use std::{process, cmp};
use std::time::{SystemTime, Duration};
use clap::{Arg, App};
use chrono::offset::Utc;
use chrono::DateTime;

const DFLT_DEV_NAME: &'static str = "ads1015";
const DFLT_CHAN_NAME: &'static str = "voltage0";
const DFLT_DEV_NAME: &str = "ads1015";
const DFLT_CHAN_NAME: &str = "voltage0";
const DFLT_TRIG_NAME: &str = "trigger0";

const DFLT_FREQ: i64 = 100;
const DFLT_NUM_SAMPLE: usize = 100;

// --------------------------------------------------------------------------

fn main() {
let matches = App::new("riio_tsbuf")
.version(crate_version!())
.about("Rust IIO timestamped buffered read example.")
.arg(Arg::with_name("network")
.short("n")
.long("network")
.arg(Arg::with_name("host")
.short("h")
.long("host")
.help("Use the network backend with the provided hostname")
.takes_value(true))
.arg(Arg::with_name("uri")
Expand All @@ -50,24 +56,40 @@ fn main() {
.long("channel")
.help("Specifies the name of the channel to read")
.takes_value(true))
.arg(Arg::with_name("trigger")
.short("t")
.long("trigger")
.help("Specifies the name of the trigger")
.takes_value(true))
.arg(Arg::with_name("num_sample")
.short("n")
.long("num_sample")
.help("Specifies the number of samples per buffer")
.takes_value(true))
.arg(Arg::with_name("frequency")
.short("f")
.long("frequency")
.help("Specifies the sampling frequency")
.takes_value(true))
.get_matches();

let dev_name = matches.value_of("device").unwrap_or(DFLT_DEV_NAME);
let chan_name = matches.value_of("chan").unwrap_or(DFLT_CHAN_NAME);

let ctx = if let Some(hostname) = matches.value_of("network") {
iio::Context::create_network(hostname)
}
else if let Some(uri) = matches.value_of("uri") {
iio::Context::create_from_uri(uri)
}
else {
iio::Context::new()
}
.unwrap_or_else(|_err| {
println!("Couldn't open IIO context.");
process::exit(1);
});
let trig_name = matches.value_of("trigger").unwrap_or(DFLT_TRIG_NAME);

let mut ctx = if let Some(hostname) = matches.value_of("host") {
iio::Context::create_network(hostname)
}
else if let Some(uri) = matches.value_of("uri") {
iio::Context::create_from_uri(uri)
}
else {
iio::Context::new()
}
.unwrap_or_else(|_err| {
println!("Couldn't open IIO context.");
process::exit(1);
});

let mut dev = ctx.find_device(dev_name).unwrap_or_else(|| {
println!("No IIO device named '{}'", dev_name);
Expand All @@ -89,22 +111,20 @@ fn main() {
ts_chan.enable();
sample_chan.enable();

println!("Sample size: {}", dev.sample_size().unwrap());

// ----- Set a trigger -----

// TODO: Make this a cmd-line option
const TRIGGER: &'static str = "trigger0";
const RATE_HZ: i64 = 100;

let trig = ctx.find_device(TRIGGER).unwrap_or_else(|| {
eprintln!("Couldn't find requested trigger: {}", TRIGGER);
let trig = ctx.find_device(trig_name).unwrap_or_else(|| {
eprintln!("Couldn't find requested trigger: {}", trig_name);
process::exit(1);
});

let freq = matches.value_of("frequency")
.and_then(|s| s.parse::<i64>().ok())
.unwrap_or(DFLT_FREQ);

// Set the sampling rate
if let Err(err) = trig.attr_write_int("sampling_frequency", RATE_HZ) {
println!("Can't set sampling rate: {}", err);
if let Err(err) = trig.attr_write_int("sampling_frequency", freq) {
println!("Can't set sampling rate to {}Hz: {}", freq, err);
}

dev.set_trigger(&trig).unwrap_or_else(|err| {
Expand All @@ -114,11 +134,22 @@ fn main() {

// ----- Create a buffer -----

let mut buf = dev.create_buffer(200, false).unwrap_or_else(|err| {
let n_sample = matches.value_of("num_sample")
.and_then(|s| s.parse::<usize>().ok())
.unwrap_or(DFLT_NUM_SAMPLE);

let mut buf = dev.create_buffer(n_sample, false).unwrap_or_else(|err| {
eprintln!("Unable to create buffer: {}", err);
process::exit(3);
});

// Make sure the timeout is more than enough to gather each buffer
// Give 50% extra time, or at least 5sec.
let ms = cmp::max(5000, 1500 * (n_sample as u64) / (freq as u64));
if let Err(err) = ctx.set_timeout_ms(ms) {
eprintln!("Error setting timeout of {}ms: {}", ms, err);
}

// ----- Capture data into the buffer -----

println!("Capturing a buffer...");
Expand All @@ -129,21 +160,17 @@ fn main() {

// Extract and print the data

let mut ts_data = buf.channel_iter::<u64>(&ts_chan);
let ts_data = buf.channel_iter::<u64>(&ts_chan);
let mut sample_data = buf.channel_iter::<u16>(&sample_chan);

loop {
// Get the next timestamp. It's represented as the 64-bit integer
// number of nanoseconds since the Unix Epoch. We convert to a
// Rust SystemTime, then a chrono DataTime for pretty printing.
if let Some(ts) = ts_data.next() {
let sys_tm = SystemTime::UNIX_EPOCH + Duration::from_nanos(ts);
let dt: DateTime<Utc> = sys_tm.into();
print!("[{}]: ", dt.format("%T%.6f"));
}
else {
break;
}
for ts in ts_data {
// The timestamp is represented as a 64-bit integer number of
// nanoseconds since the Unix Epoch. We convert to a Rust SystemTime,
// then a chrono DataTime for pretty printing.
let sys_tm = SystemTime::UNIX_EPOCH + Duration::from_nanos(ts);
let dt: DateTime<Utc> = sys_tm.into();
print!("{}: ", dt.format("%T%.6f"));

if let Some(val) = sample_data.next() {
print!("{}", val);
}
Expand Down
17 changes: 12 additions & 5 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,17 +170,24 @@ impl Context {
/// Sets the timeout for I/O operations
///
/// `timeout` The timeout. A value of zero specifies that no timeout
/// should be used.
/// should be used.
pub fn set_timeout(&mut self, timeout: Duration) -> Result<()> {
let timeout_ms: u64 = 1000 * timeout.as_secs() + u64::from(timeout.subsec_millis());
let ret = unsafe { ffi::iio_context_set_timeout(self.inner.ctx, timeout_ms as c_uint) };
let ms: u64 = 1000 * timeout.as_secs() + u64::from(timeout.subsec_millis());
self.set_timeout_ms(ms)
}

/// Sets the timeout for I/O operations, in milliseconds
///
/// `timeout` The timeout, in ms. A value of zero specifies that no
/// timeout should be used.
pub fn set_timeout_ms(&mut self, ms: u64) -> Result<()> {
let ret = unsafe { ffi::iio_context_set_timeout(self.inner.ctx, ms as c_uint) };
sys_result(ret, ())
}

/// Get the number of devices in the context
pub fn num_devices(&self) -> usize {
let n = unsafe { ffi::iio_context_get_devices_count(self.inner.ctx) };
n as usize
unsafe { ffi::iio_context_get_devices_count(self.inner.ctx) as usize }
}

/// Gets a device by index
Expand Down

0 comments on commit 8b885ac

Please sign in to comment.