Compare commits
No commits in common. "412e6c0ea9b7fb512827849ecdf5e16ea2c5e7df" and "e1abf8735113287c7a51ceb9023c656d27c7434e" have entirely different histories.
412e6c0ea9
...
e1abf87351
|
@ -55,10 +55,7 @@ use firmware::{
|
||||||
ClockSourceCommand,
|
ClockSourceCommand,
|
||||||
ClockDivisionCommand,
|
ClockDivisionCommand,
|
||||||
ProfileCommand,
|
ProfileCommand,
|
||||||
Channel0Profile0SingletoneCommand,
|
Channel0Profile0Singletone
|
||||||
Channel0Profile0SingletoneFrequencyCommand,
|
|
||||||
Channel0Profile0SingletonePhaseCommand,
|
|
||||||
Channel0Profile0SingletoneAmplitudeCommand
|
|
||||||
},
|
},
|
||||||
Urukul, scpi_root, recursive_scpi_tree, scpi_tree
|
Urukul, scpi_root, recursive_scpi_tree, scpi_tree
|
||||||
};
|
};
|
||||||
|
|
111
src/dds.rs
111
src/dds.rs
|
@ -325,7 +325,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup a complete single tone profile
|
* Set a single tone profile
|
||||||
* Phase: Expressed in positive degree, i.e. [0.0, 360.0)
|
* Phase: Expressed in positive degree, i.e. [0.0, 360.0)
|
||||||
* Frequency: Must be non-negative
|
* Frequency: Must be non-negative
|
||||||
* Amplitude: In a scale from 0 to 1, taking float
|
* Amplitude: In a scale from 0 to 1, taking float
|
||||||
|
@ -333,7 +333,6 @@ where
|
||||||
pub fn set_single_tone_profile(&mut self, profile: u8, f_out: f64, phase_offset: f64, amp_scale_factor: f64) -> Result<(), Error<E>> {
|
pub fn set_single_tone_profile(&mut self, profile: u8, f_out: f64, phase_offset: f64, amp_scale_factor: f64) -> Result<(), Error<E>> {
|
||||||
|
|
||||||
assert!(profile < 8);
|
assert!(profile < 8);
|
||||||
assert!(f_out >= 0.0);
|
|
||||||
assert!(phase_offset >= 0.0 && phase_offset < 360.0);
|
assert!(phase_offset >= 0.0 && phase_offset < 360.0);
|
||||||
assert!(amp_scale_factor >=0.0 && amp_scale_factor <= 1.0);
|
assert!(amp_scale_factor >=0.0 && amp_scale_factor <= 1.0);
|
||||||
|
|
||||||
|
@ -368,114 +367,6 @@ where
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Set frequency of a single tone profile
|
|
||||||
* Frequency: Must be non-negative
|
|
||||||
* Keep other field unchanged in the register
|
|
||||||
*/
|
|
||||||
pub fn set_single_tone_profile_frequency(&mut self, profile: u8, f_out: f64) -> Result<(), Error<E>> {
|
|
||||||
|
|
||||||
// Setup configuration registers before writing single tone register
|
|
||||||
self.set_configurations(&mut [
|
|
||||||
(DDSCFRMask::RAM_ENABLE, 0),
|
|
||||||
(DDSCFRMask::DIGITAL_RAMP_ENABLE, 0),
|
|
||||||
(DDSCFRMask::OSK_ENABLE, 0),
|
|
||||||
(DDSCFRMask::PARALLEL_DATA_PORT_ENABLE, 0),
|
|
||||||
])?;
|
|
||||||
self.set_configurations(&mut [
|
|
||||||
(DDSCFRMask::EN_AMP_SCALE_SINGLE_TONE_PRO, 1),
|
|
||||||
])?;
|
|
||||||
|
|
||||||
// Calculate frequency tuning work (FTW)
|
|
||||||
let f_res: u64 = 1 << 32;
|
|
||||||
let ftw = ((f_res as f64) * f_out / self.f_sys_clk) as u32;
|
|
||||||
|
|
||||||
// Read existing amplitude/phase data
|
|
||||||
let mut register: [u8; 8] = [0; 8];
|
|
||||||
self.read_register(0x0E + profile, &mut register)?;
|
|
||||||
|
|
||||||
// Overwrite FTW
|
|
||||||
register[4] = ((ftw >> 24) & 0xFF) as u8;
|
|
||||||
register[5] = ((ftw >> 16) & 0xFF) as u8;
|
|
||||||
register[6] = ((ftw >> 8) & 0xFF) as u8;
|
|
||||||
register[7] = ((ftw >> 0) & 0xFF) as u8;
|
|
||||||
|
|
||||||
// Update FTW by writing back the register
|
|
||||||
self.write_register(0x0E + profile, &mut register)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set phase offset of a single tone profile
|
|
||||||
* Phase: Expressed in positive degree, i.e. [0.0, 360.0)
|
|
||||||
* Keep other field unchanged in the register
|
|
||||||
*/
|
|
||||||
pub fn set_single_tone_profile_phase(&mut self, profile: u8, phase_offset: f64) -> Result<(), Error<E>> {
|
|
||||||
|
|
||||||
// Setup configuration registers before writing single tone register
|
|
||||||
self.set_configurations(&mut [
|
|
||||||
(DDSCFRMask::RAM_ENABLE, 0),
|
|
||||||
(DDSCFRMask::DIGITAL_RAMP_ENABLE, 0),
|
|
||||||
(DDSCFRMask::OSK_ENABLE, 0),
|
|
||||||
(DDSCFRMask::PARALLEL_DATA_PORT_ENABLE, 0),
|
|
||||||
])?;
|
|
||||||
self.set_configurations(&mut [
|
|
||||||
(DDSCFRMask::EN_AMP_SCALE_SINGLE_TONE_PRO, 1),
|
|
||||||
])?;
|
|
||||||
|
|
||||||
// Calculate phase offset work (POW)
|
|
||||||
let phase_res: u64 = 1 << 16;
|
|
||||||
let pow = ((phase_res as f64) * phase_offset / 360.0) as u16;
|
|
||||||
|
|
||||||
// Read existing amplitude/frequency data
|
|
||||||
let mut register: [u8; 8] = [0; 8];
|
|
||||||
self.read_register(0x0E + profile, &mut register)?;
|
|
||||||
|
|
||||||
// Overwrite POW
|
|
||||||
register[2] = ((pow >> 8) & 0xFF) as u8;
|
|
||||||
register[3] = ((pow >> 0) & 0xFF) as u8;
|
|
||||||
|
|
||||||
// Update POW by writing back the register
|
|
||||||
self.write_register(0x0E + profile, &mut register)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set amplitude offset of a single tone profile
|
|
||||||
* Amplitude: In a scale from 0 to 1, taking float
|
|
||||||
* Keep other field unchanged in the register
|
|
||||||
*/
|
|
||||||
pub fn set_single_tone_profile_amplitude(&mut self, profile: u8, amp_scale_factor: f64) -> Result<(), Error<E>> {
|
|
||||||
|
|
||||||
// Setup configuration registers before writing single tone register
|
|
||||||
self.set_configurations(&mut [
|
|
||||||
(DDSCFRMask::RAM_ENABLE, 0),
|
|
||||||
(DDSCFRMask::DIGITAL_RAMP_ENABLE, 0),
|
|
||||||
(DDSCFRMask::OSK_ENABLE, 0),
|
|
||||||
(DDSCFRMask::PARALLEL_DATA_PORT_ENABLE, 0),
|
|
||||||
])?;
|
|
||||||
self.set_configurations(&mut [
|
|
||||||
(DDSCFRMask::EN_AMP_SCALE_SINGLE_TONE_PRO, 1),
|
|
||||||
])?;
|
|
||||||
|
|
||||||
// Calculate amplitude_scale_factor (ASF)
|
|
||||||
let amp_res: u64 = 1 << 14;
|
|
||||||
let asf :u16 = if amp_scale_factor == 1.0 {
|
|
||||||
0x3FFF
|
|
||||||
} else {
|
|
||||||
((amp_res as f64) * amp_scale_factor) as u16
|
|
||||||
};
|
|
||||||
|
|
||||||
// Read existing frequency/phase data
|
|
||||||
let mut register: [u8; 8] = [0; 8];
|
|
||||||
self.read_register(0x0E + profile, &mut register)?;
|
|
||||||
|
|
||||||
// Overwrite POW
|
|
||||||
register[0] = ((asf >> 8) & 0xFF) as u8;
|
|
||||||
register[1] = ((asf >> 0) & 0xFF) as u8;
|
|
||||||
|
|
||||||
// Update POW by writing back the register
|
|
||||||
self.write_register(0x0E + profile, &mut register)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test method for DDS.
|
* Test method for DDS.
|
||||||
|
|
15
src/lib.rs
15
src/lib.rs
|
@ -165,9 +165,6 @@ pub trait UrukulTraits {
|
||||||
fn set_channel_attenuation(&mut self, channel: u8, attenuation: f32) -> Result<(), Self::Error>;
|
fn set_channel_attenuation(&mut self, channel: u8, attenuation: f32) -> Result<(), Self::Error>;
|
||||||
fn set_profile(&mut self, profile: u8) -> Result<(), Self::Error>;
|
fn set_profile(&mut self, profile: u8) -> Result<(), Self::Error>;
|
||||||
fn set_channel_single_tone_profile(&mut self, channel: u8, profile: u8, frequency: f64, phase: f64, amplitude: f64) -> Result<(), Self::Error>;
|
fn set_channel_single_tone_profile(&mut self, channel: u8, profile: u8, frequency: f64, phase: f64, amplitude: f64) -> Result<(), Self::Error>;
|
||||||
fn set_channel_single_tone_profile_frequency(&mut self, channel: u8, profile: u8, frequency: f64)-> Result<(), Self::Error>;
|
|
||||||
fn set_channel_single_tone_profile_phase(&mut self, channel: u8, profile: u8, phase: f64)-> Result<(), Self::Error>;
|
|
||||||
fn set_channel_single_tone_profile_amplitude(&mut self, channel: u8, profile: u8, amplitude: f64)-> Result<(), Self::Error>;
|
|
||||||
fn set_channel_sys_clk(&mut self, channel: u8, sys_clk: f64) -> Result<(), Self::Error>;
|
fn set_channel_sys_clk(&mut self, channel: u8, sys_clk: f64) -> Result<(), Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,18 +267,6 @@ where
|
||||||
self.dds[usize::from(channel)].set_single_tone_profile(profile, frequency, phase, amplitude)
|
self.dds[usize::from(channel)].set_single_tone_profile(profile, frequency, phase, amplitude)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_channel_single_tone_profile_frequency(&mut self, channel: u8, profile: u8, frequency: f64)-> Result<(), Self::Error> {
|
|
||||||
self.dds[usize::from(channel)].set_single_tone_profile_frequency(profile, frequency)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_channel_single_tone_profile_phase(&mut self, channel: u8, profile: u8, phase: f64)-> Result<(), Self::Error> {
|
|
||||||
self.dds[usize::from(channel)].set_single_tone_profile_phase(profile, phase)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_channel_single_tone_profile_amplitude(&mut self, channel: u8, profile: u8, amplitude: f64)-> Result<(), Self::Error> {
|
|
||||||
self.dds[usize::from(channel)].set_single_tone_profile_amplitude(profile, amplitude)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_channel_sys_clk(&mut self, channel: u8, f_sys_clk: f64) -> Result<(), Self::Error> {
|
fn set_channel_sys_clk(&mut self, channel: u8, f_sys_clk: f64) -> Result<(), Self::Error> {
|
||||||
self.dds[usize::from(channel)].set_sys_clk_frequency(f_sys_clk)
|
self.dds[usize::from(channel)].set_sys_clk_frequency(f_sys_clk)
|
||||||
}
|
}
|
||||||
|
|
234
src/scpi.rs
234
src/scpi.rs
|
@ -117,28 +117,23 @@ macro_rules! scpi_tree {
|
||||||
scpi_root!(
|
scpi_root!(
|
||||||
"CHANNEL0" => {
|
"CHANNEL0" => {
|
||||||
"SWitch" => Channel0SwitchCommand,
|
"SWitch" => Channel0SwitchCommand,
|
||||||
"ATTenuation" => Channel0AttenuationCommand,
|
"Attenuation" => Channel0AttenuationCommand,
|
||||||
"SYSCLOCK" => Channel0SystemClockCommand,
|
"SYSCLOCK" => Channel0SystemClockCommand,
|
||||||
"PROFILE0" => {
|
"PROFILE0" => {
|
||||||
"SINGLEtone" => {
|
"SINGLEtone" => Channel0Profile0Singletone
|
||||||
"FREQuency" => Channel0Profile0SingletoneFrequencyCommand,
|
|
||||||
"PHASE" => Channel0Profile0SingletonePhaseCommand,
|
|
||||||
"AMPlitude" => Channel0Profile0SingletoneAmplitudeCommand,
|
|
||||||
["Setup"] => Channel0Profile0SingletoneCommand
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"CHANNEL1" => {
|
"CHANNEL1" => {
|
||||||
"SWitch" => Channel1SwitchCommand,
|
"SWitch" => Channel1SwitchCommand,
|
||||||
"ATTenuation" => Channel1AttenuationCommand
|
"Attenuation" => Channel1AttenuationCommand
|
||||||
},
|
},
|
||||||
"CHANNEL2" => {
|
"CHANNEL2" => {
|
||||||
"SWitch" => Channel2SwitchCommand,
|
"SWitch" => Channel2SwitchCommand,
|
||||||
"ATTenuation" => Channel2AttenuationCommand
|
"Attenuation" => Channel2AttenuationCommand
|
||||||
},
|
},
|
||||||
"CHANNEL3" => {
|
"CHANNEL3" => {
|
||||||
"SWitch" => Channel3SwitchCommand,
|
"SWitch" => Channel3SwitchCommand,
|
||||||
"ATTenuation" => Channel3AttenuationCommand
|
"Attenuation" => Channel3AttenuationCommand
|
||||||
},
|
},
|
||||||
"CLOCK" => {
|
"CLOCK" => {
|
||||||
"SOURCE" => ClockSourceCommand,
|
"SOURCE" => ClockSourceCommand,
|
||||||
|
@ -172,43 +167,78 @@ pub struct Channel0SwitchCommand {}
|
||||||
pub struct Channel1SwitchCommand {}
|
pub struct Channel1SwitchCommand {}
|
||||||
pub struct Channel2SwitchCommand {}
|
pub struct Channel2SwitchCommand {}
|
||||||
pub struct Channel3SwitchCommand {}
|
pub struct Channel3SwitchCommand {}
|
||||||
|
pub struct ClockSourceCommand {}
|
||||||
|
pub struct ClockDivisionCommand {}
|
||||||
|
pub struct Channel0SystemClockCommand {}
|
||||||
|
pub struct Channel0AttenuationCommand {}
|
||||||
|
pub struct Channel1AttenuationCommand {}
|
||||||
|
pub struct Channel2AttenuationCommand {}
|
||||||
|
pub struct Channel3AttenuationCommand {}
|
||||||
|
pub struct ProfileCommand {}
|
||||||
|
pub struct Channel0Profile0Singletone {}
|
||||||
|
pub struct Channel0Profile0SingletoneFrequency {}
|
||||||
|
pub struct Channel0Profile0SingletonePhase {}
|
||||||
|
pub struct Channel0Profile0SingletoneAmplitude {}
|
||||||
|
|
||||||
macro_rules! impl_channel_switch_command {
|
impl<T: Device + UrukulTraits> Command<T> for Channel0SwitchCommand {
|
||||||
($($channel: literal => $command_struct: ty),*) => {
|
|
||||||
$(
|
|
||||||
impl<T: Device + UrukulTraits> Command<T> for $command_struct {
|
|
||||||
nquery!();
|
nquery!();
|
||||||
|
|
||||||
fn event(&self, context: &mut Context<T>, args: &mut Tokenizer) -> Result<()> {
|
fn event(&self, context: &mut Context<T>, args: &mut Tokenizer) -> Result<()> {
|
||||||
let next_state: bool = args.next_data(true)?
|
let next_state: bool = args.next_data(true)?
|
||||||
.map_or(
|
.map_or(
|
||||||
context.device.get_channel_switch_status($channel)
|
context.device.get_channel_switch_status(0)
|
||||||
.map(|current| !current)
|
.map(|current| !current)
|
||||||
.map_err(|_| Error::new(ErrorCode::HardwareError)),
|
.map_err(|_| Error::new(ErrorCode::HardwareError)),
|
||||||
|token| token.try_into()
|
|token| token.try_into()
|
||||||
)?;
|
)?;
|
||||||
context.device.set_channel_switch($channel, next_state).map_err(|_| Error::new(ErrorCode::HardwareError))
|
context.device.set_channel_switch(0, next_state).map_err(|_| Error::new(ErrorCode::HardwareError))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
)*
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_channel_switch_command!(
|
impl<T: Device + UrukulTraits> Command<T> for Channel1SwitchCommand {
|
||||||
0 => Channel0SwitchCommand,
|
nquery!();
|
||||||
1 => Channel1SwitchCommand,
|
|
||||||
2 => Channel2SwitchCommand,
|
|
||||||
3 => Channel3SwitchCommand
|
|
||||||
);
|
|
||||||
|
|
||||||
pub struct ClockSourceCommand {}
|
fn event(&self, context: &mut Context<T>, args: &mut Tokenizer) -> Result<()> {
|
||||||
pub struct ClockDivisionCommand {}
|
let next_state: bool = args.next_data(true)?
|
||||||
pub struct Channel0SystemClockCommand {}
|
.map_or(
|
||||||
pub struct ProfileCommand {}
|
context.device.get_channel_switch_status(1)
|
||||||
pub struct Channel0Profile0SingletoneCommand {}
|
.map(|current| !current)
|
||||||
pub struct Channel0Profile0SingletoneFrequencyCommand {}
|
.map_err(|_| Error::new(ErrorCode::HardwareError)),
|
||||||
pub struct Channel0Profile0SingletonePhaseCommand {}
|
|token| token.try_into()
|
||||||
pub struct Channel0Profile0SingletoneAmplitudeCommand {}
|
)?;
|
||||||
|
context.device.set_channel_switch(1, next_state).map_err(|_| Error::new(ErrorCode::HardwareError))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Device + UrukulTraits> Command<T> for Channel2SwitchCommand {
|
||||||
|
nquery!();
|
||||||
|
|
||||||
|
fn event(&self, context: &mut Context<T>, args: &mut Tokenizer) -> Result<()> {
|
||||||
|
let next_state: bool = args.next_data(true)?
|
||||||
|
.map_or(
|
||||||
|
context.device.get_channel_switch_status(2)
|
||||||
|
.map(|current| !current)
|
||||||
|
.map_err(|_| Error::new(ErrorCode::HardwareError)),
|
||||||
|
|token| token.try_into()
|
||||||
|
)?;
|
||||||
|
context.device.set_channel_switch(2, next_state).map_err(|_| Error::new(ErrorCode::HardwareError))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Device + UrukulTraits> Command<T> for Channel3SwitchCommand {
|
||||||
|
nquery!();
|
||||||
|
|
||||||
|
fn event(&self, context: &mut Context<T>, args: &mut Tokenizer) -> Result<()> {
|
||||||
|
let next_state: bool = args.next_data(true)?
|
||||||
|
.map_or(
|
||||||
|
context.device.get_channel_switch_status(3)
|
||||||
|
.map(|current| !current)
|
||||||
|
.map_err(|_| Error::new(ErrorCode::HardwareError)),
|
||||||
|
|token| token.try_into()
|
||||||
|
)?;
|
||||||
|
context.device.set_channel_switch(3, next_state).map_err(|_| Error::new(ErrorCode::HardwareError))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle CLOCK:SOURCE command, setup the proper source for the system clock
|
// Handle CLOCK:SOURCE command, setup the proper source for the system clock
|
||||||
// Leave clock division to CLOCK:DIVision command
|
// Leave clock division to CLOCK:DIVision command
|
||||||
|
@ -304,36 +334,57 @@ impl<T:Device + UrukulTraits> Command<T> for Channel0SystemClockCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Channel0AttenuationCommand {}
|
impl<T:Device + UrukulTraits> Command<T> for Channel0AttenuationCommand {
|
||||||
pub struct Channel1AttenuationCommand {}
|
|
||||||
pub struct Channel2AttenuationCommand {}
|
|
||||||
pub struct Channel3AttenuationCommand {}
|
|
||||||
|
|
||||||
macro_rules! impl_channel_attenuation_command {
|
|
||||||
($($channel: literal => $command_struct: ty),*) => {
|
|
||||||
$(
|
|
||||||
impl<T:Device + UrukulTraits> Command<T> for $command_struct {
|
|
||||||
nquery!();
|
nquery!();
|
||||||
|
|
||||||
fn event(&self, context: &mut Context<T>, args: &mut Tokenizer) -> Result<()> {
|
fn event(&self, context: &mut Context<T>, args: &mut Tokenizer) -> Result<()> {
|
||||||
let attenuation: f32 = args.next_data(false)?
|
let attenuation: f32 = args.next_data(false)?
|
||||||
.map_or(Err(Error::new(ErrorCode::IllegalParameterValue)),
|
.map_or(Err(Error::new(ErrorCode::IllegalParameterValue)),
|
||||||
|token| token.try_into())?;
|
|token| token.try_into())?;
|
||||||
trace!("Received channel {} attenuation input: {}", $channel, attenuation);
|
trace!("Received channel 0 attenuation input: {}", attenuation);
|
||||||
context.device.set_channel_attenuation($channel, attenuation)
|
context.device.set_channel_attenuation(0, attenuation)
|
||||||
.map_err(|_| Error::new(ErrorCode::HardwareError))
|
.map_err(|_| Error::new(ErrorCode::HardwareError))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
)*
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_channel_attenuation_command!(
|
impl<T:Device + UrukulTraits> Command<T> for Channel1AttenuationCommand {
|
||||||
0 => Channel0AttenuationCommand,
|
nquery!();
|
||||||
1 => Channel1AttenuationCommand,
|
|
||||||
2 => Channel2AttenuationCommand,
|
fn event(&self, context: &mut Context<T>, args: &mut Tokenizer) -> Result<()> {
|
||||||
3 => Channel3AttenuationCommand
|
let attenuation: f32 = args.next_data(false)?
|
||||||
);
|
.map_or(Err(Error::new(ErrorCode::IllegalParameterValue)),
|
||||||
|
|token| token.try_into())?;
|
||||||
|
trace!("Received channel 1 attenuation input: {}", attenuation);
|
||||||
|
context.device.set_channel_attenuation(1, attenuation)
|
||||||
|
.map_err(|_| Error::new(ErrorCode::HardwareError))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T:Device + UrukulTraits> Command<T> for Channel2AttenuationCommand {
|
||||||
|
nquery!();
|
||||||
|
|
||||||
|
fn event(&self, context: &mut Context<T>, args: &mut Tokenizer) -> Result<()> {
|
||||||
|
let attenuation: f32 = args.next_data(false)?
|
||||||
|
.map_or(Err(Error::new(ErrorCode::IllegalParameterValue)),
|
||||||
|
|token| token.try_into())?;
|
||||||
|
trace!("Received channel 2 attenuation input: {}", attenuation);
|
||||||
|
context.device.set_channel_attenuation(2, attenuation)
|
||||||
|
.map_err(|_| Error::new(ErrorCode::HardwareError))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T:Device + UrukulTraits> Command<T> for Channel3AttenuationCommand {
|
||||||
|
nquery!();
|
||||||
|
|
||||||
|
fn event(&self, context: &mut Context<T>, args: &mut Tokenizer) -> Result<()> {
|
||||||
|
let attenuation: f32 = args.next_data(false)?
|
||||||
|
.map_or(Err(Error::new(ErrorCode::IllegalParameterValue)),
|
||||||
|
|token| token.try_into())?;
|
||||||
|
trace!("Received channel 3 attenuation input: {}", attenuation);
|
||||||
|
context.device.set_channel_attenuation(3, attenuation)
|
||||||
|
.map_err(|_| Error::new(ErrorCode::HardwareError))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T:Device + UrukulTraits> Command<T> for ProfileCommand {
|
impl<T:Device + UrukulTraits> Command<T> for ProfileCommand {
|
||||||
nquery!();
|
nquery!();
|
||||||
|
@ -357,7 +408,7 @@ impl<T:Device + UrukulTraits> Command<T> for ProfileCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T:Device + UrukulTraits> Command<T> for Channel0Profile0SingletoneCommand {
|
impl<T:Device + UrukulTraits> Command<T> for Channel0Profile0Singletone {
|
||||||
nquery!();
|
nquery!();
|
||||||
|
|
||||||
// Params: frequency, phase, amplitude (all mandatory)
|
// Params: frequency, phase, amplitude (all mandatory)
|
||||||
|
@ -402,85 +453,12 @@ impl<T:Device + UrukulTraits> Command<T> for Channel0Profile0SingletoneCommand {
|
||||||
return Err(ErrorCode::DataOutOfRange.into());
|
return Err(ErrorCode::DataOutOfRange.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("Set up a single tone on channel 0, profile 0");
|
// TODO: Setup single tone on DDS
|
||||||
context.device.set_channel_single_tone_profile(0, 0, frequency.get::<hertz>(), phase.get::<degree>(), amplitude)
|
context.device.set_channel_single_tone_profile(0, 0, frequency.get::<hertz>(), phase.get::<degree>(), amplitude)
|
||||||
.map_err(|_| Error::new(ErrorCode::HardwareError))
|
.map_err(|_| Error::new(ErrorCode::HardwareError))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T:Device + UrukulTraits> Command<T> for Channel0Profile0SingletoneFrequencyCommand {
|
|
||||||
// TODO: Implement query for publishing
|
|
||||||
nquery!();
|
|
||||||
|
|
||||||
// Param: frequency
|
|
||||||
fn event(&self, context: &mut Context<T>, args: &mut Tokenizer) -> Result<()> {
|
|
||||||
|
|
||||||
// Read output frequency
|
|
||||||
let frequency: f64::Frequency = args.next_data(false)?
|
|
||||||
.map_or(Err(Error::new(ErrorCode::MissingParameter)), |t| {
|
|
||||||
t.numeric(|s| match s {
|
|
||||||
NumericValues::Default => Ok(f64::Frequency::new::<hertz>(0.0)),
|
|
||||||
_ => Err(ErrorCode::IllegalParameterValue.into()),
|
|
||||||
})
|
|
||||||
})?;
|
|
||||||
trace!("Received channel 0 profile 0 output single tone frequency: {:?}", frequency);
|
|
||||||
// Handle negative frequency
|
|
||||||
if frequency.get::<hertz>() < 0.0 {
|
|
||||||
return Err(ErrorCode::DataOutOfRange.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
context.device.set_channel_single_tone_profile_frequency(0, 0, frequency.get::<hertz>())
|
|
||||||
.map_err(|_| Error::new(ErrorCode::HardwareError))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T:Device + UrukulTraits> Command<T> for Channel0Profile0SingletonePhaseCommand {
|
|
||||||
// TODO: Implement query for publishing
|
|
||||||
nquery!();
|
|
||||||
|
|
||||||
// Param: frequency
|
|
||||||
fn event(&self, context: &mut Context<T>, args: &mut Tokenizer) -> Result<()> {
|
|
||||||
|
|
||||||
// Read phase offset
|
|
||||||
let phase: f64::Angle = args.next_data(false)?
|
|
||||||
.map_or(Err(Error::new(ErrorCode::MissingParameter)), |t| {
|
|
||||||
t.numeric(
|
|
||||||
|s| match s {
|
|
||||||
NumericValues::Default => Ok(f64::Angle::new::<degree>(0.0)),
|
|
||||||
_ => Err(ErrorCode::IllegalParameterValue.into()),
|
|
||||||
})
|
|
||||||
})?;
|
|
||||||
trace!("Received channel 0 profile 0 output single tone phase offset: {:?}", phase);
|
|
||||||
// Handle out-of-bound phase offset
|
|
||||||
if phase.get::<degree>() < 0.0 || phase.get::<degree>() >= 360.0 {
|
|
||||||
return Err(ErrorCode::DataOutOfRange.into());
|
|
||||||
}
|
|
||||||
context.device.set_channel_single_tone_profile_phase(0, 0, phase.get::<degree>())
|
|
||||||
.map_err(|_| Error::new(ErrorCode::HardwareError))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T:Device + UrukulTraits> Command<T> for Channel0Profile0SingletoneAmplitudeCommand {
|
|
||||||
// TODO: Implement query for publishing
|
|
||||||
nquery!();
|
|
||||||
|
|
||||||
// Param: frequency
|
|
||||||
fn event(&self, context: &mut Context<T>, args: &mut Tokenizer) -> Result<()> {
|
|
||||||
|
|
||||||
// Read amplitude offset
|
|
||||||
let amplitude: f64 = args.next_data(false)?
|
|
||||||
.map_or(Err(Error::new(ErrorCode::MissingParameter)),
|
|
||||||
|token| token.try_into())?;
|
|
||||||
trace!("Received channel 0 profile 0 output single tone amplitude offset: {:?}", amplitude);
|
|
||||||
// Handle out-of-bound phase offset
|
|
||||||
if amplitude < 0.0 || amplitude > 1.0 {
|
|
||||||
return Err(ErrorCode::DataOutOfRange.into());
|
|
||||||
}
|
|
||||||
context.device.set_channel_single_tone_profile_amplitude(0, 0, amplitude)
|
|
||||||
.map_err(|_| Error::new(ErrorCode::HardwareError))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implement "Device" trait from SCPI
|
* Implement "Device" trait from SCPI
|
||||||
* TODO: Implement mandatory commands
|
* TODO: Implement mandatory commands
|
||||||
|
|
Loading…
Reference in New Issue