diff --git a/src/scope.rs b/src/scope.rs index 3185136..d378cbb 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -112,10 +112,10 @@ impl Nscope { a2: AnalogOutput::create(command_tx.clone(), 1), p1: PulseOutput::create(command_tx.clone(), 0), p2: PulseOutput::create(command_tx.clone(), 1), - ch1: AnalogInput::default(), - ch2: AnalogInput::default(), - ch3: AnalogInput::default(), - ch4: AnalogInput::default(), + ch1: AnalogInput::create(is_legacy), + ch2: AnalogInput::create(is_legacy), + ch3: AnalogInput::create(is_legacy), + ch4: AnalogInput::create(is_legacy), fw_version, power_status, command_tx, @@ -129,7 +129,7 @@ impl Nscope { return Ok(scope); } // Wait for the response from the backend - if let Ok(_) = init_rx.recv_timeout(Duration::from_secs(5)) { + if init_rx.recv_timeout(Duration::from_secs(5)).is_ok() { return Ok(scope); } } diff --git a/src/scope/analog_input.rs b/src/scope/analog_input.rs index 45c0066..270cfab 100644 --- a/src/scope/analog_input.rs +++ b/src/scope/analog_input.rs @@ -8,22 +8,42 @@ * **************************************************************************************************/ +mod voltages_legacy; mod voltages; +use voltages_legacy::AnalogInterfaceLegacy; +use voltages::AnalogInterfaceModern; + +#[derive(Debug, Copy, Clone)] +enum AnalogInterface { + Legacy(AnalogInterfaceLegacy), + Modern(AnalogInterfaceModern) +} + /// Interface to a single scope channel #[derive(Debug, Copy, Clone)] pub struct AnalogInput { pub(crate) is_on: bool, - pub(crate) gain_setting: u8, - pub(crate) offset_setting: u8, + analog_interface: AnalogInterface, } -impl Default for AnalogInput { - fn default() -> Self { - let mut analog_input = AnalogInput { - is_on: true, - gain_setting: 0, - offset_setting: 0 +impl AnalogInput { + pub(crate) fn create(is_legacy: bool) -> Self { + let mut analog_input = match is_legacy { + true => AnalogInput { + is_on: true, + analog_interface: AnalogInterface::Legacy( + AnalogInterfaceLegacy { + gain_setting: 0, + offset_setting: 0, + }), + }, + false => AnalogInput { + is_on: true, + analog_interface: AnalogInterface::Modern( + AnalogInterfaceModern { + }), + } }; analog_input.set_range(-5.0, 5.0); analog_input @@ -31,7 +51,6 @@ impl Default for AnalogInput { } impl AnalogInput { - pub fn is_on(&self) -> bool { self.is_on } @@ -43,5 +62,47 @@ impl AnalogInput { pub fn turn_off(&mut self) { self.is_on = false; } + + pub fn set_range(&mut self, vmin: f64, vmax: f64) { + match self.analog_interface { + AnalogInterface::Legacy(mut interface) => { interface.set_range(vmin, vmax) } + AnalogInterface::Modern(mut interface) => { interface.set_range(vmin, vmax) } + } + } + + pub fn gain(&self) -> f64 { + match self.analog_interface { + AnalogInterface::Legacy(interface) => { interface.gain() } + AnalogInterface::Modern(interface) => { interface.gain() } + } + } + + pub(crate) fn measurement_from_voltage(&self, voltage: f64) -> i16 { + match self.analog_interface { + AnalogInterface::Legacy(interface) => { interface.measurement_from_voltage(voltage) } + AnalogInterface::Modern(interface) => { interface.measurement_from_voltage(voltage) } + } + } + + pub(crate) fn voltage_from_measurement(&self, adc_data: u16) -> f64 { + match self.analog_interface { + AnalogInterface::Legacy(interface) => { interface.voltage_from_measurement(adc_data) } + AnalogInterface::Modern(interface) => { interface.voltage_from_measurement(adc_data) } + } + } + + pub(crate) fn gain_cmd(&self) -> u8 { + match self.analog_interface { + AnalogInterface::Legacy(interface) => { interface.gain_setting } + AnalogInterface::Modern(_interface) => { 0 } + } + } + + pub(crate) fn offset_cmd(&self) -> u8 { + match self.analog_interface { + AnalogInterface::Legacy(interface) => { interface.offset_setting } + AnalogInterface::Modern(_interface) => { 0 } + } + } } diff --git a/src/scope/analog_input/voltages.rs b/src/scope/analog_input/voltages.rs index 60dc455..6f8849c 100644 --- a/src/scope/analog_input/voltages.rs +++ b/src/scope/analog_input/voltages.rs @@ -1,63 +1,36 @@ -const DELTA1: f64 = 1.65; -const DELTA2: f64 = 3.3 / 10.0; -const ALPHA1: f64 = 50.0 / 5000.0; -const ALPHA2: f64 = 20.0 / 256.0; +#[derive(Debug, Copy, Clone)] +pub(super) struct AnalogInterfaceModern { +} -const BETA1: f64 = 3.3 * 50.0 / 62.0 / 5000.0; -const BETA2: f64 = 3.3 * 20.0 / 62.0 / 256.0; +impl AnalogInterfaceModern { + pub(super) fn set_level(&mut self, _level: f64) { -impl super::AnalogInput { - fn set_level(&mut self, level: f64) { - let ch_gain = self.gain_setting as f64; - let gain = 1.0 + ALPHA1 + ALPHA2 * ch_gain; - if gain < 1.1 { - self.offset_setting = 31; - return; - } - let desired_level_setting = (level * DELTA2 * gain + DELTA1 * (gain - 1.0)) / (BETA1 + BETA2 * ch_gain); - self.offset_setting = (desired_level_setting + 0.5) as u8 } - fn set_gain(&mut self, gain: f64) { - let desired_gain_setting = (gain - 1.0 - ALPHA1) / ALPHA2; - self.gain_setting = desired_gain_setting as u8; - } + pub(super) fn set_gain(&mut self, _gain: f64) { - pub fn gain(&self) -> f64 { - self.gain_setting as f64 * ALPHA2 + ALPHA1 + 1.0 } -} -impl super::AnalogInput { - pub(crate) fn measurement_from_voltage(&self, voltage: f64) -> i16 { - let ch_gain = self.gain_setting as f64; - let ch_level = self.offset_setting as f64; - - let gain = 1.0 + ALPHA1 + ALPHA2 * ch_gain; - let level = (ch_level * (BETA1 + BETA2 * ch_gain) - DELTA1 * (gain - 1.0)) / DELTA2 / gain; - ((voltage - level) * gain / 10.0 * 4095.0 + 2047.0) as i16 + pub(super) fn gain(&self) -> f64 { + 1.0 } -} -impl super::AnalogInput { - pub(crate) fn voltage_from_measurement(&self, adc_data: u16) -> f64 { - let adc_reading = adc_data as f64; - let ch_gain = self.gain_setting as f64; - let ch_level = self.offset_setting as f64; + pub(super) fn measurement_from_voltage(&self, _voltage: f64) -> i16 { + 0i16 + } - let gain = 1.0 + ALPHA1 + ALPHA2 * ch_gain; - let level = (ch_level * (BETA1 + BETA2 * ch_gain) - DELTA1 * (gain - 1.0)) / DELTA2 / gain; + pub(super) fn voltage_from_measurement(&self, adc_data: u16) -> f64 { + let gain = 1.0f64; + let v_offset = 0.0f64; - 10.0 / gain * (adc_reading - 2047.0) / 4095.0 + level + let adc_voltage = adc_data as f64 * 2.5 / 4095.0; + ((adc_voltage / gain + v_offset * (gain - 1.0) / (gain)) - 1.25) * 10.0 / 2.5 } -} - -impl super::AnalogInput { - pub fn set_range(&mut self, vmin: f64, vmax: f64) { + pub(super) fn set_range(&mut self, vmin: f64, vmax: f64) { let level = (vmax + vmin) / 2.0; - let gain = 10.0 / (vmax - vmin); + let gain = 10.0 / (vmax - vmin); self.set_gain(gain); self.set_level(level); diff --git a/src/scope/analog_input/voltages_legacy.rs b/src/scope/analog_input/voltages_legacy.rs new file mode 100644 index 0000000..4bdd956 --- /dev/null +++ b/src/scope/analog_input/voltages_legacy.rs @@ -0,0 +1,65 @@ +const DELTA1: f64 = 1.65; +const DELTA2: f64 = 3.3 / 10.0; + +const ALPHA1: f64 = 50.0 / 5000.0; +const ALPHA2: f64 = 20.0 / 256.0; + +const BETA1: f64 = 3.3 * 50.0 / 62.0 / 5000.0; +const BETA2: f64 = 3.3 * 20.0 / 62.0 / 256.0; + +#[derive(Debug, Copy, Clone)] +pub(super) struct AnalogInterfaceLegacy { + pub(super) gain_setting: u8, + pub(super) offset_setting: u8, +} + +impl AnalogInterfaceLegacy { + pub(super) fn set_level(&mut self, level: f64) { + let ch_gain = self.gain_setting as f64; + let gain = 1.0 + ALPHA1 + ALPHA2 * ch_gain; + if gain < 1.1 { + self.offset_setting = 31; + return; + } + let desired_level_setting = (level * DELTA2 * gain + DELTA1 * (gain - 1.0)) / (BETA1 + BETA2 * ch_gain); + self.offset_setting = (desired_level_setting + 0.5) as u8 + } + + pub(super) fn set_gain(&mut self, gain: f64) { + let desired_gain_setting = (gain - 1.0 - ALPHA1) / ALPHA2; + self.gain_setting = desired_gain_setting as u8; + } + + pub(super) fn gain(&self) -> f64 { + self.gain_setting as f64 * ALPHA2 + ALPHA1 + 1.0 + } + + pub(super) fn measurement_from_voltage(&self, voltage: f64) -> i16 { + let ch_gain = self.gain_setting as f64; + let ch_level = self.offset_setting as f64; + + let gain = 1.0 + ALPHA1 + ALPHA2 * ch_gain; + let level = (ch_level * (BETA1 + BETA2 * ch_gain) - DELTA1 * (gain - 1.0)) / DELTA2 / gain; + + ((voltage - level) * gain / 10.0 * 4095.0 + 2047.0) as i16 + } + + pub(super) fn voltage_from_measurement(&self, adc_data: u16) -> f64 { + let adc_reading = adc_data as f64; + let ch_gain = self.gain_setting as f64; + let ch_level = self.offset_setting as f64; + + let gain = 1.0 + ALPHA1 + ALPHA2 * ch_gain; + let level = (ch_level * (BETA1 + BETA2 * ch_gain) - DELTA1 * (gain - 1.0)) / DELTA2 / gain; + + 10.0 / gain * (adc_reading - 2047.0) / 4095.0 + level + } + + pub(super) fn set_range(&mut self, vmin: f64, vmax: f64) { + let level = (vmax + vmin) / 2.0; + let gain = 10.0 / (vmax - vmin); + + self.set_gain(gain); + self.set_level(level); + } +} \ No newline at end of file diff --git a/src/scope/commands.rs b/src/scope/commands.rs index 204410b..77e902e 100644 --- a/src/scope/commands.rs +++ b/src/scope/commands.rs @@ -88,7 +88,7 @@ impl Command { Command::SetAnalogOutput(cmd) => { cmd.handle_rx(buffer) } Command::SetPulseOutput(cmd) => { cmd.handle_rx(buffer) } Command::RequestData(cmd) => { cmd.handle_rx(buffer) } - Command::StopData => {} + Command::StopData => { } } } diff --git a/src/scope/data_requests.rs b/src/scope/data_requests.rs index df39479..1082324 100644 --- a/src/scope/data_requests.rs +++ b/src/scope/data_requests.rs @@ -148,8 +148,8 @@ impl ScopeCommand for DataRequest { for (i, ch) in self.channels.iter().enumerate() { if ch.is_on { - usb_buf[15 + i] = ch.gain_setting; - usb_buf[19 + i] = ch.offset_setting; + usb_buf[15 + i] = ch.gain_cmd(); + usb_buf[19 + i] = ch.offset_cmd(); } else { usb_buf[15 + i] = 0xFF; } @@ -160,20 +160,27 @@ impl ScopeCommand for DataRequest { } fn fill_tx_buffer(&self, usb_buf: &mut [u8; 64]) -> Result<(), Box> { - let num_channels_on = self.channels.iter().filter(|&ch| ch.is_on).count(); - - let samples_between_records: u32 = (400_000.0 / self.sample_rate_hz) as u32; let total_samples = *self.remaining_samples.read().unwrap(); trace!("Requesting {} samples with {} samples between records", total_samples, samples_between_records); - if samples_between_records < 25 && total_samples * num_channels_on as u32 > 3200 { + if samples_between_records < 25 && total_samples > 2400 { return Err("Data not recordable".into()); } usb_buf[2..6].copy_from_slice(&samples_between_records.to_le_bytes()); usb_buf[6..10].copy_from_slice(&total_samples.to_le_bytes()); + // Fill bytes 10-13 with the channel gains (or 0xFF to indicate off) + for (i, ch) in self.channels.iter().enumerate() { + if ch.is_on { + usb_buf[10 + i] = ch.gain_cmd(); + // usb_buf[14 + i] = ch.offset_setting; + } else { + usb_buf[10 + i] = 0xFF; + } + } + Ok(()) } @@ -225,7 +232,6 @@ impl ScopeCommand for DataRequest { impl DataRequest { pub(crate) fn handle_incoming_data(&self, usb_buf: &[u8; 64], channel: usize) { - let num_received = usb_buf[0] as usize; let mut num_parsed: usize = 0; while num_parsed < num_received { @@ -237,23 +243,23 @@ impl DataRequest { _ => panic!("Unexpected behavior of odd/even bitmask") }; - trace!("Ch{}: ADCData: {}", channel+1, adc_data); self.data_collator.write().unwrap()[channel].push_back(adc_data); num_parsed += 1; } } pub(crate) fn collate_results(&self) { - let data_collator = &mut *self.data_collator.write().unwrap(); - - let received_samples = data_collator.iter().map( - |ch| ch.len() - ).collect::>(); + // Find the number of samples received for all channels that are on using filter and map + let received_samples = data_collator + .iter() + .enumerate() + .filter(|&(ch, _)| self.channels[ch].is_on) + .map(|(_, collator_channel)| collator_channel.len()) + .collect::>(); if let Some(&complete_samples) = received_samples.iter().min() { - let mut samples_to_pop = complete_samples; while samples_to_pop > 0 { let mut sample = Sample { @@ -262,23 +268,24 @@ impl DataRequest { }; for (ch, input_buffer) in data_collator.iter_mut().enumerate() { - let data = input_buffer.pop_front().unwrap(); - sample.data[ch] = Some(data as f64); + let channel = &self.channels[ch]; + + if channel.is_on { + let data = input_buffer.pop_front().unwrap(); + sample.data[ch] = Some(channel.voltage_from_measurement(data)); + trace!("Ch{}: ADCData: {} Vi: {}", ch+1, data, channel.voltage_from_measurement(data)); + } } self.sender.send(sample).unwrap(); samples_to_pop -= 1; } - if complete_samples > 0{ + if complete_samples > 0 { let mut remaining_samples = self.remaining_samples.write().unwrap(); *remaining_samples -= complete_samples as u32; trace!("Received {} samples, {} samples remaining", complete_samples, remaining_samples); } - - - } - } } \ No newline at end of file diff --git a/src/scope/run_loops/v2.rs b/src/scope/run_loops/v2.rs index b7ee00b..62f17ea 100644 --- a/src/scope/run_loops/v2.rs +++ b/src/scope/run_loops/v2.rs @@ -109,6 +109,12 @@ impl crate::Nscope { // If the command has finished it's work if command.is_finished() { + if let Command::StopData = command { + if let Some(active_data_request_id) = active_data_request { + active_requests_map.remove(&active_data_request_id); + active_data_request = None; + } + } active_requests_map.remove(&request_id); trace!("Finished request ID: {}", request_id); } else { @@ -148,6 +154,8 @@ impl crate::Nscope { } + + // If we received data on any incoming channel, collate any results if received_ch_data { if let Some(request_id) = active_data_request { if let Some(Command::RequestData(data_request)) = active_requests_map.get(&request_id) {