quartiq / stabilizer

Firmware and software for the Sinara Stabilizer module with high speed, low latency ADC/DAC data processing and powerful DSP algorithms in between
http://quartiq.de/stabilizer/
Apache License 2.0
111 stars 27 forks source link

streaming #150

Closed jordens closed 3 years ago

jordens commented 4 years ago

forked from #54 details in #99 and #147

dnadlinger commented 3 years ago

Some notes on a MVP streaming implementation (which I may or may not get around to actually doing):

jordens commented 3 years ago

Yeah. With that I was able to stream timestamps plus four channels at ~50 Mb/s over TCP with room to spare. I let the queue/frame granularity be the data of a single process invocation, i.e. batch. And the packaging was done by TCP. With UDP you'd want to concatenate a few. I'm uncertain how much of this can and should be made configurable at runtime (other than stream target and on/off) and whether all that configuration can be represented in the header. You certainly want to get a full description of the payload every now and then.

Old rotten patch ```diff diff --git a/Cargo.toml b/Cargo.toml index 8626796..ccbd7c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ cortex-m-log = { version = "0.5", features = ["log-integration"] } log = "0.4" panic-abort = "0.3" panic-semihosting = { version = "0.5.2", optional = true } +heapless = { version = "0.4", features = ["const-fn"] } [dependencies.stm32h7] path = "../stm32-rs/stm32h7" diff --git a/src/main.rs b/src/main.rs index 8ffc57f..9508bda 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,11 +14,11 @@ extern crate log; use core::ptr; use core::cell::RefCell; -use core::fmt::Write; use core::sync::atomic::{AtomicU32, AtomicBool, Ordering}; use cortex_m_rt::{entry, exception}; use stm32h7::stm32h7x3::{self as stm32, Peripherals, CorePeripherals, interrupt}; use cortex_m::interrupt::Mutex; +use heapless::{consts::*, spsc::Queue}; use smoltcp as net; @@ -514,6 +514,7 @@ macro_rules! create_socket { ) } +static mut IIRLOG: Queue<[i16; 5], U512> = Queue::new(); #[entry] fn main() -> ! { @@ -648,11 +649,23 @@ fn main() -> ! { socket.listen(80).unwrap_or_else(|e| warn!("TCP listen error: {:?}", e)); } else if last != time && socket.can_send() { last = time; - let (x0, y0, x1, y1) = unsafe { - (IIR_STATE[0][0], IIR_STATE[0][2], IIR_STATE[1][0], IIR_STATE[1][2]) }; - writeln!(socket, "t={} x0={:.1} y0={:.1} x1={:.1} y1={:.1}", - time, x0, y0, x1, y1) - .unwrap_or_else(|e| warn!("TCP send error: {:?}", e)); + let mut c = unsafe { IIRLOG.split().1 }; + socket.send(|buf| { + let len = buf.len(); + let mut i = 0; + while i + 2*4 < len { + match c.dequeue() { + Some(d) => for v in d.iter() { + let v = v.to_le_bytes(); + let l = v.len(); + buf[i..i + l].copy_from_slice(&v); + i += l; + }, + None => break + } + } + (i, ()) + }).ok().unwrap(); } } if !match iface.poll(&mut sockets, net::time::Instant::from_millis(time as i64)) { @@ -708,6 +721,11 @@ fn SPI1() { let txdr = &spi4.txdr as *const _ as *mut u16; unsafe { ptr::write_volatile(txdr, d) }; } + let time = TIME.load(Ordering::Relaxed); + let mut p = unsafe { IIRLOG.split().0 }; + p.enqueue(unsafe { + [time as i16, IIR_STATE[0][0] as i16, IIR_STATE[0][2] as i16, + IIR_STATE[1][0] as i16, IIR_STATE[1][2] as i16] }).ok(); }); #[cfg(feature = "bkpt")] cortex_m::asm::bkpt(); ```
jordens commented 3 years ago

Closed by #380 Follow-on improvements in #385 #386 etc