nscope/scope/
analog_output.rs

1/***************************************************************************************************
2 *
3 *  nLabs, LLC
4 *  https://nscope.org
5 *  Copyright(c) 2020. All Rights Reserved
6 *
7 *  This file is part of the nScope API
8 *
9 **************************************************************************************************/
10
11use std::error::Error;
12use std::str::FromStr;
13use std::sync::{mpsc, RwLock};
14use std::sync::mpsc::Sender;
15
16use crate::scope::commands::ScopeCommand;
17
18use super::commands::Command;
19
20/// Possible analog output signal types
21#[derive(Debug, PartialEq, Copy, Clone)]
22pub enum AnalogWaveType {
23    Sine = 0,
24    Triangle = 1,
25}
26
27impl FromStr for AnalogWaveType {
28    type Err = ();
29    fn from_str(input: &str) -> Result<AnalogWaveType, Self::Err> {
30        match input {
31            "Sine" => Ok(AnalogWaveType::Sine),
32            "Triangle" => Ok(AnalogWaveType::Triangle),
33            _ => Err(()),
34        }
35    }
36}
37
38/// Possible analog output polarities
39#[derive(Debug, PartialEq, Copy, Clone)]
40pub enum AnalogSignalPolarity {
41    Unipolar,
42    Bipolar,
43}
44
45impl FromStr for AnalogSignalPolarity {
46    type Err = ();
47    fn from_str(input: &str) -> Result<AnalogSignalPolarity, Self::Err> {
48        match input {
49            "Unipolar" => Ok(AnalogSignalPolarity::Unipolar),
50            "Bipolar" => Ok(AnalogSignalPolarity::Bipolar),
51            _ => Err(()),
52        }
53    }
54}
55
56/// Interface to an analog output
57#[derive(Clone, Copy, Debug)]
58struct AnalogOutputState {
59    is_on: bool,
60    frequency: f64,
61    amplitude: f64,
62    wave_type: AnalogWaveType,
63    polarity: AnalogSignalPolarity,
64}
65
66/// Interface to an analog output channel
67#[derive(Debug)]
68pub struct AnalogOutput {
69    pub channel: usize,
70    command_tx: Sender<Command>,
71    state: RwLock<AnalogOutputState>,
72}
73
74impl AnalogOutput {
75    pub(super) fn create(cmd_tx: Sender<Command>, ax_channel: usize) -> Self {
76
77        let default_state = AnalogOutputState {
78            is_on: false,
79            frequency: 1.0,
80            amplitude: 1.0,
81            wave_type: AnalogWaveType::Sine,
82            polarity: AnalogSignalPolarity::Unipolar,
83        };
84
85        let ax = AnalogOutput {
86            command_tx: cmd_tx,
87            channel: ax_channel,
88            state: RwLock::new(default_state),
89        };
90
91        ax.set(default_state);
92        ax
93    }
94
95    fn set(&self, ax_state: AnalogOutputState) {
96        // Create a method for the backend to communicate back to us what we want
97        let (tx, rx) = mpsc::channel::<AnalogOutputState>();
98
99        // Create the command to set an analog output
100        let command = Command::SetAnalogOutput(AxRequest {
101            channel: self.channel,
102            ax_state,
103            sender: tx,
104
105        });
106
107        // Send the command to the backend
108        self.command_tx.send(command).unwrap();
109
110        // Wait for the response from the backend
111        let response_state = rx.recv().unwrap();
112        // Write the response state
113        *self.state.write().unwrap() = response_state;
114    }
115
116    pub fn is_on(&self) -> bool {
117        self.state.read().unwrap().is_on
118    }
119    pub fn frequency(&self) -> f64 {
120        self.state.read().unwrap().frequency
121    }
122    pub fn amplitude(&self) -> f64 {
123        self.state.read().unwrap().amplitude
124    }
125    pub fn wave_type(&self) -> AnalogWaveType {
126        self.state.read().unwrap().wave_type
127    }
128    pub fn polarity(&self) -> AnalogSignalPolarity {
129        self.state.read().unwrap().polarity
130    }
131
132
133    pub fn turn_on(&self) {
134        let mut state = *self.state.read().unwrap();
135        state.is_on = true;
136        self.set(state)
137    }
138    pub fn turn_off(&self) {
139        let mut state = *self.state.read().unwrap();
140        state.is_on = false;
141        self.set(state)
142    }
143
144    pub fn set_frequency(&self, desired_hz: f64) {
145        let mut state = *self.state.read().unwrap();
146        state.frequency = desired_hz;
147        self.set(state)
148    }
149
150    pub fn set_amplitude(&self, desired_volts: f64) {
151        let mut state = *self.state.read().unwrap();
152        state.amplitude = desired_volts;
153        self.set(state)
154    }
155
156    pub fn set_wave_type(&self, wave_type: AnalogWaveType) {
157        let mut state = *self.state.read().unwrap();
158        state.wave_type = wave_type;
159        self.set(state)
160    }
161
162    pub fn set_polarity(&self, polarity: AnalogSignalPolarity) {
163        let mut state = *self.state.read().unwrap();
164        state.polarity = polarity;
165        self.set(state)
166    }
167}
168
169
170#[derive(Debug)]
171pub(super) struct AxRequest {
172    channel: usize,
173    ax_state: AnalogOutputState,
174    sender: Sender<AnalogOutputState>,
175}
176
177impl ScopeCommand for AxRequest {
178    fn fill_tx_buffer(&self, usb_buf: &mut [u8; 65]) -> Result<(), Box<dyn Error>> {
179        usb_buf[1] = 0x02;
180
181        let i_ch = 3 + 10 * self.channel;
182        if self.ax_state.is_on {
183            usb_buf[i_ch] = self.ax_state.wave_type as u8;
184            usb_buf[i_ch] |= 0x80;
185
186            let scaled_frequency = self.ax_state.frequency * 2.0_f64.powi(28) / 4000000.0;
187            let freq_register: u32 = scaled_frequency as u32;
188
189            usb_buf[i_ch + 1] = (freq_register & 0x00FF) as u8;
190            usb_buf[i_ch + 2] = ((freq_register & 0x3F00) >> 8) as u8;
191            usb_buf[i_ch + 3] = (freq_register >> 14 & 0x00FF) as u8;
192            usb_buf[i_ch + 4] = ((freq_register >> 14 & 0x3F00) >> 8) as u8;
193
194            if self.ax_state.amplitude < 0.0 {
195                usb_buf[i_ch] |= 0x2;
196            }
197            let rf = 49900.0;
198            let vin = 0.6;
199            let rm = 75.0;
200            let rv = 100000.0 / 257.0;
201
202            let gain: u8 = match self.ax_state.polarity {
203                AnalogSignalPolarity::Unipolar => ((vin * rf / self.ax_state.amplitude.abs() - rm) / rv) as u8,
204                AnalogSignalPolarity::Bipolar => {
205                    ((vin * rf / 2.0 / self.ax_state.amplitude.abs() - rm) / rv) as u8
206                }
207            };
208
209            let offset: u8 = ((rm + rv * (gain as f64)) / (rm + rv * (gain as f64) + rf)
210                * self.ax_state.amplitude.abs()
211                * 255.0
212                / 3.05) as u8;
213
214            usb_buf[i_ch + 5] = gain;
215            usb_buf[i_ch + 6] = offset;
216        } else {
217            usb_buf[i_ch] = 0xFF;
218        }
219        Ok(())
220    }
221
222    fn handle_rx(&self, _usb_buf: &[u8; 64]) {
223        self.sender.send(self.ax_state).unwrap();
224    }
225
226    fn is_finished(&self) -> bool {
227        true
228    }
229}