signal_generator: fix config conversion, clarify
@@ -55,28 +55,43 @@ impl Default for BasicConfig {
pub enum Error {
/// The provided amplitude is out-of-range.
InvalidAmplitude,
+ /// The provided symmetry is out of range.
+ InvalidSymmetry,
+ /// The provided frequency is out of range.
+ InvalidFrequency,
}
impl TryFrom<BasicConfig> for Config {
type Error = Error;
fn try_from(config: BasicConfig) -> Result<Config, Error> {
- // Calculate the frequency tuning words
- let frequency_tuning_word: [u32; 2] = {
+ // Validate symmetry
+ if config.symmetry < 0.0 || config.symmetry > 1.0 {
+ return Err(Error::InvalidSymmetry);
+ }
+
const LSB_PER_HERTZ: f32 = (1u64 << (31 + ADC_SAMPLE_TICKS_LOG2))
as f32
/ (TIMER_FREQUENCY.0 * 1_000_000) as f32;
let ftw = config.frequency * LSB_PER_HERTZ;
- if config.symmetry <= ftw / u32::MAX as f32 {
- [1u32 << 31, ftw as u32]
- } else if 1. - config.symmetry <= ftw / u32::MAX as f32 {
- [ftw as u32, 1u32 << 31]
+ // Validate base frequency tuning word to be below Nyquist.
+ const NYQUIST: f32 = (1u32 << 31) as _;
+ if 2.0 * ftw > NYQUIST {
+ return Err(Error::InvalidFrequency);
+ }
+
+ // Calculate the frequency tuning words.
+ let frequency_tuning_word = {
+ let ftws = [ftw / config.symmetry, ftw / (1.0 - config.symmetry)];
+
+ // Clip both frequency tuning words to within Nyquist before rounding.
+ if ftws[0] > NYQUIST {
+ [1u32 << 31, ftws[1] as u32]
+ } else if ftws[1] > NYQUIST {
+ [ftws[0] as u32, 1u32 << 31]
} else {
- [
- (ftw / config.symmetry) as u32,
- (ftw / (1.0 - config.symmetry)) as u32,
- ]
+ [ftws[0] as u32, ftws[1] as u32]
}
};
