Updating after refactor

master
Ryan Summers 2021-07-26 12:24:36 +02:00
parent 4c27100c23
commit 8d4193ed62
4 changed files with 95 additions and 119 deletions

View File

@ -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 =

View File

@ -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 =

View File

@ -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())

View File

@ -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.