Added first working UI

This commit is contained in:
Sebastian 2023-12-21 00:26:56 +01:00
parent 7d5eb1887d
commit c5bec82d59
4 changed files with 94 additions and 27 deletions

View File

@ -1,7 +1,6 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
#![feature(slice_split_once)]
use defmt_rtt as _; // global logger
use panic_probe as _;
@ -376,7 +375,9 @@ mod app {
}
loop {
if let Some((msg, rest)) = buffer.split_once(|&x| x == 0) {
if let Some(idx) = buffer.iter().position(|&x| x == 0) {
let (msg, rest) = buffer.split_at(idx+1);
let mut message = [0u8; 128];
message[0..msg.len()].clone_from_slice(msg);
let host_msg = from_bytes_cobs::<HostMessage>(&mut message);

View File

@ -8,5 +8,6 @@ edition = "2021"
[dependencies]
cheapsdo-protocol = { path = "../protocol" }
eframe = "0.24.1"
egui_plot = "0.24.1"
postcard = {version = "1.0.8", features = ["use-std"]}
serialport = "4.3.0"

View File

@ -1,11 +1,12 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
use std::sync::{Arc, Mutex};
use std::io;
use std::{io::Write, thread};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::{io::Write, thread};
use eframe::egui;
use egui_plot::{Line, Plot, PlotBounds, PlotPoints};
use cheapsdo_protocol::*;
use postcard::{from_bytes_cobs, to_stdvec_cobs};
@ -22,8 +23,24 @@ fn main() -> Result<(), eframe::Error> {
)
}
struct SharedState {
device_state: StatusMessage,
average_points: Vec<[f64; 2]>,
measured_points: Vec<[f64; 2]>,
}
impl Default for SharedState {
fn default() -> Self {
Self {
device_state: StatusMessage::default(),
average_points: Vec::<[f64; 2]>::new(),
measured_points: Vec::<[f64; 2]>::new(),
}
}
}
struct CheapsdoControl {
devicestate: Arc<Mutex<StatusMessage>>,
shared_state: Arc<Mutex<SharedState>>,
serial_device: String,
serial_connected: bool,
}
@ -31,7 +48,7 @@ struct CheapsdoControl {
impl Default for CheapsdoControl {
fn default() -> Self {
Self {
devicestate: Arc::new(Mutex::new(StatusMessage::default())),
shared_state: Arc::new(Mutex::new(SharedState::default())),
serial_device: "".to_owned(),
serial_connected: false,
}
@ -43,8 +60,6 @@ impl eframe::App for CheapsdoControl {
let ports =
serialport::available_ports().unwrap_or(Vec::<serialport::SerialPortInfo>::new());
egui::CentralPanel::default().show(ctx, |ui| {
ui.horizontal(|ui| {
egui::ComboBox::from_label("Select Serialport")
@ -59,40 +74,74 @@ impl eframe::App for CheapsdoControl {
}
});
if ui.add_enabled(!self.serial_connected, egui::Button::new("Open")).clicked() {
if ui
.add_enabled(!self.serial_connected, egui::Button::new("Open"))
.clicked()
{
self.serial_connected = true;
let serial_device = self.serial_device.clone();
let devicestate = self.devicestate.clone();
let devicestate = self.shared_state.clone();
let ctx = ctx.clone();
std::thread::spawn(move || {
poll_device(serial_device, devicestate);
poll_device(serial_device, devicestate, ctx);
});
}
if ui.add_enabled(self.serial_connected, egui::Button::new("Close")).clicked() {
}
if ui
.add_enabled(self.serial_connected, egui::Button::new("Close"))
.clicked()
{}
});
ui.separator();
{
let mut state = self.devicestate.lock().unwrap();
let mut state = self.shared_state.lock().unwrap();
ui.horizontal(|ui| {
ui.label(format!("Measured: {}", state.measured_frequency));
ui.label(format!("Average: {}", state.average_frequency));
ui.label(format!(
"Measured: {}",
state.device_state.measured_frequency
));
ui.label(format!("Average: {}", state.device_state.average_frequency));
});
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")
.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)
})
.show(ui, |plot_ui| {
plot_ui.set_auto_bounds([true, true].into());
plot_ui.line(average_line);
//plot_ui.line(measured_line);
})
}
});
}
}
fn poll_device(port: String, state: Arc<Mutex<StatusMessage>>) {
fn poll_device(port: String, state: Arc<Mutex<SharedState>>, ctx: egui::Context) {
let mut port = serialport::new(port, 115_200)
.timeout(Duration::from_millis(10))
.open().expect("Failed to open port");
.timeout(Duration::from_millis(10))
.open()
.expect("Failed to open port");
loop {
let host_msg = HostMessage::RequestStatus;
@ -107,20 +156,25 @@ fn poll_device(port: String, state: Arc<Mutex<StatusMessage>>) {
println!("Data: {:?}", serial_buf);
let dev_msg = from_bytes_cobs::<DeviceMessage>(&mut serial_buf).unwrap();
match dev_msg {
DeviceMessage::Status(status_msg) => {
let mut state = state.lock().unwrap();
*state = status_msg;
},
}
let x = state.average_points.len() as f64;
state.average_points.push([x, status_msg.average_frequency]);
state
.measured_points
.push([x, status_msg.measured_frequency]);
state.device_state = status_msg;
ctx.request_repaint()
}
}
}
Err(ref e) if e.kind() == io::ErrorKind::TimedOut => (),
Err(e) => eprintln!("{:?}", e),
}
thread::sleep(Duration::from_millis(1000));
}
}
}

View File

@ -19,3 +19,14 @@ pub struct StatusMessage {
pub average_frequency: f64,
pub pwm: u16,
}
impl Default for StatusMessage {
fn default() -> Self {
Self {
measured_frequency: 0.0f64,
average_frequency: 0.0f64,
pwm: 0u16,
}
}
}