diff --git a/mcu-contrib/default.nix b/mcu-contrib/default.nix
index 6527371..cfe8832 100644
--- a/mcu-contrib/default.nix
+++ b/mcu-contrib/default.nix
@@ -8,8 +8,8 @@ let
     "thumbv7em-none-eabihf"
   ];
   rustManifest = pkgs.fetchurl {
-    url = "https://static.rust-lang.org/dist/2024-06-13/channel-rust-stable.toml";
-    sha256 = "sha256-Ngiz76YP4HTY75GGdH2P+APE/DEIx2R/Dn+BwwOyzZU=";
+    url = "https://static.rust-lang.org/dist/2024-11-28/channel-rust-stable.toml";
+    sha256 = "b3544fb72bc3189697fc18ac2d3fa27d57ee8434f59d9919d4d70af2c6f010b3";
   };
   rustChannelOfTargets = _channel: _date: targets:
     (pkgs.lib.rustLib.fromManifestFile rustManifest {
diff --git a/mcu-contrib/pounder-725.diff b/mcu-contrib/pounder-725.diff
index fc7b2c3..7e3adb7 100644
--- a/mcu-contrib/pounder-725.diff
+++ b/mcu-contrib/pounder-725.diff
@@ -216,7 +216,7 @@ index 025f7d4f..59578cce 100644
      fn add_write(&mut self, register: Register, value: &[u8]) {
          let data = &mut self.data[self.index..];
 diff --git a/src/bin/dual-iir.rs b/src/bin/dual-iir.rs
-index ea566e14..84bde34a 100644
+index d4146cc2..e7f9cf28 100644
 --- a/src/bin/dual-iir.rs
 +++ b/src/bin/dual-iir.rs
 @@ -28,7 +28,7 @@
@@ -226,9 +226,9 @@ index ea566e14..84bde34a 100644
 -use core::mem::MaybeUninit;
 +use core::mem::{MaybeUninit, size_of};
  use core::sync::atomic::{fence, Ordering};
+ use miniconf::{Leaf, Tree};
  use serde::{Deserialize, Serialize};
- 
-@@ -47,6 +47,8 @@ use stabilizer::{
+@@ -48,6 +48,8 @@ use stabilizer::{
          dac::{Dac0Output, Dac1Output, DacCode},
          hal,
          signal_generator::{self, SignalGenerator},
@@ -237,9 +237,9 @@ index ea566e14..84bde34a 100644
          timers::SamplingTimer,
          DigitalInput0, DigitalInput1, SerialTerminal, SystemTimer, Systick,
          UsbDevice, AFE0, AFE1,
-@@ -179,6 +181,16 @@ pub struct DualIir {
+@@ -173,6 +175,16 @@ pub struct DualIir {
+     /// # Value
      /// See [signal_generator::BasicConfig#miniconf]
-     #[tree(depth = 2)]
      source: [signal_generator::BasicConfig; 2],
 +
 +    /// Specifies the config for pounder DDS clock configuration, DDS channels & attenuations
@@ -254,7 +254,7 @@ index ea566e14..84bde34a 100644
  }
  
  impl Default for DualIir {
-@@ -206,6 +218,8 @@ impl Default for DualIir {
+@@ -200,6 +212,8 @@ impl Default for DualIir {
              source: Default::default(),
  
              stream: Default::default(),
@@ -263,7 +263,7 @@ index ea566e14..84bde34a 100644
          }
      }
  }
-@@ -222,6 +236,7 @@ mod app {
+@@ -216,6 +230,7 @@ mod app {
          active_settings: DualIir,
          telemetry: TelemetryBuffer,
          source: [SignalGenerator; 2],
@@ -271,7 +271,7 @@ index ea566e14..84bde34a 100644
      }
  
      #[local]
-@@ -233,6 +248,7 @@ mod app {
+@@ -227,6 +242,7 @@ mod app {
          adcs: (Adc0Input, Adc1Input),
          dacs: (Dac0Output, Dac1Output),
          iir_state: [[[f32; 4]; IIR_CASCADE_LENGTH]; 2],
@@ -279,7 +279,7 @@ index ea566e14..84bde34a 100644
          generator: FrameGenerator,
          cpu_temp_sensor: stabilizer::hardware::cpu_temp_sensor::CpuTempSensor,
      }
-@@ -242,7 +258,7 @@ mod app {
+@@ -236,7 +252,7 @@ mod app {
          let clock = SystemTimer::new(|| Systick::now().ticks());
  
          // Configure the microcontroller
@@ -288,7 +288,7 @@ index ea566e14..84bde34a 100644
              c.core,
              c.device,
              clock,
-@@ -261,6 +277,13 @@ mod app {
+@@ -255,6 +271,13 @@ mod app {
  
          let generator = network.configure_streaming(StreamFormat::AdcDacData);
  
@@ -302,7 +302,7 @@ index ea566e14..84bde34a 100644
          let shared = Shared {
              usb: stabilizer.usb,
              network,
-@@ -279,6 +302,7 @@ mod app {
+@@ -273,6 +296,7 @@ mod app {
                  ),
              ],
              settings: stabilizer.settings,
@@ -310,7 +310,7 @@ index ea566e14..84bde34a 100644
          };
  
          let mut local = Local {
-@@ -289,6 +313,7 @@ mod app {
+@@ -283,6 +307,7 @@ mod app {
              adcs: stabilizer.adcs,
              dacs: stabilizer.dacs,
              iir_state: [[[0.; 4]; IIR_CASCADE_LENGTH]; 2],
@@ -318,7 +318,7 @@ index ea566e14..84bde34a 100644
              generator,
              cpu_temp_sensor: stabilizer.temperature_sensor,
          };
-@@ -458,7 +483,7 @@ mod app {
+@@ -452,7 +477,7 @@ mod app {
          }
      }
  
@@ -326,8 +326,8 @@ index ea566e14..84bde34a 100644
 +    #[task(priority = 1, local=[afes, dds_clock_state], shared=[network, settings, active_settings, source, pounder])]
      async fn settings_update(mut c: settings_update::Context) {
          c.shared.settings.lock(|settings| {
-             c.local.afes.0.set_gain(settings.dual_iir.afe[0]);
-@@ -480,6 +505,17 @@ mod app {
+             c.local.afes.0.set_gain(*settings.dual_iir.afe[0]);
+@@ -474,6 +499,17 @@ mod app {
                      ),
                  }
              }
@@ -345,7 +345,7 @@ index ea566e14..84bde34a 100644
  
              c.shared
                  .network
-@@ -491,21 +527,30 @@ mod app {
+@@ -485,22 +521,31 @@ mod app {
          });
      }
  
@@ -353,15 +353,16 @@ index ea566e14..84bde34a 100644
 +    #[task(priority = 1, shared=[network, settings, telemetry, pounder], local=[cpu_temp_sensor])]
      async fn telemetry(mut c: telemetry::Context) {
          loop {
-             let telemetry = c.shared.telemetry.lock(|telemetry| *telemetry);
+             let telemetry =
+                 c.shared.telemetry.lock(|telemetry| telemetry.clone());
  
 -            let (gains, telemetry_period) =
 +            let (gains, telemetry_period, pounder_config) =
                  c.shared.settings.lock(|settings| {
--                    (settings.dual_iir.afe, settings.dual_iir.telemetry_period)
+-                    (settings.dual_iir.afe, *settings.dual_iir.telemetry_period)
 +                    (
 +                        settings.dual_iir.afe,
-+                        settings.dual_iir.telemetry_period,
++                        *settings.dual_iir.telemetry_period,
 +                        settings.dual_iir.pounder
 +                    )
                  });
@@ -372,15 +373,15 @@ index ea566e14..84bde34a 100644
 +
              c.shared.network.lock(|net| {
                  net.telemetry.publish(&telemetry.finalize(
-                     gains[0],
-                     gains[1],
+                     *gains[0],
+                     *gains[1],
                      c.local.cpu_temp_sensor.get_temperature().unwrap(),
 +                    pounder_telemetry,
                  ))
              });
  
 diff --git a/src/bin/lockin.rs b/src/bin/lockin.rs
-index 3ddecd7c..77a7474b 100644
+index d8d193dd..4aff9517 100644
 --- a/src/bin/lockin.rs
 +++ b/src/bin/lockin.rs
 @@ -29,7 +29,7 @@
@@ -392,9 +393,9 @@ index 3ddecd7c..77a7474b 100644
      sync::atomic::{fence, Ordering},
  };
  
-@@ -547,6 +547,7 @@ mod app {
-                     gains[0],
-                     gains[1],
+@@ -543,6 +543,7 @@ mod app {
+                     *gains[0],
+                     *gains[1],
                      c.local.cpu_temp_sensor.get_temperature().unwrap(),
 +                    None,
                  ))
@@ -489,7 +490,7 @@ index 3ae1ce90..cd978b01 100644
      #[allow(dead_code)]
      #[inline]
 diff --git a/src/hardware/pounder/mod.rs b/src/hardware/pounder/mod.rs
-index 5bc7e9ff..5b8d5d30 100644
+index c144db0c..a6831605 100644
 --- a/src/hardware/pounder/mod.rs
 +++ b/src/hardware/pounder/mod.rs
 @@ -1,10 +1,17 @@
@@ -502,28 +503,30 @@ index 5bc7e9ff..5b8d5d30 100644
 +use ad9959::{
 +    amplitude_to_acr, frequency_to_ftw, phase_to_pow, validate_clocking,
 +};
- use embedded_hal::blocking::spi::Transfer;
+ use embedded_hal_02::blocking::spi::Transfer;
  use enum_iterator::Sequence;
-+use miniconf::Tree;
++use miniconf::{Leaf, Tree};
 +use rf_power::PowerMeasurementInterface;
  use serde::{Deserialize, Serialize};
 +use stm32h7xx_hal::time::MegaHertz;
  
  pub mod attenuators;
  pub mod dds_output;
-@@ -120,40 +127,99 @@ impl From<Channel> for GpioPin {
+@@ -120,38 +127,97 @@ impl From<Channel> for GpioPin {
      }
  }
  
 -#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
 -pub struct DdsChannelState {
 -    pub phase_offset: f32,
+-    pub frequency: f32,
+-    pub amplitude: f32,
+-    pub enabled: bool,
 +#[derive(Serialize, Deserialize, Copy, Clone, Debug, Tree)]
 +pub struct DdsChannelConfig {
-     pub frequency: f32,
-+    pub phase_offset: f32,
-     pub amplitude: f32,
--    pub enabled: bool,
++    pub frequency: Leaf<f32>,
++    pub phase_offset: Leaf<f32>,
++    pub amplitude: Leaf<f32>,
  }
  
 -#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
@@ -533,9 +536,9 @@ index 5bc7e9ff..5b8d5d30 100644
 +impl Default for DdsChannelConfig {
 +    fn default() -> Self {
 +        Self {
-+            frequency: 0.0,
-+            phase_offset: 0.0,
-+            amplitude: 0.0,
++            frequency: 0.0.into(),
++            phase_offset: 0.0.into(),
++            amplitude: 0.0.into(),
 +        }
 +    }
  }
@@ -557,8 +560,12 @@ index 5bc7e9ff..5b8d5d30 100644
 +    /// Control amplitudes of DDS channels. It corresponds to the AD9959 ACR register, which
 +    /// controls the amplitude scaling factor of DDS channels.
 +    pub amplitude_control: u32,
-+}
-+
+ }
+ 
+-#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
+-pub struct OutputChannelState {
+-    pub attenuation: f32,
+-    pub channel: DdsChannelState,
 +impl TryFrom<(ClockConfig, ChannelConfig)> for Profile {
 +    type Error = ad9959::Error;
 +
@@ -566,52 +573,52 @@ index 5bc7e9ff..5b8d5d30 100644
 +        (clocking, channel): (ClockConfig, ChannelConfig),
 +    ) -> Result<Self, Self::Error> {
 +        let system_clock_frequency =
-+            clocking.reference_clock * clocking.multiplier as f32;
++            *clocking.reference_clock * *clocking.multiplier as f32;
 +        Ok(Profile {
 +            frequency_tuning_word: frequency_to_ftw(
-+                channel.dds.frequency,
++                *channel.dds.frequency,
 +                system_clock_frequency,
 +            )?,
-+            phase_offset: phase_to_pow(channel.dds.phase_offset)?,
-+            amplitude_control: amplitude_to_acr(channel.dds.amplitude)?,
++            phase_offset: phase_to_pow(*channel.dds.phase_offset)?,
++            amplitude_control: amplitude_to_acr(*channel.dds.amplitude)?,
 +        })
 +    }
  }
  
 -#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
--pub struct OutputChannelState {
+-pub struct DdsClockConfig {
+-    pub multiplier: u8,
+-    pub reference_clock: f32,
+-    pub external_clock: bool,
 +#[derive(Serialize, Deserialize, Copy, Clone, Debug, Tree)]
 +pub struct ChannelConfig {
 +    #[tree]
 +    pub dds: DdsChannelConfig,
-     pub attenuation: f32,
--    pub channel: DdsChannelState,
- }
- 
--#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
--pub struct DdsClockConfig {
++    pub attenuation: Leaf<f32>,
++}
++
 +impl Default for ChannelConfig {
 +    fn default() -> Self {
 +        ChannelConfig {
 +            dds: DdsChannelConfig::default(),
-+            attenuation: 31.5,
++            attenuation: 31.5.into(),
 +        }
 +    }
 +}
 +
 +#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Tree)]
 +pub struct ClockConfig {
-     pub multiplier: u8,
-     pub reference_clock: f32,
-     pub external_clock: bool,
- }
- 
++    pub multiplier: Leaf<u8>,
++    pub reference_clock: Leaf<f32>,
++    pub external_clock: Leaf<bool>,
++}
++
 +impl Default for ClockConfig {
 +    fn default() -> Self {
 +        Self {
-+            multiplier: 5,
-+            reference_clock: MegaHertz::MHz(100).to_Hz() as f32,
-+            external_clock: false,
++            multiplier: 5.into(),
++            reference_clock: (MegaHertz::MHz(100).to_Hz() as f32).into(),
++            external_clock: false.into(),
 +        }
 +    }
 +}
@@ -620,15 +627,13 @@ index 5bc7e9ff..5b8d5d30 100644
 +pub struct PounderConfig {
 +    #[tree]
 +    pub clock: ClockConfig,
-+    #[tree(depth = 2)]
++    #[tree]
 +    pub in_channel: [ChannelConfig; 2],
-+    #[tree(depth = 2)]
++    #[tree]
 +    pub out_channel: [ChannelConfig; 2],
-+}
-+
+ }
+ 
  impl From<Channel> for ad9959::Channel {
-     /// Translate pounder channels to DDS output channels.
-     fn from(other: Channel) -> Self {
 @@ -585,3 +651,78 @@ impl rf_power::PowerMeasurementInterface for PounderDevices {
          Ok(adc_scale * 2.048)
      }
@@ -642,19 +647,19 @@ index 5bc7e9ff..5b8d5d30 100644
 +    ) {
 +        if *clocking != settings.clock {
 +            match validate_clocking(
-+                settings.clock.reference_clock,
-+                settings.clock.multiplier,
++                *settings.clock.reference_clock,
++                *settings.clock.multiplier,
 +            ) {
 +                Ok(_frequency) => {
 +                    self.pounder
-+                        .set_ext_clk(settings.clock.external_clock)
++                        .set_ext_clk(*settings.clock.external_clock)
 +                        .unwrap();
 +
 +                    self.dds_output
 +                        .builder()
 +                        .set_system_clock(
-+                            settings.clock.reference_clock,
-+                            settings.clock.multiplier,
++                            *settings.clock.reference_clock,
++                            *settings.clock.multiplier,
 +                        )
 +                        .unwrap()
 +                        .write();
@@ -685,7 +690,7 @@ index 5bc7e9ff..5b8d5d30 100644
 +
 +                    if let Err(err) = self.pounder.set_attenuation(
 +                        pounder_channel,
-+                        channel_config.attenuation,
++                        *channel_config.attenuation,
 +                    ) {
 +                        log::error!("Invalid attenuation settings: {:?}", err)
 +                    }
@@ -722,7 +727,7 @@ index 714ec57f..d442f197 100644
      box_pool,
      pool::boxed::{Box, BoxBlock},
 diff --git a/src/net/mod.rs b/src/net/mod.rs
-index 43733fa8..a8b90f86 100644
+index 8d815e51..5541f8ba 100644
 --- a/src/net/mod.rs
 +++ b/src/net/mod.rs
 @@ -32,14 +32,14 @@ pub type NetworkReference =
@@ -743,7 +748,7 @@ index 43733fa8..a8b90f86 100644
      }
  }
 diff --git a/src/net/telemetry.rs b/src/net/telemetry.rs
-index c8eb536b..116382a3 100644
+index 6b42b97c..48f9828e 100644
 --- a/src/net/telemetry.rs
 +++ b/src/net/telemetry.rs
 @@ -16,7 +16,7 @@ use minimq::{DeferredPublication, Publication};
@@ -781,8 +786,8 @@ index c8eb536b..116382a3 100644
 +    pub config: PounderConfig,
  }
  
- impl Default for TelemetryBuffer {
-@@ -87,10 +107,17 @@ impl TelemetryBuffer {
+ impl TelemetryBuffer {
+@@ -77,10 +97,17 @@ impl TelemetryBuffer {
      /// * `afe0` - The current AFE configuration for channel 0.
      /// * `afe1` - The current AFE configuration for channel 1.
      /// * `cpu_temp` - The current CPU temperature.
@@ -801,7 +806,7 @@ index c8eb536b..116382a3 100644
          let in0_volts = Into::<f32>::into(self.adcs[0]) / afe0.as_multiplier();
          let in1_volts = Into::<f32>::into(self.adcs[1]) / afe1.as_multiplier();
  
-@@ -99,6 +126,7 @@ impl TelemetryBuffer {
+@@ -89,6 +116,7 @@ impl TelemetryBuffer {
              adcs: [in0_volts, in1_volts],
              dacs: [self.dacs[0].into(), self.dacs[1].into()],
              digital_inputs: self.digital_inputs,