Compare commits
9 Commits
forgejo-ac
...
main
Author | SHA1 | Date |
---|---|---|
Sebastian | be45b12b5a | |
Sebastian | d90ac1ec00 | |
Sebastian | 565d17b383 | |
Sebastian | 6dd49234df | |
Sebastian | c2b7bf9e1e | |
Sebastian | e6c6e1696a | |
Sebastian | 6048d4826c | |
Sebastian | ae54fdfee9 | |
Sebastian | 08f9ae557d |
|
@ -14,7 +14,7 @@ jobs:
|
|||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: build-cheapsdo
|
||||
key: build-cheapsdo-firmware
|
||||
restore-keys: audit-cheapsdo
|
||||
- run: cd firmware && CARGO_HOME=~/.cargo cargo build --target thumbv7m-none-eabi --release
|
||||
|
||||
|
@ -32,7 +32,8 @@ jobs:
|
|||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: build-cheapsdo
|
||||
key: build-cheapsdo-linux
|
||||
restore-keys: build-cheapsdo-firmware
|
||||
- run: cd hostsoftware && CARGO_HOME=~/.cargo cargo build --release
|
||||
|
||||
build-windows:
|
||||
|
@ -50,7 +51,8 @@ jobs:
|
|||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: build-cheapsdo
|
||||
key: build-cheapsdo-windows
|
||||
restore-keys: build-cheapsdo-linux
|
||||
- run: cd hostsoftware && CARGO_HOME=~/.cargo cargo build --target x86_64-pc-windows-gnu --release
|
||||
|
||||
build-appimage:
|
||||
|
@ -68,5 +70,6 @@ jobs:
|
|||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: build-cheapsdo
|
||||
key: build-cheapsdo-appimage
|
||||
restore-keys: build-cheapsdo-linux
|
||||
- run: cd hostsoftware && CARGO_HOME=~/.cargo PATH=$PATH:$CARGO_HOME/bin x build -r --format appimage
|
|
@ -26,3 +26,4 @@ cheapsdo-protocol = { path = "../protocol" }
|
|||
postcard = {version = "1.0.8", features = ["use-defmt"]}
|
||||
heapless = {version = "0.8.0", features = ["defmt-03"]}
|
||||
num = {version = "0.4.1", default-features = false, features = ["libm"]}
|
||||
serde = { version = "1.0.195", default-features = false }
|
||||
|
|
|
@ -6,6 +6,7 @@ use defmt_rtt as _; // global logger
|
|||
use panic_probe as _;
|
||||
use stm32f1xx_hal as _;
|
||||
|
||||
mod nvstate;
|
||||
mod si5153;
|
||||
|
||||
// same panicking *behavior* as `panic-probe` but doesn't print a panic message
|
||||
|
@ -24,6 +25,7 @@ mod app {
|
|||
use rtic_monotonics::systick::*;
|
||||
|
||||
use stm32f1xx_hal::{
|
||||
flash::{self, FlashWriter},
|
||||
gpio::{self, gpioa, gpioc, Alternate, Output, PushPull},
|
||||
i2c, pac,
|
||||
pac::{RCC, TIM2, TIM3, TIM4},
|
||||
|
@ -41,6 +43,7 @@ mod app {
|
|||
|
||||
use cheapsdo_protocol::{DeviceMessage, HostMessage, StatusMessage};
|
||||
|
||||
use crate::nvstate::{self, NVState};
|
||||
use crate::si5153;
|
||||
|
||||
const USB_BUFFER_SIZE: usize = 64;
|
||||
|
@ -51,6 +54,8 @@ mod app {
|
|||
tim2: TIM2,
|
||||
tim3: TIM3,
|
||||
pwm: PwmHz<TIM4, Tim4NoRemap, timer::Ch<0>, gpio::Pin<'B', 6, Alternate>>,
|
||||
nvstate: NVState,
|
||||
flash: flash::Parts,
|
||||
}
|
||||
|
||||
#[shared]
|
||||
|
@ -61,7 +66,7 @@ mod app {
|
|||
buffer: Vec<u8, USB_BUFFER_SIZE>,
|
||||
}
|
||||
|
||||
const TARGET_FREQ: f64 = 10.0f64;
|
||||
const TARGET_FREQ: u64 = 10_000_000_000; // in millihertz
|
||||
|
||||
#[init]
|
||||
fn init(cx: init::Context) -> (Shared, Local) {
|
||||
|
@ -229,6 +234,10 @@ mod app {
|
|||
si_pll.set_ms_freq(&mut i2c1, si5153::Multisynth::MS0, 100_000_000);
|
||||
si_pll.enable_ms_output(&mut i2c1, si5153::Multisynth::MS0);
|
||||
|
||||
let nvstate = nvstate::load(&mut flash);
|
||||
|
||||
defmt::info!("read nvstate from flash");
|
||||
|
||||
update_pwm::spawn().unwrap();
|
||||
|
||||
(
|
||||
|
@ -243,13 +252,15 @@ mod app {
|
|||
tim2,
|
||||
tim3,
|
||||
pwm,
|
||||
nvstate,
|
||||
flash,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
const WINDOW_LEN: usize = 100;
|
||||
|
||||
#[task(local=[tim2, tim3, pwm, board_led], shared=[device_status])]
|
||||
#[task(local=[tim2, tim3, pwm, board_led, nvstate, flash], shared=[device_status])]
|
||||
async fn update_pwm(mut cx: update_pwm::Context) {
|
||||
defmt::info!("Update Task started");
|
||||
|
||||
|
@ -257,9 +268,16 @@ mod app {
|
|||
let tim3 = cx.local.tim3;
|
||||
let pwm = cx.local.pwm;
|
||||
let board_led = cx.local.board_led;
|
||||
let mut nvstate = cx.local.nvstate;
|
||||
let mut flash = cx.local.flash;
|
||||
|
||||
let max_pwm = pwm.get_max_duty() as i32;
|
||||
let mut cur_pwm = max_pwm / 2;
|
||||
let mut cur_pwm = nvstate.pwm as i32;
|
||||
cur_pwm = if cur_pwm < 0 { 0 } else { cur_pwm };
|
||||
cur_pwm = if cur_pwm > max_pwm { max_pwm } else { cur_pwm };
|
||||
|
||||
pwm.set_duty(Channel::C1, cur_pwm as u16);
|
||||
defmt::info!("pwm:\t{}", cur_pwm);
|
||||
|
||||
// Inialize last_ic
|
||||
while !tim2.sr.read().cc1if().bit_is_set() || !tim3.sr.read().cc1if().bit_is_set() {
|
||||
|
@ -270,11 +288,11 @@ mod app {
|
|||
|
||||
let mut last_ic = ic2 << 16 | ic1;
|
||||
|
||||
let mut samples: [f64; WINDOW_LEN] = [10.0; WINDOW_LEN];
|
||||
let mut short_avg: f64 = 10.0;
|
||||
let mut samples: [u64; WINDOW_LEN] = [10_000_000_000; WINDOW_LEN];
|
||||
let mut short_avg: u64 = 10_000_000_000;
|
||||
|
||||
loop {
|
||||
let mut last_freq = 10.0f64;
|
||||
let mut last_freq: u64 = 10_000_000_000;
|
||||
|
||||
let mut count = 0;
|
||||
while count < WINDOW_LEN {
|
||||
|
@ -299,22 +317,24 @@ mod app {
|
|||
|
||||
last_ic = sum_ic;
|
||||
|
||||
let freq = (diff_ic as f64) / 1_000_000f64;
|
||||
defmt::info!("freq:\t{} MHz", freq);
|
||||
let freq = (diff_ic as u64) * 1000;
|
||||
defmt::info!("freq:\t{} mHz", freq as i64);
|
||||
defmt::info!("last_freq:\t{} mHz", last_freq as i64);
|
||||
|
||||
let diff = freq - last_freq;
|
||||
let diff = freq as i64 - last_freq as i64;
|
||||
last_freq = freq;
|
||||
if diff > 0.000_100 || diff < -0.000_100 {
|
||||
if diff.abs() > 50_000 {
|
||||
defmt::info!("Out of range, dropping sample.");
|
||||
continue;
|
||||
}
|
||||
|
||||
samples[count] = freq;
|
||||
short_avg = 0.0;
|
||||
short_avg = 0;
|
||||
for i in 0..WINDOW_LEN {
|
||||
short_avg += samples[i] / WINDOW_LEN as f64;
|
||||
short_avg += samples[i];
|
||||
}
|
||||
defmt::info!("short_avg:\t{} MHz", short_avg);
|
||||
short_avg = short_avg / WINDOW_LEN as u64;
|
||||
defmt::info!("short_avg:\t{} mHz", short_avg);
|
||||
|
||||
cx.shared.device_status.lock(|device_status| {
|
||||
device_status.measured_frequency = freq;
|
||||
|
@ -326,14 +346,12 @@ mod app {
|
|||
board_led.toggle();
|
||||
}
|
||||
|
||||
defmt::info!("short_avg:\t{} MHz", short_avg);
|
||||
|
||||
let diff = (TARGET_FREQ - short_avg) * 1_000_000.0;
|
||||
if diff > 0.1 || diff < -0.1 {
|
||||
cur_pwm += (diff * 30.0) as i32;
|
||||
} else if diff < -0.01 {
|
||||
let diff = TARGET_FREQ as i64 - short_avg as i64;
|
||||
if diff.abs() > 100 {
|
||||
cur_pwm += (diff * 30 / 1000) as i32;
|
||||
} else if diff < -10 {
|
||||
cur_pwm -= 1;
|
||||
} else if diff > 0.01 {
|
||||
} else if diff > 10 {
|
||||
cur_pwm += 1;
|
||||
}
|
||||
|
||||
|
@ -343,6 +361,9 @@ mod app {
|
|||
pwm.set_duty(Channel::C1, cur_pwm as u16);
|
||||
defmt::info!("pwm:\t{}", cur_pwm);
|
||||
|
||||
nvstate.pwm = cur_pwm as u16;
|
||||
nvstate.save(&mut flash);
|
||||
|
||||
Systick::delay(500.millis()).await;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
use postcard::{from_bytes_cobs, to_slice_cobs};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stm32f1xx_hal::flash::{self, FlashSize, FlashWriter, SectorSize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct NVState {
|
||||
pub pwm: u16,
|
||||
}
|
||||
|
||||
impl Default for NVState {
|
||||
fn default() -> Self {
|
||||
Self { pwm: 1500u16 }
|
||||
}
|
||||
}
|
||||
|
||||
const PAGE_SIZE: usize = 1024;
|
||||
const NVSTATE_OFFSET: u32 = 63 * PAGE_SIZE as u32;
|
||||
|
||||
const FLASH_SIZE: FlashSize = FlashSize::Sz64K;
|
||||
const SECTOR_SIZE: SectorSize = SectorSize::Sz1K;
|
||||
|
||||
pub fn load(flash: &mut flash::Parts) -> NVState {
|
||||
let mut flash_writer = flash.writer(SECTOR_SIZE, FLASH_SIZE);
|
||||
|
||||
let tmp = flash_writer.read(NVSTATE_OFFSET, PAGE_SIZE).unwrap();
|
||||
let mut nvstate_page = [0u8; PAGE_SIZE];
|
||||
nvstate_page.copy_from_slice(tmp);
|
||||
|
||||
match from_bytes_cobs::<NVState>(&mut nvstate_page) {
|
||||
Ok(nvstate) => nvstate,
|
||||
Err(_) => NVState::default(),
|
||||
}
|
||||
}
|
||||
|
||||
impl NVState {
|
||||
pub fn save(&self, flash: &mut flash::Parts) {
|
||||
let mut flash_writer = flash.writer(SECTOR_SIZE, FLASH_SIZE);
|
||||
|
||||
let mut page = [0u8; PAGE_SIZE];
|
||||
let used = to_slice_cobs(self, &mut page).unwrap();
|
||||
|
||||
flash_writer.page_erase(NVSTATE_OFFSET).unwrap();
|
||||
flash_writer.write(NVSTATE_OFFSET, &used).unwrap();
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
cheapsdo-protocol = { path = "../protocol" }
|
||||
crossbeam-channel = "0.5.11"
|
||||
eframe = "0.24.1"
|
||||
egui_plot = "0.24.1"
|
||||
postcard = {version = "1.0.8", features = ["use-std"]}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
use std::io;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use std::io::Write;
|
||||
use std::time::Duration;
|
||||
use std::{io::Write, thread};
|
||||
|
||||
use crossbeam_channel::{select, unbounded, Receiver, Sender};
|
||||
|
||||
use eframe::egui;
|
||||
use egui_plot::{Line, Plot, PlotBounds, PlotPoints};
|
||||
use egui_plot::{Line, Plot, PlotPoints};
|
||||
|
||||
use cheapsdo_protocol::*;
|
||||
use postcard::{from_bytes_cobs, to_stdvec_cobs};
|
||||
|
@ -21,40 +23,43 @@ fn main() -> Result<(), eframe::Error> {
|
|||
eframe::run_native(
|
||||
"Cheapsdo Control",
|
||||
options,
|
||||
Box::new(|cc| Box::<CheapsdoControl>::default()),
|
||||
Box::new(|_cc| Box::<CheapsdoControl>::default()),
|
||||
)
|
||||
}
|
||||
|
||||
struct SharedState {
|
||||
device_state: StatusMessage,
|
||||
average_points: Vec<[f64; 2]>,
|
||||
measured_points: Vec<[f64; 2]>,
|
||||
pwm_points: Vec<[f64; 2]>,
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum SerialPortCmd {
|
||||
Disconnect,
|
||||
}
|
||||
|
||||
impl Default for SharedState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
device_state: StatusMessage::default(),
|
||||
average_points: Vec::<[f64; 2]>::new(),
|
||||
measured_points: Vec::<[f64; 2]>::new(),
|
||||
pwm_points: Vec::<[f64; 2]>::new(),
|
||||
}
|
||||
}
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum SerialPortData {
|
||||
DeviceState(StatusMessage),
|
||||
}
|
||||
|
||||
struct CheapsdoControl {
|
||||
shared_state: Arc<Mutex<SharedState>>,
|
||||
serial_device: String,
|
||||
serial_connected: bool,
|
||||
|
||||
data_rx: Option<Receiver<SerialPortData>>,
|
||||
cmd_tx: Option<Sender<SerialPortCmd>>,
|
||||
|
||||
device_state: StatusMessage,
|
||||
average_points: Vec<[f64; 2]>,
|
||||
pwm_points: Vec<[f64; 2]>,
|
||||
}
|
||||
|
||||
impl Default for CheapsdoControl {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
shared_state: Arc::new(Mutex::new(SharedState::default())),
|
||||
serial_device: "".to_owned(),
|
||||
serial_connected: false,
|
||||
data_rx: None,
|
||||
cmd_tx: None,
|
||||
|
||||
device_state: StatusMessage::default(),
|
||||
average_points: Vec::new(),
|
||||
pwm_points: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +69,30 @@ impl eframe::App for CheapsdoControl {
|
|||
let ports =
|
||||
serialport::available_ports().unwrap_or(Vec::<serialport::SerialPortInfo>::new());
|
||||
|
||||
if let Some(data_rx) = &self.data_rx {
|
||||
loop {
|
||||
select! {
|
||||
recv(data_rx) -> data => {
|
||||
match data {
|
||||
Ok(SerialPortData::DeviceState(status_msg)) => {
|
||||
self.device_state = status_msg.clone();
|
||||
self.average_points.push([
|
||||
self.average_points.len() as f64,
|
||||
status_msg.average_frequency as f64 / 1_000_000_000.0
|
||||
]);
|
||||
self.pwm_points.push([
|
||||
self.pwm_points.len() as f64,
|
||||
status_msg.pwm as f64
|
||||
]);
|
||||
},
|
||||
Err(_) => break,
|
||||
};
|
||||
},
|
||||
default => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
egui::ComboBox::from_label("Select Serialport")
|
||||
|
@ -79,104 +108,124 @@ impl eframe::App for CheapsdoControl {
|
|||
});
|
||||
|
||||
if ui
|
||||
.add_enabled(!self.serial_connected, egui::Button::new("Open"))
|
||||
.add_enabled(
|
||||
!self.serial_connected && !self.serial_device.is_empty(),
|
||||
egui::Button::new("Open"),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
self.serial_connected = true;
|
||||
|
||||
let serial_device = self.serial_device.clone();
|
||||
let devicestate = self.shared_state.clone();
|
||||
let ctx = ctx.clone();
|
||||
|
||||
self.serial_connected = true;
|
||||
self.average_points.clear();
|
||||
self.pwm_points.clear();
|
||||
|
||||
let (cmd_tx, cmd_rx) = unbounded();
|
||||
let (data_tx, data_rx) = unbounded();
|
||||
|
||||
self.cmd_tx = Some(cmd_tx);
|
||||
self.data_rx = Some(data_rx);
|
||||
|
||||
std::thread::spawn(move || {
|
||||
poll_device(serial_device, devicestate, ctx);
|
||||
poll_device(serial_device, cmd_rx, data_tx, ctx);
|
||||
});
|
||||
}
|
||||
|
||||
if ui
|
||||
.add_enabled(self.serial_connected, egui::Button::new("Close"))
|
||||
.clicked()
|
||||
{}
|
||||
{
|
||||
if let Some(cmd_tx) = &self.cmd_tx {
|
||||
cmd_tx.send(SerialPortCmd::Disconnect).unwrap();
|
||||
}
|
||||
self.serial_connected = false;
|
||||
}
|
||||
});
|
||||
|
||||
ui.separator();
|
||||
|
||||
{
|
||||
let mut state = self.shared_state.lock().unwrap();
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(
|
||||
egui::RichText::new(format!(
|
||||
"Measured: {}",
|
||||
formatters::frequency(state.device_state.measured_frequency)
|
||||
))
|
||||
.family(egui::FontFamily::Monospace)
|
||||
.size(20.0),
|
||||
);
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(
|
||||
egui::RichText::new(format!(
|
||||
"Measured: {}",
|
||||
formatters::frequency(
|
||||
self.device_state.measured_frequency as f64 / 1_000_000_000.0
|
||||
)
|
||||
))
|
||||
.family(egui::FontFamily::Monospace)
|
||||
.size(20.0),
|
||||
);
|
||||
|
||||
ui.add_space(100.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.label(
|
||||
egui::RichText::new(format!(
|
||||
"Average: {}",
|
||||
formatters::frequency(
|
||||
self.device_state.average_frequency as f64 / 1_000_000_000.0
|
||||
)
|
||||
))
|
||||
.family(egui::FontFamily::Monospace)
|
||||
.size(20.0),
|
||||
);
|
||||
});
|
||||
|
||||
ui.add_space(20.0);
|
||||
|
||||
let average_line = Line::new(PlotPoints::new(self.average_points.clone()));
|
||||
//let measured_line = Line::new(PlotPoints::new(self.measured_points.clone()));
|
||||
Plot::new("frequency_plot")
|
||||
.view_aspect(4.0)
|
||||
.allow_zoom(false)
|
||||
.allow_scroll(false)
|
||||
.allow_drag(false)
|
||||
.allow_boxed_zoom(false)
|
||||
.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);
|
||||
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("frequency_plot")
|
||||
.view_aspect(4.0)
|
||||
.allow_zoom(false)
|
||||
.allow_scroll(false)
|
||||
.allow_drag(false)
|
||||
.allow_boxed_zoom(false)
|
||||
.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);
|
||||
});
|
||||
}
|
||||
let pwm_line = Line::new(PlotPoints::new(self.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);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_device(port: String, state: Arc<Mutex<SharedState>>, ctx: egui::Context) {
|
||||
fn poll_device(
|
||||
port: String,
|
||||
cmd_rx: Receiver<SerialPortCmd>,
|
||||
data_tx: Sender<SerialPortData>,
|
||||
ctx: egui::Context,
|
||||
) {
|
||||
let mut port = serialport::new(port, 115_200)
|
||||
.timeout(Duration::from_millis(10))
|
||||
.open()
|
||||
.expect("Failed to open port");
|
||||
|
||||
let host_msg = HostMessage::RequestStatus;
|
||||
let msg_bytes = to_stdvec_cobs(&host_msg).unwrap();
|
||||
port.write_all(&msg_bytes).unwrap();
|
||||
|
||||
loop {
|
||||
let host_msg = HostMessage::RequestStatus;
|
||||
let msg_bytes = to_stdvec_cobs(&host_msg).unwrap();
|
||||
|
||||
port.write_all(&msg_bytes).unwrap();
|
||||
|
||||
let mut serial_buf: Vec<u8> = vec![0; 128];
|
||||
match port.read(serial_buf.as_mut_slice()) {
|
||||
Ok(t) => {
|
||||
|
@ -187,16 +236,10 @@ fn poll_device(port: String, state: Arc<Mutex<SharedState>>, ctx: egui::Context)
|
|||
|
||||
match dev_msg {
|
||||
DeviceMessage::Status(status_msg) => {
|
||||
let mut state = state.lock().unwrap();
|
||||
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.pwm_points.push([x, status_msg.pwm as f64]);
|
||||
|
||||
state.device_state = status_msg;
|
||||
ctx.request_repaint()
|
||||
data_tx
|
||||
.send(SerialPortData::DeviceState(status_msg))
|
||||
.unwrap();
|
||||
ctx.request_repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -204,6 +247,16 @@ fn poll_device(port: String, state: Arc<Mutex<SharedState>>, ctx: egui::Context)
|
|||
Err(e) => eprintln!("{:?}", e),
|
||||
}
|
||||
|
||||
thread::sleep(Duration::from_millis(1000));
|
||||
select! {
|
||||
recv(cmd_rx) -> cmd => match cmd {
|
||||
Ok(SerialPortCmd::Disconnect) => return,
|
||||
Err(_) => {},
|
||||
},
|
||||
default(Duration::from_secs(1)) => {
|
||||
let host_msg = HostMessage::RequestStatus;
|
||||
let msg_bytes = to_stdvec_cobs(&host_msg).unwrap();
|
||||
port.write_all(&msg_bytes).unwrap();
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
3
memory.x
3
memory.x
|
@ -1,6 +1,7 @@
|
|||
/* Linker script for the STM32F103C8T6 */
|
||||
MEMORY
|
||||
{
|
||||
FLASH : ORIGIN = 0x08000000, LENGTH = 64K
|
||||
FLASH : ORIGIN = 0x08000000, LENGTH = 63K
|
||||
NVSTATE : ORIGIN = FLASH + 63K, LENGTH = 1K
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 20K
|
||||
}
|
||||
|
|
|
@ -15,16 +15,16 @@ pub enum HostMessage {
|
|||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
pub struct StatusMessage {
|
||||
pub measured_frequency: f64,
|
||||
pub average_frequency: f64,
|
||||
pub measured_frequency: u64,
|
||||
pub average_frequency: u64,
|
||||
pub pwm: u16,
|
||||
}
|
||||
|
||||
impl Default for StatusMessage {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
measured_frequency: 0.0f64,
|
||||
average_frequency: 0.0f64,
|
||||
measured_frequency: 0u64,
|
||||
average_frequency: 0u64,
|
||||
pwm: 0u16,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue