Updating after refactor
This commit is contained in:
parent
4c27100c23
commit
8d4193ed62
|
@ -194,7 +194,7 @@ const APP: () = {
|
||||||
stabilizer.net.mac_address,
|
stabilizer.net.mac_address,
|
||||||
);
|
);
|
||||||
|
|
||||||
let generator = network.enable_streaming();
|
let generator = network.enable_streaming(StreamFormat::AdcDacData);
|
||||||
|
|
||||||
// Spawn a settings update for default settings.
|
// Spawn a settings update for default settings.
|
||||||
c.spawn.settings_update().unwrap();
|
c.spawn.settings_update().unwrap();
|
||||||
|
@ -308,43 +308,23 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stream the data.
|
// Stream the data.
|
||||||
generator.add::<_, { SAMPLE_BUFFER_SIZE * 8 }>(
|
const N: usize = SAMPLE_BUFFER_SIZE * core::mem::size_of::<u16>();
|
||||||
StreamFormat::AdcDacData,
|
generator.add::<_, { N * 4 }>(|buf| {
|
||||||
|buf| unsafe {
|
for (data, buf) in adc_samples
|
||||||
let dst = buf.as_ptr() as usize as *mut u16;
|
.iter()
|
||||||
|
.chain(dac_samples.iter())
|
||||||
let adc0 = &adc_samples[0][0] as *const u16;
|
.zip(buf.chunks_exact_mut(N))
|
||||||
core::ptr::copy_nonoverlapping(
|
{
|
||||||
adc0,
|
assert_eq!(core::mem::size_of_val(data), N);
|
||||||
dst,
|
let data = unsafe {
|
||||||
SAMPLE_BUFFER_SIZE,
|
core::slice::from_raw_parts(
|
||||||
);
|
data.as_ptr() as *const u8,
|
||||||
|
N,
|
||||||
let dst = dst.add(SAMPLE_BUFFER_SIZE);
|
)
|
||||||
let adc1 = &adc_samples[1][0] as *const u16;
|
};
|
||||||
core::ptr::copy_nonoverlapping(
|
buf.copy_from_slice(data)
|
||||||
adc1,
|
}
|
||||||
dst,
|
});
|
||||||
SAMPLE_BUFFER_SIZE,
|
|
||||||
);
|
|
||||||
|
|
||||||
let dst = dst.add(SAMPLE_BUFFER_SIZE);
|
|
||||||
let dac0 = &dac_samples[0][0] as *const u16;
|
|
||||||
core::ptr::copy_nonoverlapping(
|
|
||||||
dac0,
|
|
||||||
dst,
|
|
||||||
SAMPLE_BUFFER_SIZE,
|
|
||||||
);
|
|
||||||
|
|
||||||
let dst = dst.add(SAMPLE_BUFFER_SIZE);
|
|
||||||
let dac1 = &dac_samples[1][0] as *const u16;
|
|
||||||
core::ptr::copy_nonoverlapping(
|
|
||||||
dac1,
|
|
||||||
dst,
|
|
||||||
SAMPLE_BUFFER_SIZE,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Update telemetry measurements.
|
// Update telemetry measurements.
|
||||||
telemetry.adcs =
|
telemetry.adcs =
|
||||||
|
|
|
@ -231,7 +231,7 @@ const APP: () = {
|
||||||
stabilizer.net.mac_address,
|
stabilizer.net.mac_address,
|
||||||
);
|
);
|
||||||
|
|
||||||
let generator = network.enable_streaming();
|
let generator = network.enable_streaming(StreamFormat::AdcDacData);
|
||||||
|
|
||||||
let settings = Settings::default();
|
let settings = Settings::default();
|
||||||
|
|
||||||
|
@ -396,43 +396,23 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stream the data.
|
// Stream the data.
|
||||||
generator.add::<_, { SAMPLE_BUFFER_SIZE * 8 }>(
|
const N: usize = SAMPLE_BUFFER_SIZE * core::mem::size_of::<u16>();
|
||||||
StreamFormat::AdcDacData,
|
generator.add::<_, { N * 4 }>(|buf| {
|
||||||
|buf| unsafe {
|
for (data, buf) in adc_samples
|
||||||
let dst = buf.as_ptr() as usize as *mut u16;
|
.iter()
|
||||||
|
.chain(dac_samples.iter())
|
||||||
let adc0 = &adc_samples[0][0] as *const u16;
|
.zip(buf.chunks_exact_mut(N))
|
||||||
core::ptr::copy_nonoverlapping(
|
{
|
||||||
adc0,
|
assert_eq!(core::mem::size_of_val(data), N);
|
||||||
dst,
|
let data = unsafe {
|
||||||
SAMPLE_BUFFER_SIZE,
|
core::slice::from_raw_parts(
|
||||||
);
|
data.as_ptr() as *const u8,
|
||||||
|
N,
|
||||||
let dst = dst.add(SAMPLE_BUFFER_SIZE);
|
)
|
||||||
let adc1 = &adc_samples[1][0] as *const u16;
|
};
|
||||||
core::ptr::copy_nonoverlapping(
|
buf.copy_from_slice(data)
|
||||||
adc1,
|
}
|
||||||
dst,
|
});
|
||||||
SAMPLE_BUFFER_SIZE,
|
|
||||||
);
|
|
||||||
|
|
||||||
let dst = dst.add(SAMPLE_BUFFER_SIZE);
|
|
||||||
let dac0 = &dac_samples[0][0] as *const u16;
|
|
||||||
core::ptr::copy_nonoverlapping(
|
|
||||||
dac0,
|
|
||||||
dst,
|
|
||||||
SAMPLE_BUFFER_SIZE,
|
|
||||||
);
|
|
||||||
|
|
||||||
let dst = dst.add(SAMPLE_BUFFER_SIZE);
|
|
||||||
let dac1 = &dac_samples[1][0] as *const u16;
|
|
||||||
core::ptr::copy_nonoverlapping(
|
|
||||||
dac1,
|
|
||||||
dst,
|
|
||||||
SAMPLE_BUFFER_SIZE,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Update telemetry measurements.
|
// Update telemetry measurements.
|
||||||
telemetry.adcs =
|
telemetry.adcs =
|
||||||
|
|
|
@ -12,22 +12,21 @@
|
||||||
//! ## Header Format
|
//! ## Header Format
|
||||||
//! The header of each stream frame consists of 7 bytes. All data is stored in little-endian format.
|
//! The header of each stream frame consists of 7 bytes. All data is stored in little-endian format.
|
||||||
//!
|
//!
|
||||||
//! Elements appear sequentiall as follows:
|
//! Elements appear sequentially as follows:
|
||||||
//! * Sequence Number <u16>
|
//! * Magic word 0x057B <u16>
|
||||||
//! * Format Code <u16>
|
//! * Format Code <u8>
|
||||||
//! * Batch Count <16>
|
//! * Batch Size <u8>
|
||||||
//! * Batch size <u8>
|
//! * Sequence Number <u32>
|
||||||
//!
|
//!
|
||||||
//! The "Sequence Number" is an identifier that increments for ever execution of the DSP process.
|
//! The "Magic word" is a constant field for all packets. The value is alway 0x057B.
|
||||||
//! This can be used to determine if a stream frame was lost.
|
|
||||||
//!
|
//!
|
||||||
//! The "Format Code" is a unique specifier that indicates the serialization format of each batch of
|
//! The "Format Code" is a unique specifier that indicates the serialization format of each batch of
|
||||||
//! data in the frame. Refer to [StreamFormat] for further information.
|
//! data in the frame. Refer to [StreamFormat] for further information.
|
||||||
//!
|
//!
|
||||||
//! The "Batch Count" indicates how many batches are present in the current frame.
|
//! The "Batch size" is the value of [SAMPLE_BUFFER_SIZE].
|
||||||
//!
|
//!
|
||||||
//! The "Batch Size" specifies the [crate::hardware::design_parameters::SAMPLE_BUFFER_SIZE]
|
//! The "Sequence Number" is an identifier that increments for ever execution of the DSP process.
|
||||||
//! parameter, which can be used to determine the number of samples per batch.
|
//! This can be used to determine if a stream frame was lost.
|
||||||
//!
|
//!
|
||||||
//! # Example
|
//! # Example
|
||||||
//! A sample Python script is available in `scripts/stream_throughput.py` to demonstrate reception
|
//! A sample Python script is available in `scripts/stream_throughput.py` to demonstrate reception
|
||||||
|
@ -43,6 +42,10 @@ use heapless::pool::{Box, Init, Pool, Uninit};
|
||||||
|
|
||||||
use super::NetworkReference;
|
use super::NetworkReference;
|
||||||
|
|
||||||
|
const MAGIC_WORD: u16 = 0x057B;
|
||||||
|
|
||||||
|
const HEADER_SIZE: usize = 8;
|
||||||
|
|
||||||
// The number of frames that can be buffered.
|
// The number of frames that can be buffered.
|
||||||
const FRAME_COUNT: usize = 4;
|
const FRAME_COUNT: usize = 4;
|
||||||
|
|
||||||
|
@ -70,9 +73,12 @@ pub struct StreamTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies the format of streamed data
|
/// Specifies the format of streamed data
|
||||||
#[repr(u16)]
|
#[repr(u8)]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub enum StreamFormat {
|
pub enum StreamFormat {
|
||||||
|
/// Reserved, unused format specifier.
|
||||||
|
Unknown = 0,
|
||||||
|
|
||||||
/// Streamed data contains ADC0, ADC1, DAC0, and DAC1 sequentially in little-endian format.
|
/// Streamed data contains ADC0, ADC1, DAC0, and DAC1 sequentially in little-endian format.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
@ -80,7 +86,7 @@ pub enum StreamFormat {
|
||||||
/// ```
|
/// ```
|
||||||
/// <ADC0[0]> <ADC0[1]> <ADC1[0]> <ADC1[1]> <DAC0[0]> <DAC0[1]> <DAC1[0]> <DAC1[1]>
|
/// <ADC0[0]> <ADC0[1]> <ADC1[0]> <ADC1[1]> <DAC0[0]> <DAC0[1]> <DAC1[0]> <DAC1[1]>
|
||||||
/// ```
|
/// ```
|
||||||
AdcDacData = 0,
|
AdcDacData = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<StreamTarget> for SocketAddr {
|
impl From<StreamTarget> for SocketAddr {
|
||||||
|
@ -128,27 +134,25 @@ pub fn setup_streaming(
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StreamFrame {
|
struct StreamFrame {
|
||||||
format: StreamFormat,
|
|
||||||
sequence_number: u16,
|
|
||||||
buffer: Box<[u8; FRAME_SIZE], Init>,
|
buffer: Box<[u8; FRAME_SIZE], Init>,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
batch_count: u16,
|
|
||||||
batch_size: u8,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StreamFrame {
|
impl StreamFrame {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
buffer: Box<[u8; FRAME_SIZE], Uninit>,
|
buffer: Box<[u8; FRAME_SIZE], Uninit>,
|
||||||
format: StreamFormat,
|
format: u8,
|
||||||
sequence_number: u16,
|
buffer_size: u8,
|
||||||
|
sequence_number: u32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let mut buffer = unsafe { buffer.assume_init() };
|
||||||
|
buffer[0..2].copy_from_slice(&MAGIC_WORD.to_ne_bytes());
|
||||||
|
buffer[2] = format;
|
||||||
|
buffer[3] = buffer_size;
|
||||||
|
buffer[4..8].copy_from_slice(&sequence_number.to_ne_bytes());
|
||||||
Self {
|
Self {
|
||||||
format,
|
buffer,
|
||||||
offset: 7,
|
offset: HEADER_SIZE,
|
||||||
sequence_number,
|
|
||||||
buffer: unsafe { buffer.assume_init() },
|
|
||||||
batch_size: SAMPLE_BUFFER_SIZE as u8,
|
|
||||||
batch_count: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +165,6 @@ impl StreamFrame {
|
||||||
let result = f(&mut self.buffer[self.offset..self.offset + T]);
|
let result = f(&mut self.buffer[self.offset..self.offset + T]);
|
||||||
|
|
||||||
self.offset += T;
|
self.offset += T;
|
||||||
self.batch_count = self.batch_count.checked_add(1).unwrap();
|
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -171,12 +174,7 @@ impl StreamFrame {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish(&mut self) -> &[u8] {
|
pub fn finish(&mut self) -> &[u8] {
|
||||||
let offset = self.offset;
|
&self.buffer[..self.offset]
|
||||||
self.buffer[0..2].copy_from_slice(&self.sequence_number.to_ne_bytes());
|
|
||||||
self.buffer[2..4].copy_from_slice(&(self.format as u16).to_ne_bytes());
|
|
||||||
self.buffer[4..6].copy_from_slice(&self.batch_count.to_ne_bytes());
|
|
||||||
self.buffer[6] = self.batch_size;
|
|
||||||
&self.buffer[..offset]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +183,8 @@ pub struct FrameGenerator {
|
||||||
queue: Producer<'static, StreamFrame, FRAME_COUNT>,
|
queue: Producer<'static, StreamFrame, FRAME_COUNT>,
|
||||||
pool: &'static Pool<[u8; FRAME_SIZE]>,
|
pool: &'static Pool<[u8; FRAME_SIZE]>,
|
||||||
current_frame: Option<StreamFrame>,
|
current_frame: Option<StreamFrame>,
|
||||||
sequence_number: u16,
|
sequence_number: u32,
|
||||||
|
format: StreamFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FrameGenerator {
|
impl FrameGenerator {
|
||||||
|
@ -196,18 +195,32 @@ impl FrameGenerator {
|
||||||
Self {
|
Self {
|
||||||
queue,
|
queue,
|
||||||
pool,
|
pool,
|
||||||
|
format: StreamFormat::Unknown,
|
||||||
current_frame: None,
|
current_frame: None,
|
||||||
sequence_number: 0,
|
sequence_number: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specify the format of the stream.
|
||||||
|
///
|
||||||
|
/// # Note:
|
||||||
|
/// This function may only be called once upon initializing streaming
|
||||||
|
///
|
||||||
|
/// # Args
|
||||||
|
/// * `format` - The desired format of the stream.
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub(crate) fn set_format(&mut self, format: StreamFormat) {
|
||||||
|
assert!(self.format == StreamFormat::Unknown);
|
||||||
|
assert!(format != StreamFormat::Unknown);
|
||||||
|
self.format = format;
|
||||||
|
}
|
||||||
|
|
||||||
/// Add a batch to the current stream frame.
|
/// Add a batch to the current stream frame.
|
||||||
///
|
///
|
||||||
/// # Args
|
/// # Args
|
||||||
/// * `format` - The format of the stream. This must be the same for each execution.
|
|
||||||
/// * `f` - A closure that will be provided the buffer to write batch data into. The buffer will
|
/// * `f` - A closure that will be provided the buffer to write batch data into. The buffer will
|
||||||
/// be the size of the `T` template argument.
|
/// be the size of the `T` template argument.
|
||||||
pub fn add<F, const T: usize>(&mut self, format: StreamFormat, f: F)
|
pub fn add<F, const T: usize>(&mut self, f: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&mut [u8]),
|
F: FnMut(&mut [u8]),
|
||||||
{
|
{
|
||||||
|
@ -218,7 +231,8 @@ impl FrameGenerator {
|
||||||
if let Some(buffer) = self.pool.alloc() {
|
if let Some(buffer) = self.pool.alloc() {
|
||||||
self.current_frame.replace(StreamFrame::new(
|
self.current_frame.replace(StreamFrame::new(
|
||||||
buffer,
|
buffer,
|
||||||
format,
|
self.format as u8,
|
||||||
|
SAMPLE_BUFFER_SIZE as u8,
|
||||||
sequence_number,
|
sequence_number,
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
|
@ -226,14 +240,11 @@ impl FrameGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(
|
let current_frame = self.current_frame.as_mut().unwrap();
|
||||||
format == self.current_frame.as_ref().unwrap().format,
|
|
||||||
"Unexpected stream format encountered"
|
|
||||||
);
|
|
||||||
|
|
||||||
self.current_frame.as_mut().unwrap().add_batch::<_, T>(f);
|
current_frame.add_batch::<_, T>(f);
|
||||||
|
|
||||||
if self.current_frame.as_ref().unwrap().is_full::<T>() {
|
if current_frame.is_full::<T>() {
|
||||||
if self
|
if self
|
||||||
.queue
|
.queue
|
||||||
.enqueue(self.current_frame.take().unwrap())
|
.enqueue(self.current_frame.take().unwrap())
|
||||||
|
|
|
@ -113,8 +113,13 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enable live data streaming.
|
/// Enable live data streaming.
|
||||||
pub fn enable_streaming(&mut self) -> FrameGenerator {
|
pub fn enable_streaming(
|
||||||
self.generator.take().unwrap()
|
&mut self,
|
||||||
|
format: data_stream::StreamFormat,
|
||||||
|
) -> FrameGenerator {
|
||||||
|
let mut generator = self.generator.take().unwrap();
|
||||||
|
generator.set_format(format);
|
||||||
|
generator
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Direct the stream to the provided remote target.
|
/// Direct the stream to the provided remote target.
|
||||||
|
|
Loading…
Reference in New Issue