From 3673c14cdb2cfdab70973cbae186f456262a6d65 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sun, 24 Dec 2023 23:06:03 +0100 Subject: [PATCH] Added pwm plot --- firmware/src/main.rs | 88 ++++++++++++++-------------------- hostsoftware/src/formatters.rs | 12 +++++ hostsoftware/src/main.rs | 67 ++++++++++++++++++-------- protocol/src/lib.rs | 7 ++- 4 files changed, 99 insertions(+), 75 deletions(-) create mode 100644 hostsoftware/src/formatters.rs diff --git a/firmware/src/main.rs b/firmware/src/main.rs index a34f89e..8e46d6c 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -37,9 +37,9 @@ mod app { use heapless::Vec; use postcard::{from_bytes_cobs, to_vec_cobs}; - use cheapsdo_protocol::{*, DeviceMessage}; + use cheapsdo_protocol::{DeviceMessage, HostMessage, StatusMessage}; - const USB_BUFFER_SIZE : usize = 64; + const USB_BUFFER_SIZE: usize = 64; #[local] struct Local { @@ -53,8 +53,7 @@ mod app { struct Shared { usb_dev: UsbDevice<'static, UsbBusType>, serial: usbd_serial::SerialPort<'static, UsbBusType>, - current_freq: f64, - short_avg: f64, + device_status: StatusMessage, buffer: Vec, } @@ -204,8 +203,7 @@ mod app { Shared { serial, usb_dev, - current_freq: 0.0f64, - short_avg: 0.0f64, + device_status: StatusMessage::default(), buffer: Vec::new(), }, Local { @@ -217,10 +215,9 @@ mod app { ) } - const WINDOW_LEN: usize = 100; - #[task(local=[tim2, tim3, pwm, board_led], shared=[current_freq, short_avg])] + #[task(local=[tim2, tim3, pwm, board_led], shared=[device_status])] async fn update_pwm(mut cx: update_pwm::Context) { defmt::info!("Update Task started"); @@ -278,8 +275,8 @@ mod app { continue; } - cx.shared.current_freq.lock(|current_freq| { - *current_freq = freq; + cx.shared.device_status.lock(|device_status| { + device_status.measured_frequency = freq; }); short_avg += freq / WINDOW_LEN as f64; @@ -289,8 +286,8 @@ mod app { } defmt::info!("short_avg:\t{} MHz", short_avg); - cx.shared.short_avg.lock(|avg| { - *avg = short_avg; + cx.shared.device_status.lock(|device_status| { + device_status.average_frequency = short_avg; }); let diff = (TARGET_FREQ - short_avg) * 1_000_000.0; @@ -305,6 +302,10 @@ mod app { cur_pwm = if cur_pwm < 0 { 0 } else { cur_pwm }; cur_pwm = if cur_pwm > max_pwm { max_pwm } else { cur_pwm }; + cx.shared.device_status.lock(|device_status| { + device_status.pwm = cur_pwm as u16; + }); + pwm.set_duty(Channel::C1, cur_pwm as u16); defmt::info!("pwm:\t{}", cur_pwm); @@ -312,52 +313,39 @@ mod app { } } - #[task(binds = USB_HP_CAN_TX, shared = [usb_dev, serial, buffer, current_freq, short_avg])] + #[task(binds = USB_HP_CAN_TX, shared = [usb_dev, serial, buffer, device_status])] fn usb_tx(cx: usb_tx::Context) { let mut usb_dev = cx.shared.usb_dev; let mut serial = cx.shared.serial; let mut buffer = cx.shared.buffer; - let mut current_freq = cx.shared.current_freq; - let mut short_avg = cx.shared.short_avg; + let mut device_status = cx.shared.device_status; - ( - &mut usb_dev, - &mut serial, - &mut buffer, - &mut current_freq, - &mut short_avg, - ) - .lock(|usb_dev, serial, buffer, current_freq, short_avg| { - usb_poll(usb_dev, serial, buffer, current_freq, short_avg); - }); + (&mut usb_dev, &mut serial, &mut buffer, &mut device_status).lock( + |usb_dev, serial, buffer, device_status| { + usb_poll(usb_dev, serial, buffer, device_status); + }, + ); } - #[task(binds = USB_LP_CAN_RX0, shared = [usb_dev, serial, buffer, current_freq, short_avg])] + #[task(binds = USB_LP_CAN_RX0, shared = [usb_dev, serial, buffer, device_status])] fn usb_rx0(cx: usb_rx0::Context) { let mut usb_dev = cx.shared.usb_dev; let mut serial = cx.shared.serial; let mut buffer = cx.shared.buffer; - let mut current_freq = cx.shared.current_freq; - let mut short_avg = cx.shared.short_avg; + let mut device_status = cx.shared.device_status; - ( - &mut usb_dev, - &mut serial, - &mut buffer, - &mut current_freq, - &mut short_avg, - ) - .lock(|usb_dev, serial, buffer, current_freq, short_avg| { - usb_poll(usb_dev, serial, buffer, current_freq, short_avg); - }); + (&mut usb_dev, &mut serial, &mut buffer, &mut device_status).lock( + |usb_dev, serial, buffer, device_status| { + usb_poll(usb_dev, serial, buffer, device_status); + }, + ); } fn usb_poll( usb_dev: &mut usb_device::prelude::UsbDevice<'static, B>, serial: &mut usbd_serial::SerialPort<'static, B>, buffer: &mut Vec, - current_freq: &mut f64, - short_avg: &mut f64, + device_status: &StatusMessage, ) { if !usb_dev.poll(&mut [serial]) { return; @@ -376,7 +364,7 @@ mod app { loop { if let Some(idx) = buffer.iter().position(|&x| x == 0) { - let (msg, rest) = buffer.split_at(idx+1); + let (msg, rest) = buffer.split_at(idx + 1); let mut message = [0u8; 128]; message[0..msg.len()].clone_from_slice(msg); @@ -385,19 +373,15 @@ mod app { match host_msg { Ok(host_msg) => match host_msg { HostMessage::RequestStatus => { - let device_msg = DeviceMessage::Status(StatusMessage{ - measured_frequency: *current_freq, - average_frequency: *short_avg, - pwm: 0, - }); - - let bytes = to_vec_cobs::(&device_msg).unwrap(); + let device_msg = DeviceMessage::Status(device_status.clone()); + let bytes = + to_vec_cobs::(&device_msg).unwrap(); serial.write(bytes.as_slice()).unwrap(); - }, - HostMessage::SetPLLOutputs => { - defmt::error!("PLL output is not implemented yet") } - } + HostMessage::SetPLLOutputs => { + defmt::error!("PLL output is not implemented yet") + } + }, Err(err) => defmt::error!("Unable to parse host message: {}", err), }; diff --git a/hostsoftware/src/formatters.rs b/hostsoftware/src/formatters.rs new file mode 100644 index 0000000..bdf4f3a --- /dev/null +++ b/hostsoftware/src/formatters.rs @@ -0,0 +1,12 @@ +pub fn frequency(freq: f64) -> String { + let rest = (freq * 1_000_000_000.0) as u64; + let milli_hz = rest % 1000; + let rest = rest / 1000; + let hz = rest % 1000; + let rest = rest / 1000; + let khz = rest % 1000; + let rest = rest / 1000; + let mhz = rest % 1000; + + format!("{:02}.{:03} {:03} {:03} MHz", mhz, khz, hz, milli_hz) +} diff --git a/hostsoftware/src/main.rs b/hostsoftware/src/main.rs index 32cd28c..47526e2 100644 --- a/hostsoftware/src/main.rs +++ b/hostsoftware/src/main.rs @@ -11,6 +11,8 @@ use egui_plot::{Line, Plot, PlotBounds, PlotPoints}; use cheapsdo_protocol::*; use postcard::{from_bytes_cobs, to_stdvec_cobs}; +mod formatters; + fn main() -> Result<(), eframe::Error> { let options = eframe::NativeOptions { viewport: egui::ViewportBuilder::default(), @@ -27,6 +29,7 @@ struct SharedState { device_state: StatusMessage, average_points: Vec<[f64; 2]>, measured_points: Vec<[f64; 2]>, + pwm_points: Vec<[f64; 2]>, } impl Default for SharedState { @@ -35,6 +38,7 @@ impl Default for SharedState { device_state: StatusMessage::default(), average_points: Vec::<[f64; 2]>::new(), measured_points: Vec::<[f64; 2]>::new(), + pwm_points: Vec::<[f64; 2]>::new(), } } } @@ -100,38 +104,62 @@ impl eframe::App for CheapsdoControl { { let mut state = self.shared_state.lock().unwrap(); ui.horizontal(|ui| { - ui.label(format!( - "Measured: {}", - state.device_state.measured_frequency - )); - ui.label(format!("Average: {}", state.device_state.average_frequency)); + ui.label( + egui::RichText::new(format!( + "Measured: {}", + formatters::frequency(state.device_state.measured_frequency) + )) + .family(egui::FontFamily::Monospace) + .size(20.0), + ); + + ui.add_space(100.0); + + ui.label( + egui::RichText::new(format!( + "Average: {}", + formatters::frequency(state.device_state.average_frequency) + )) + .family(egui::FontFamily::Monospace) + .size(20.0), + ); }); + ui.add_space(20.0); + let average_line = Line::new(PlotPoints::new(state.average_points.clone())); let measured_line = Line::new(PlotPoints::new(state.measured_points.clone())); - Plot::new("my_plot") + Plot::new("frequency_plot") + .view_aspect(4.0) .allow_zoom(false) .allow_scroll(false) .allow_drag(false) .allow_boxed_zoom(false) - .y_axis_width(20) - .y_axis_formatter(|val, _, _| { - let rest = (val * 1_000_000_000.0) as u64; - let milli_hz = rest % 1000; - let rest = rest / 1000; - let hz = rest % 1000; - let rest = rest / 1000; - let khz = rest % 1000; - let rest = rest / 1000; - let mhz = rest % 1000; - - format!("{:02}.{:03} {:03} {:03}", mhz, khz, hz, milli_hz) + .y_axis_width(12) + .y_axis_formatter(|val, _, _| formatters::frequency(val)) + .label_formatter(|name, value| { + format!("{}: {}", name, formatters::frequency(value.y)) }) .show(ui, |plot_ui| { plot_ui.set_auto_bounds([true, true].into()); plot_ui.line(average_line); //plot_ui.line(measured_line); - }) + }); + + ui.add_space(20.0); + + let pwm_line = Line::new(PlotPoints::new(state.pwm_points.clone())); + Plot::new("pwm_plot") + .view_aspect(4.0) + .allow_zoom(false) + .allow_scroll(false) + .allow_drag(false) + .allow_boxed_zoom(false) + .y_axis_width(12) + .show(ui, |plot_ui| { + plot_ui.set_auto_bounds([true, true].into()); + plot_ui.line(pwm_line); + }); } }); } @@ -165,6 +193,7 @@ fn poll_device(port: String, state: Arc>, ctx: egui::Context) state .measured_points .push([x, status_msg.measured_frequency]); + state.pwm_points.push([x, status_msg.pwm as f64]); state.device_state = status_msg; ctx.request_repaint() diff --git a/protocol/src/lib.rs b/protocol/src/lib.rs index c06ce49..9ac5663 100644 --- a/protocol/src/lib.rs +++ b/protocol/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug, PartialEq)] pub enum DeviceMessage { @@ -13,14 +13,13 @@ pub enum HostMessage { SetPLLOutputs, } -#[derive(Serialize, Deserialize, Debug, PartialEq)] +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] pub struct StatusMessage { pub measured_frequency: f64, pub average_frequency: f64, pub pwm: u16, } - impl Default for StatusMessage { fn default() -> Self { Self { @@ -29,4 +28,4 @@ impl Default for StatusMessage { pwm: 0u16, } } -} \ No newline at end of file +}