Added first working UI
This commit is contained in:
parent
7d5eb1887d
commit
c5bec82d59
|
@ -1,7 +1,6 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
#![feature(slice_split_once)]
|
|
||||||
use defmt_rtt as _; // global logger
|
use defmt_rtt as _; // global logger
|
||||||
|
|
||||||
use panic_probe as _;
|
use panic_probe as _;
|
||||||
|
@ -376,7 +375,9 @@ mod app {
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
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];
|
let mut message = [0u8; 128];
|
||||||
message[0..msg.len()].clone_from_slice(msg);
|
message[0..msg.len()].clone_from_slice(msg);
|
||||||
let host_msg = from_bytes_cobs::<HostMessage>(&mut message);
|
let host_msg = from_bytes_cobs::<HostMessage>(&mut message);
|
||||||
|
|
|
@ -8,5 +8,6 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cheapsdo-protocol = { path = "../protocol" }
|
cheapsdo-protocol = { path = "../protocol" }
|
||||||
eframe = "0.24.1"
|
eframe = "0.24.1"
|
||||||
|
egui_plot = "0.24.1"
|
||||||
postcard = {version = "1.0.8", features = ["use-std"]}
|
postcard = {version = "1.0.8", features = ["use-std"]}
|
||||||
serialport = "4.3.0"
|
serialport = "4.3.0"
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![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;
|
||||||
use std::{io::Write, thread};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use std::{io::Write, thread};
|
||||||
|
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
|
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};
|
||||||
|
@ -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 {
|
struct CheapsdoControl {
|
||||||
devicestate: Arc<Mutex<StatusMessage>>,
|
shared_state: Arc<Mutex<SharedState>>,
|
||||||
serial_device: String,
|
serial_device: String,
|
||||||
serial_connected: bool,
|
serial_connected: bool,
|
||||||
}
|
}
|
||||||
|
@ -31,7 +48,7 @@ struct CheapsdoControl {
|
||||||
impl Default for CheapsdoControl {
|
impl Default for CheapsdoControl {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
devicestate: Arc::new(Mutex::new(StatusMessage::default())),
|
shared_state: Arc::new(Mutex::new(SharedState::default())),
|
||||||
serial_device: "".to_owned(),
|
serial_device: "".to_owned(),
|
||||||
serial_connected: false,
|
serial_connected: false,
|
||||||
}
|
}
|
||||||
|
@ -43,8 +60,6 @@ impl eframe::App for CheapsdoControl {
|
||||||
let ports =
|
let ports =
|
||||||
serialport::available_ports().unwrap_or(Vec::<serialport::SerialPortInfo>::new());
|
serialport::available_ports().unwrap_or(Vec::<serialport::SerialPortInfo>::new());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
egui::ComboBox::from_label("Select Serialport")
|
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;
|
self.serial_connected = true;
|
||||||
|
|
||||||
let serial_device = self.serial_device.clone();
|
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 || {
|
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();
|
ui.separator();
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut state = self.devicestate.lock().unwrap();
|
let mut state = self.shared_state.lock().unwrap();
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label(format!("Measured: {}", state.measured_frequency));
|
ui.label(format!(
|
||||||
ui.label(format!("Average: {}", state.average_frequency));
|
"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<SharedState>>, ctx: egui::Context) {
|
||||||
fn poll_device(port: String, state: Arc<Mutex<StatusMessage>>) {
|
|
||||||
let mut port = serialport::new(port, 115_200)
|
let mut port = serialport::new(port, 115_200)
|
||||||
.timeout(Duration::from_millis(10))
|
.timeout(Duration::from_millis(10))
|
||||||
.open().expect("Failed to open port");
|
.open()
|
||||||
|
.expect("Failed to open port");
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let host_msg = HostMessage::RequestStatus;
|
let host_msg = HostMessage::RequestStatus;
|
||||||
|
@ -107,20 +156,25 @@ fn poll_device(port: String, state: Arc<Mutex<StatusMessage>>) {
|
||||||
println!("Data: {:?}", serial_buf);
|
println!("Data: {:?}", serial_buf);
|
||||||
|
|
||||||
let dev_msg = from_bytes_cobs::<DeviceMessage>(&mut serial_buf).unwrap();
|
let dev_msg = from_bytes_cobs::<DeviceMessage>(&mut serial_buf).unwrap();
|
||||||
|
|
||||||
match dev_msg {
|
match dev_msg {
|
||||||
DeviceMessage::Status(status_msg) => {
|
DeviceMessage::Status(status_msg) => {
|
||||||
let mut state = state.lock().unwrap();
|
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(ref e) if e.kind() == io::ErrorKind::TimedOut => (),
|
||||||
Err(e) => eprintln!("{:?}", e),
|
Err(e) => eprintln!("{:?}", e),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
thread::sleep(Duration::from_millis(1000));
|
thread::sleep(Duration::from_millis(1000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,3 +19,14 @@ pub struct StatusMessage {
|
||||||
pub average_frequency: f64,
|
pub average_frequency: f64,
|
||||||
pub pwm: u16,
|
pub pwm: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Default for StatusMessage {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
measured_frequency: 0.0f64,
|
||||||
|
average_frequency: 0.0f64,
|
||||||
|
pwm: 0u16,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue