Skip to content

Commit

Permalink
Merge pull request #27 from quartiq/feature/interlock-config
Browse files Browse the repository at this point in the history
Initial interlock configuration and RF channel management structure
  • Loading branch information
ryan-summers authored Jul 9, 2020
2 parents 34c0524 + 30799fe commit 27f2b50
Show file tree
Hide file tree
Showing 7 changed files with 563 additions and 10 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ cortex-m-rt = "0.6.10"
panic-halt = "0.2.0"
cortex-m-rtic = "0.5.3"
embedded-hal = "0.2.4"
enum-iterator = "0.6.0"
cortex-m-log = { version = "0.6.1", features = ["log-integration"] }
log = "0.4.8"
shared-bus-rtic = "0.1.2"
Expand Down
1 change: 1 addition & 0 deletions ads7924/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub enum Channel {
}

/// Indicates errors that the ADC may encounter.
#[derive(Debug)]
pub enum Error {
Interface,
Size,
Expand Down
1 change: 1 addition & 0 deletions dac7571/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ where
}

/// Represents errors that can be generated by the DAC driver.
#[derive(Debug)]
pub enum Error {
Bounds,
Interface,
Expand Down
133 changes: 133 additions & 0 deletions src/booster_channels.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//! Booster NGFW channel management control interface definitions.
//!
//! # Copyright
//! Copyright (C) 2020 QUARTIQ GmbH - All Rights Reserved
//! Unauthorized usage, editing, or copying is strictly prohibited.
//! Proprietary and confidential.
use enum_iterator::IntoEnumIterator;
use tca9548::{self, Tca9548};

use super::{BusManager, BusProxy, I2C};
use crate::error::Error;
use crate::rf_channel::{ChannelPins as RfChannelPins, RfChannel};

/// Represents a control structure for interfacing to booster RF channels.
pub struct BoosterChannels {
channels: [Option<RfChannel>; 8],
mux: Tca9548<BusProxy<I2C>>,
}

/// Indicates a booster RF channel.
#[derive(IntoEnumIterator, Copy, Clone, Debug)]
pub enum Channel {
Zero = 0,
One = 1,
Two = 2,
Three = 3,
Four = 4,
Five = 5,
Six = 6,
Seven = 7,
}

impl Into<tca9548::Bus> for Channel {
fn into(self) -> tca9548::Bus {
match self {
Channel::Zero => tca9548::Bus::Zero,
Channel::One => tca9548::Bus::One,
Channel::Two => tca9548::Bus::Two,
Channel::Three => tca9548::Bus::Three,
Channel::Four => tca9548::Bus::Four,
Channel::Five => tca9548::Bus::Five,
Channel::Six => tca9548::Bus::Six,
Channel::Seven => tca9548::Bus::Seven,
}
}
}

impl BoosterChannels {
/// Construct booster RF channels.
///
/// # Note
/// This function will scan channels to check if they are present.
///
/// # Args
/// * `mux` - The I2C mux used for switching between channel communications.
/// * `manager` - The I2C bus manager used for the shared I2C bus.
/// * `pins` - An array of all RfChannel control/status pins.
///
/// # Returns
/// A `BoosterChannels` object that can be used to manage all available RF channels.
pub fn new(
mut mux: Tca9548<BusProxy<I2C>>,
manager: &'static BusManager,
mut pins: [Option<RfChannelPins>; 8],
) -> Self {
let mut rf_channels: [Option<RfChannel>; 8] =
[None, None, None, None, None, None, None, None];

for channel in Channel::into_enum_iter() {
// Selecting an I2C bus should never fail.
mux.select_bus(Some(channel.into()))
.expect("Failed to select channel");

let control_pins = pins[channel as usize]
.take()
.expect("Channel pins not available");

match RfChannel::new(manager, control_pins) {
Some(mut rf_channel) => {
// Setting interlock thresholds should not fail here as we have verified the
// device is on the bus.
rf_channel.set_interlock_thresholds(0.0, 0.0).unwrap();
rf_channels[channel as usize].replace(rf_channel);
}
None => {
info!("Channel {} did not enumerate", channel as usize);
}
}
}

BoosterChannels {
channels: rf_channels,
mux: mux,
}
}

/// Set the interlock thresholds for the channel.
///
/// # Args
/// * `channel` - The RF channel to set thresholds for.
/// * `forward_threshold` - The dBm interlock threshold for forward power.
/// * `reflected_threshold` - The dBm interlock threshold for reflected power.
pub fn set_interlock_thresholds(
&mut self,
channel: Channel,
forward_threshold: f32,
reflected_threshold: f32,
) -> Result<(), Error> {
if self.channels[channel as usize].is_none() {
return Err(Error::NotPresent);
}

// Selecting an I2C bus should never fail.
self.mux
.select_bus(Some(channel.into()))
.expect("Failed to select channel");

match &mut self.channels[channel as usize] {
Some(rf_channel) => {
match rf_channel.set_interlock_thresholds(forward_threshold, reflected_threshold) {
// Configuring a present channel should never have an interface failure
// (although the requested value may be out of range).
Err(Error::Interface) => {
panic!("Failed to configure thresholds on CH{}", channel as usize);
}
x => x,
}
}
None => Err(Error::NotPresent),
}
}
}
15 changes: 15 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//! Error type definitions for Booster NGFW
//!
//! # Copyright
//! Copyright (C) 2020 QUARTIQ GmbH - All Rights Reserved
//! Unauthorized usage, editing, or copying is strictly prohibited.
//! Proprietary and confidential.
/// An enumeration of possible errors with the device.
#[derive(Debug, Copy, Clone)]
pub enum Error {
Invalid,
NotPresent,
Interface,
Bounds,
}
131 changes: 121 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ use shared_bus_rtic::{self, BusProxy};
use stm32f4xx_hal as hal;

use hal::prelude::*;
use tca9548::Tca9548;

mod booster_channels;
mod error;
mod rf_channel;
use booster_channels::BoosterChannels;
use rf_channel::{AdcPins, ChannelPins as RfChannelPins};

// Convenience type definition for the I2C bus used for booster RF channels.
type I2C = hal::i2c::I2c<
Expand All @@ -27,10 +32,65 @@ type I2C = hal::i2c::I2c<
),
>;

// Convenience type definition for the shared bus BusManager type.
type BusManager = shared_bus_rtic::shared_bus::BusManager<shared_bus_rtic::Mutex<I2C>, I2C>;

/// Construct ADC pins associated with an RF channel.
///
/// # Args
/// * `gpio` - The GPIO port used to instantiate analog pins.
/// * `tx_power` - The name of the pin to instantiate for the TX power measurement.
/// * `reflected_power` - The name of the pin to instantiate for the reflected power measurement.
///
/// # Returns
/// An AdcPin enumeration describing the ADC pins.
macro_rules! adc_pins {
($gpio:ident, $tx_power:ident, $reflected_power:ident) => {{
let tx_power = $gpio.$tx_power.into_analog().downgrade();
let reflected_power = $gpio.$reflected_power.into_analog().downgrade();

AdcPins::$gpio(tx_power, reflected_power)
}};
}

/// Macro for genering an RfChannelPins structure.
///
/// # Args
/// * `gpiod` - The GPIOD Parts structure to extract pins from.
/// * `gpioe` - The GPIOE Parts structure to extract pins from.
/// * `gpiog` - The GPIOG Parts structure to extract pins from.
/// * `enable` - The pin ID of the enable pin in GPIOD.
/// * `alert` - The pin ID of the alert pin in GPIOD.
/// * `input_overdrive` - The pin ID of the input overdrive pin in GPIOE.
/// * `output_overdrive` - The pin ID of the output overdrive pin in GPIOE.
/// * `signal_on` - The pin ID of the signal on pin in GPIOG.
///
/// # Returns
/// An option containing the RfChannelPins structure.
macro_rules! channel_pins {
($gpiod:ident, $gpioe:ident, $gpiog:ident, $enable:ident, $alert:ident, $input_overdrive:ident,
$output_overdrive:ident, $signal_on:ident, $analog_pins:ident) => {{
let enable_power = $gpiod.$enable.into_push_pull_output().downgrade();
let alert = $gpiod.$alert.into_floating_input().downgrade();
let input_overdrive = $gpioe.$input_overdrive.into_floating_input().downgrade();
let output_overdrive = $gpioe.$output_overdrive.into_pull_down_input().downgrade();
let signal_on = $gpiog.$signal_on.into_push_pull_output().downgrade();

Some(RfChannelPins::new(
enable_power,
alert,
input_overdrive,
output_overdrive,
signal_on,
$analog_pins,
))
}};
}

#[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true)]
const APP: () = {
struct Resources {
mux: Tca9548<BusProxy<I2C>>,
channels: BoosterChannels,
}

#[init]
Expand All @@ -49,10 +109,16 @@ const APP: () = {
.require_pll48clk()
.freeze();

let gpiob = c.device.GPIOB.split();

let mut delay = hal::delay::Delay::new(cp.SYST, clocks);

let gpioa = c.device.GPIOA.split();
let gpiob = c.device.GPIOB.split();
let gpioc = c.device.GPIOC.split();
let gpiod = c.device.GPIOD.split();
let gpioe = c.device.GPIOE.split();
let gpiof = c.device.GPIOF.split();
let gpiog = c.device.GPIOG.split();

let i2c_bus_manager = {
let i2c = {
let scl = gpiob.pb6.into_alternate_af4_open_drain();
Expand All @@ -63,18 +129,63 @@ const APP: () = {
shared_bus_rtic::new!(i2c, I2C)
};

let mux = {
let mut i2c_mux_reset = gpiob.pb14.into_push_pull_output();
tca9548::Tca9548::default(i2c_bus_manager.acquire(), &mut i2c_mux_reset, &mut delay)
.unwrap()
// Instantiate the I2C interface to the I2C mux. Use a shared-bus so we can share the I2C
// bus with all of the Booster peripheral devices.
let channels = {
let channel_pins = {
let ch1_pins = {
let analog_pins = adc_pins!(gpioa, pa0, pa1);
channel_pins!(gpiod, gpioe, gpiog, pd0, pd8, pe8, pe0, pg8, analog_pins)
};
let ch2_pins = {
let analog_pins = adc_pins!(gpioa, pa2, pa3);
channel_pins!(gpiod, gpioe, gpiog, pd1, pd9, pe9, pe1, pg9, analog_pins)
};
let ch3_pins = {
let analog_pins = adc_pins!(gpiof, pf6, pf7);
channel_pins!(gpiod, gpioe, gpiog, pd2, pd10, pe10, pe2, pg10, analog_pins)
};
let ch4_pins = {
let analog_pins = adc_pins!(gpiof, pf8, pf9);
channel_pins!(gpiod, gpioe, gpiog, pd3, pd11, pe11, pe3, pg11, analog_pins)
};
let ch5_pins = {
let analog_pins = adc_pins!(gpiof, pf10, pf3);
channel_pins!(gpiod, gpioe, gpiog, pd4, pd12, pe12, pe4, pg12, analog_pins)
};
let ch6_pins = {
let analog_pins = adc_pins!(gpioc, pc0, pc1);
channel_pins!(gpiod, gpioe, gpiog, pd5, pd13, pe13, pe5, pg13, analog_pins)
};
let ch7_pins = {
let analog_pins = adc_pins!(gpioc, pc2, pc3);
channel_pins!(gpiod, gpioe, gpiog, pd6, pd14, pe14, pe6, pg14, analog_pins)
};
let ch8_pins = {
let analog_pins = adc_pins!(gpiof, pf4, pf5);
channel_pins!(gpiod, gpioe, gpiog, pd7, pd15, pe15, pe7, pg15, analog_pins)
};

[
ch1_pins, ch2_pins, ch3_pins, ch4_pins, ch5_pins, ch6_pins, ch7_pins, ch8_pins,
]
};

let mux = {
let mut i2c_mux_reset = gpiob.pb14.into_push_pull_output();
tca9548::Tca9548::default(i2c_bus_manager.acquire(), &mut i2c_mux_reset, &mut delay)
.unwrap()
};

BoosterChannels::new(mux, &i2c_bus_manager, channel_pins)
};

info!("Startup complete");

init::LateResources { mux }
init::LateResources { channels: channels }
}

#[idle(resources=[mux])]
#[idle(resources=[channels])]
fn idle(_: idle::Context) -> ! {
loop {
asm::nop();
Expand Down
Loading

0 comments on commit 27f2b50

Please sign in to comment.