Added pwm plot
This commit is contained in:
parent
c5bec82d59
commit
3673c14cdb
|
@ -37,9 +37,9 @@ mod app {
|
||||||
use heapless::Vec;
|
use heapless::Vec;
|
||||||
use postcard::{from_bytes_cobs, to_vec_cobs};
|
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]
|
#[local]
|
||||||
struct Local {
|
struct Local {
|
||||||
|
@ -53,8 +53,7 @@ mod app {
|
||||||
struct Shared {
|
struct Shared {
|
||||||
usb_dev: UsbDevice<'static, UsbBusType>,
|
usb_dev: UsbDevice<'static, UsbBusType>,
|
||||||
serial: usbd_serial::SerialPort<'static, UsbBusType>,
|
serial: usbd_serial::SerialPort<'static, UsbBusType>,
|
||||||
current_freq: f64,
|
device_status: StatusMessage,
|
||||||
short_avg: f64,
|
|
||||||
buffer: Vec<u8, USB_BUFFER_SIZE>,
|
buffer: Vec<u8, USB_BUFFER_SIZE>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,8 +203,7 @@ mod app {
|
||||||
Shared {
|
Shared {
|
||||||
serial,
|
serial,
|
||||||
usb_dev,
|
usb_dev,
|
||||||
current_freq: 0.0f64,
|
device_status: StatusMessage::default(),
|
||||||
short_avg: 0.0f64,
|
|
||||||
buffer: Vec::new(),
|
buffer: Vec::new(),
|
||||||
},
|
},
|
||||||
Local {
|
Local {
|
||||||
|
@ -217,10 +215,9 @@ mod app {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const WINDOW_LEN: usize = 100;
|
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) {
|
async fn update_pwm(mut cx: update_pwm::Context) {
|
||||||
defmt::info!("Update Task started");
|
defmt::info!("Update Task started");
|
||||||
|
|
||||||
|
@ -278,8 +275,8 @@ mod app {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.shared.current_freq.lock(|current_freq| {
|
cx.shared.device_status.lock(|device_status| {
|
||||||
*current_freq = freq;
|
device_status.measured_frequency = freq;
|
||||||
});
|
});
|
||||||
|
|
||||||
short_avg += freq / WINDOW_LEN as f64;
|
short_avg += freq / WINDOW_LEN as f64;
|
||||||
|
@ -289,8 +286,8 @@ mod app {
|
||||||
}
|
}
|
||||||
|
|
||||||
defmt::info!("short_avg:\t{} MHz", short_avg);
|
defmt::info!("short_avg:\t{} MHz", short_avg);
|
||||||
cx.shared.short_avg.lock(|avg| {
|
cx.shared.device_status.lock(|device_status| {
|
||||||
*avg = short_avg;
|
device_status.average_frequency = short_avg;
|
||||||
});
|
});
|
||||||
|
|
||||||
let diff = (TARGET_FREQ - short_avg) * 1_000_000.0;
|
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 < 0 { 0 } else { cur_pwm };
|
||||||
cur_pwm = if cur_pwm > max_pwm { max_pwm } 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);
|
pwm.set_duty(Channel::C1, cur_pwm as u16);
|
||||||
defmt::info!("pwm:\t{}", cur_pwm);
|
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) {
|
fn usb_tx(cx: usb_tx::Context) {
|
||||||
let mut usb_dev = cx.shared.usb_dev;
|
let mut usb_dev = cx.shared.usb_dev;
|
||||||
let mut serial = cx.shared.serial;
|
let mut serial = cx.shared.serial;
|
||||||
let mut buffer = cx.shared.buffer;
|
let mut buffer = cx.shared.buffer;
|
||||||
let mut current_freq = cx.shared.current_freq;
|
let mut device_status = cx.shared.device_status;
|
||||||
let mut short_avg = cx.shared.short_avg;
|
|
||||||
|
|
||||||
(
|
(&mut usb_dev, &mut serial, &mut buffer, &mut device_status).lock(
|
||||||
&mut usb_dev,
|
|usb_dev, serial, buffer, device_status| {
|
||||||
&mut serial,
|
usb_poll(usb_dev, serial, buffer, device_status);
|
||||||
&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);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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) {
|
fn usb_rx0(cx: usb_rx0::Context) {
|
||||||
let mut usb_dev = cx.shared.usb_dev;
|
let mut usb_dev = cx.shared.usb_dev;
|
||||||
let mut serial = cx.shared.serial;
|
let mut serial = cx.shared.serial;
|
||||||
let mut buffer = cx.shared.buffer;
|
let mut buffer = cx.shared.buffer;
|
||||||
let mut current_freq = cx.shared.current_freq;
|
let mut device_status = cx.shared.device_status;
|
||||||
let mut short_avg = cx.shared.short_avg;
|
|
||||||
|
|
||||||
(
|
(&mut usb_dev, &mut serial, &mut buffer, &mut device_status).lock(
|
||||||
&mut usb_dev,
|
|usb_dev, serial, buffer, device_status| {
|
||||||
&mut serial,
|
usb_poll(usb_dev, serial, buffer, device_status);
|
||||||
&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);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usb_poll<B: usb_device::bus::UsbBus>(
|
fn usb_poll<B: usb_device::bus::UsbBus>(
|
||||||
usb_dev: &mut usb_device::prelude::UsbDevice<'static, B>,
|
usb_dev: &mut usb_device::prelude::UsbDevice<'static, B>,
|
||||||
serial: &mut usbd_serial::SerialPort<'static, B>,
|
serial: &mut usbd_serial::SerialPort<'static, B>,
|
||||||
buffer: &mut Vec<u8, USB_BUFFER_SIZE>,
|
buffer: &mut Vec<u8, USB_BUFFER_SIZE>,
|
||||||
current_freq: &mut f64,
|
device_status: &StatusMessage,
|
||||||
short_avg: &mut f64,
|
|
||||||
) {
|
) {
|
||||||
if !usb_dev.poll(&mut [serial]) {
|
if !usb_dev.poll(&mut [serial]) {
|
||||||
return;
|
return;
|
||||||
|
@ -376,7 +364,7 @@ mod app {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Some(idx) = buffer.iter().position(|&x| x == 0) {
|
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];
|
let mut message = [0u8; 128];
|
||||||
message[0..msg.len()].clone_from_slice(msg);
|
message[0..msg.len()].clone_from_slice(msg);
|
||||||
|
@ -385,19 +373,15 @@ mod app {
|
||||||
match host_msg {
|
match host_msg {
|
||||||
Ok(host_msg) => match host_msg {
|
Ok(host_msg) => match host_msg {
|
||||||
HostMessage::RequestStatus => {
|
HostMessage::RequestStatus => {
|
||||||
let device_msg = DeviceMessage::Status(StatusMessage{
|
let device_msg = DeviceMessage::Status(device_status.clone());
|
||||||
measured_frequency: *current_freq,
|
let bytes =
|
||||||
average_frequency: *short_avg,
|
to_vec_cobs::<DeviceMessage, USB_BUFFER_SIZE>(&device_msg).unwrap();
|
||||||
pwm: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
let bytes = to_vec_cobs::<DeviceMessage, USB_BUFFER_SIZE>(&device_msg).unwrap();
|
|
||||||
serial.write(bytes.as_slice()).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),
|
Err(err) => defmt::error!("Unable to parse host message: {}", err),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -11,6 +11,8 @@ use egui_plot::{Line, Plot, PlotBounds, PlotPoints};
|
||||||
use cheapsdo_protocol::*;
|
use cheapsdo_protocol::*;
|
||||||
use postcard::{from_bytes_cobs, to_stdvec_cobs};
|
use postcard::{from_bytes_cobs, to_stdvec_cobs};
|
||||||
|
|
||||||
|
mod formatters;
|
||||||
|
|
||||||
fn main() -> Result<(), eframe::Error> {
|
fn main() -> Result<(), eframe::Error> {
|
||||||
let options = eframe::NativeOptions {
|
let options = eframe::NativeOptions {
|
||||||
viewport: egui::ViewportBuilder::default(),
|
viewport: egui::ViewportBuilder::default(),
|
||||||
|
@ -27,6 +29,7 @@ struct SharedState {
|
||||||
device_state: StatusMessage,
|
device_state: StatusMessage,
|
||||||
average_points: Vec<[f64; 2]>,
|
average_points: Vec<[f64; 2]>,
|
||||||
measured_points: Vec<[f64; 2]>,
|
measured_points: Vec<[f64; 2]>,
|
||||||
|
pwm_points: Vec<[f64; 2]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SharedState {
|
impl Default for SharedState {
|
||||||
|
@ -35,6 +38,7 @@ impl Default for SharedState {
|
||||||
device_state: StatusMessage::default(),
|
device_state: StatusMessage::default(),
|
||||||
average_points: Vec::<[f64; 2]>::new(),
|
average_points: Vec::<[f64; 2]>::new(),
|
||||||
measured_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();
|
let mut state = self.shared_state.lock().unwrap();
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label(format!(
|
ui.label(
|
||||||
"Measured: {}",
|
egui::RichText::new(format!(
|
||||||
state.device_state.measured_frequency
|
"Measured: {}",
|
||||||
));
|
formatters::frequency(state.device_state.measured_frequency)
|
||||||
ui.label(format!("Average: {}", state.device_state.average_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 average_line = Line::new(PlotPoints::new(state.average_points.clone()));
|
||||||
let measured_line = Line::new(PlotPoints::new(state.measured_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_zoom(false)
|
||||||
.allow_scroll(false)
|
.allow_scroll(false)
|
||||||
.allow_drag(false)
|
.allow_drag(false)
|
||||||
.allow_boxed_zoom(false)
|
.allow_boxed_zoom(false)
|
||||||
.y_axis_width(20)
|
.y_axis_width(12)
|
||||||
.y_axis_formatter(|val, _, _| {
|
.y_axis_formatter(|val, _, _| formatters::frequency(val))
|
||||||
let rest = (val * 1_000_000_000.0) as u64;
|
.label_formatter(|name, value| {
|
||||||
let milli_hz = rest % 1000;
|
format!("{}: {}", name, formatters::frequency(value.y))
|
||||||
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)
|
|
||||||
})
|
})
|
||||||
.show(ui, |plot_ui| {
|
.show(ui, |plot_ui| {
|
||||||
plot_ui.set_auto_bounds([true, true].into());
|
plot_ui.set_auto_bounds([true, true].into());
|
||||||
plot_ui.line(average_line);
|
plot_ui.line(average_line);
|
||||||
//plot_ui.line(measured_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<Mutex<SharedState>>, ctx: egui::Context)
|
||||||
state
|
state
|
||||||
.measured_points
|
.measured_points
|
||||||
.push([x, status_msg.measured_frequency]);
|
.push([x, status_msg.measured_frequency]);
|
||||||
|
state.pwm_points.push([x, status_msg.pwm as f64]);
|
||||||
|
|
||||||
state.device_state = status_msg;
|
state.device_state = status_msg;
|
||||||
ctx.request_repaint()
|
ctx.request_repaint()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
pub enum DeviceMessage {
|
pub enum DeviceMessage {
|
||||||
|
@ -13,14 +13,13 @@ pub enum HostMessage {
|
||||||
SetPLLOutputs,
|
SetPLLOutputs,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||||
pub struct StatusMessage {
|
pub struct StatusMessage {
|
||||||
pub measured_frequency: f64,
|
pub measured_frequency: f64,
|
||||||
pub average_frequency: f64,
|
pub average_frequency: f64,
|
||||||
pub pwm: u16,
|
pub pwm: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Default for StatusMessage {
|
impl Default for StatusMessage {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -29,4 +28,4 @@ impl Default for StatusMessage {
|
||||||
pwm: 0u16,
|
pwm: 0u16,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue