make fanicer
This commit is contained in:
@@ -6,3 +6,4 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
macroquad = "0.4.13"
|
macroquad = "0.4.13"
|
||||||
serialport = "4.5.1"
|
serialport = "4.5.1"
|
||||||
|
|
||||||
|
|||||||
2
rust-toolchain.toml
Normal file
2
rust-toolchain.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "nightly"
|
||||||
392
src/main.rs
392
src/main.rs
@@ -1,43 +1,61 @@
|
|||||||
|
#![feature(random)]
|
||||||
use core::f32;
|
use core::f32;
|
||||||
use std::time::Duration;
|
use std::{
|
||||||
|
fs::read_dir,
|
||||||
|
path::PathBuf,
|
||||||
|
sync::mpsc::{self, Receiver, Sender},
|
||||||
|
thread::{self, JoinHandle},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
use macroquad::prelude::*;
|
use macroquad::prelude::*;
|
||||||
use serialport::SerialPort;
|
|
||||||
|
|
||||||
const THICKNESS: f32 = 2.0;
|
const THICKNESS: f32 = 2.0;
|
||||||
const TAIL_LEN: usize = 500;
|
const TAIL_LEN: usize = 200;
|
||||||
|
const BAUD_RATE: u32 = 57600;
|
||||||
|
static mut PORT: Option<String> = None;
|
||||||
|
|
||||||
#[derive(Clone,Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
struct Point {
|
struct Point {
|
||||||
x: f32,
|
x: f32,
|
||||||
y: f32,
|
y: f32,
|
||||||
}
|
}
|
||||||
impl Point {
|
impl Point {
|
||||||
fn new(x: f32, y: f32) -> Self {
|
fn new(x: f32, y: f32) -> Self {
|
||||||
Self {x,y}
|
Self { x, y }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DebugWindow {
|
struct DebugWindow<'a> {
|
||||||
text: Vec<String>,
|
text: Vec<String>,
|
||||||
text_margin: f32,
|
text_margin: f32,
|
||||||
|
font: Option<&'a Font>,
|
||||||
}
|
}
|
||||||
impl DebugWindow {
|
impl<'a> DebugWindow<'a> {
|
||||||
fn new() -> Self {
|
fn new(font: Option<&'a Font>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
text: Vec::new(),
|
text: Vec::new(),
|
||||||
text_margin: 20.0,
|
text_margin: 20.0,
|
||||||
|
font,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn add_line(&mut self, line: String) {
|
fn add_line(&mut self, line: String) {
|
||||||
self.text.push(line);
|
self.text.push(line);
|
||||||
}
|
}
|
||||||
|
fn get_params(&self) -> TextParams {
|
||||||
|
let params = TextParams {
|
||||||
|
color: WHITE,
|
||||||
|
font: self.font,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
params
|
||||||
|
}
|
||||||
fn draw(&self) {
|
fn draw(&self) {
|
||||||
let params = TextParams { color: WHITE, ..Default::default()} ;
|
let params = self.get_params();
|
||||||
|
|
||||||
self.text.iter().enumerate().for_each(|(index, text)| {
|
self.text.iter().enumerate().for_each(|(index, text)| {
|
||||||
let x = self.text_margin;
|
let x = self.text_margin;
|
||||||
let y = self.text_margin+20.*(index as f32 + 1.);
|
let y = self.text_margin + 20. * (index as f32 + 1.);
|
||||||
|
|
||||||
// let measurement = measure_text(text, None, params.font_size, params.font_scale);
|
// let measurement = measure_text(text, None, params.font_size, params.font_scale);
|
||||||
// draw_rectangle(x,y,measurement.width,-measurement.height, Color { r: 1., g: 1., b: 1., a: 0.25 });
|
// draw_rectangle(x,y,measurement.width,-measurement.height, Color { r: 1., g: 1., b: 1., a: 0.25 });
|
||||||
@@ -48,12 +66,13 @@ impl DebugWindow {
|
|||||||
|
|
||||||
enum Axis {
|
enum Axis {
|
||||||
One,
|
One,
|
||||||
Two
|
Two,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Graph
|
/// # Graph
|
||||||
/// Holds 1 contiguous line. Can be graphed on 1 or 2 axis.
|
/// Holds 1 contiguous line. Can be graphed on 1 or 2 axis.
|
||||||
struct Graph {
|
struct Graph<'a> {
|
||||||
|
font: Option<&'a Font>,
|
||||||
points: [Point; TAIL_LEN],
|
points: [Point; TAIL_LEN],
|
||||||
head: usize,
|
head: usize,
|
||||||
axises: Axis,
|
axises: Axis,
|
||||||
@@ -66,35 +85,79 @@ struct Graph {
|
|||||||
/// How fast X scrolls when using a since axis tail
|
/// How fast X scrolls when using a since axis tail
|
||||||
px_per_s: f32,
|
px_per_s: f32,
|
||||||
}
|
}
|
||||||
impl Graph {
|
impl<'a> Graph<'a> {
|
||||||
fn new(axises: Axis) -> Self {
|
fn recalculate_origin(&mut self) {
|
||||||
|
let (x_offset, y_offset) = match self.axises {
|
||||||
|
Axis::One => (0., screen_height() / 2.),
|
||||||
|
Axis::Two => (screen_width() / 2., screen_height() / 2.),
|
||||||
|
};
|
||||||
|
self.x_origin = x_offset;
|
||||||
|
self.y_origin = y_offset;
|
||||||
|
}
|
||||||
|
fn new(axises: Axis, font: Option<&'a Font>) -> Self {
|
||||||
let (x_offset, y_offset) = match axises {
|
let (x_offset, y_offset) = match axises {
|
||||||
Axis::One => {
|
Axis::One => (0., screen_height() / 2.),
|
||||||
(0., screen_height()*0.5)
|
Axis::Two => (screen_width() / 2., screen_height() / 2.),
|
||||||
},
|
|
||||||
Axis::Two => {
|
|
||||||
(screen_width()/2.,screen_height()/2.)
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
font,
|
||||||
// start all the dots off screen
|
// start all the dots off screen
|
||||||
points: [Point::new(-1.,-1.); TAIL_LEN],
|
points: [Point::new(-1., -1.); TAIL_LEN],
|
||||||
head: 0,
|
head: 0,
|
||||||
axises,
|
axises,
|
||||||
x_origin: x_offset,
|
x_origin: x_offset,
|
||||||
y_origin: y_offset,
|
y_origin: y_offset,
|
||||||
px_per_s: 750.,
|
px_per_s: 800.,
|
||||||
head_tracker: 0.,
|
head_tracker: 0.,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn draw_time(&self) {
|
||||||
|
let ms_per_px = self.px_per_s / 1000.;
|
||||||
|
// how many ms per segment
|
||||||
|
let segment_len_ms = 100.;
|
||||||
|
let px_offset = ms_per_px * segment_len_ms;
|
||||||
|
let segments = screen_width() / px_offset;
|
||||||
|
|
||||||
|
let mut params = TextParams::default();
|
||||||
|
params.font = self.font;
|
||||||
|
params.font_size = 20;
|
||||||
|
params.color = DARKGRAY;
|
||||||
|
|
||||||
|
let y2 = screen_height();
|
||||||
|
for i in 0..=segments as i32 {
|
||||||
|
let x = i as f32 * px_offset;
|
||||||
|
draw_line(x, 0., x, y2, 2., DARKGRAY);
|
||||||
|
|
||||||
|
draw_text_ex(
|
||||||
|
&format!("{}ms", segment_len_ms * i as f32),
|
||||||
|
x,
|
||||||
|
y2 / 2.,
|
||||||
|
params.clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
fn draw_axises(&self) {
|
fn draw_axises(&self) {
|
||||||
// Horzontal line
|
// Horzontal line
|
||||||
// (0, y_origin) -> (max, y_origin)
|
// (0, y_origin) -> (max, y_origin)
|
||||||
draw_line(0.,self.y_origin,screen_width(),self.y_origin,1.,DARKGRAY);
|
draw_line(
|
||||||
|
0.,
|
||||||
|
self.y_origin,
|
||||||
|
screen_width(),
|
||||||
|
self.y_origin,
|
||||||
|
1.,
|
||||||
|
DARKGRAY,
|
||||||
|
);
|
||||||
// Vertical line
|
// Vertical line
|
||||||
// (x_origin, 0) -> (x_origin, max)
|
// (x_origin, 0) -> (x_origin, max)
|
||||||
draw_line(self.x_origin,0.,self.x_origin,screen_height(),1.,DARKGRAY);
|
draw_line(
|
||||||
|
self.x_origin,
|
||||||
|
0.,
|
||||||
|
self.x_origin,
|
||||||
|
screen_height(),
|
||||||
|
1.,
|
||||||
|
DARKGRAY,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
fn place_next(&mut self, delta_time: f32, x_displacement: f32, y_displacement: f32) {
|
fn place_next(&mut self, delta_time: f32, x_displacement: f32, y_displacement: f32) {
|
||||||
match self.axises {
|
match self.axises {
|
||||||
@@ -105,16 +168,22 @@ impl Graph {
|
|||||||
} else {
|
} else {
|
||||||
self.head_tracker = self.head_tracker + (delta_time * self.px_per_s)
|
self.head_tracker = self.head_tracker + (delta_time * self.px_per_s)
|
||||||
}
|
}
|
||||||
self.push(Point::new(self.head_tracker, self.y_origin-y_displacement));
|
self.push(Point::new(
|
||||||
},
|
self.head_tracker,
|
||||||
|
self.y_origin - y_displacement,
|
||||||
|
));
|
||||||
|
}
|
||||||
Axis::Two => {
|
Axis::Two => {
|
||||||
// both x and y will get displaced
|
// both x and y will get displaced
|
||||||
self.push(Point::new(self.x_origin+x_displacement,self.y_origin-y_displacement))
|
self.push(Point::new(
|
||||||
},
|
self.x_origin + x_displacement,
|
||||||
|
self.y_origin - y_displacement,
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn push(&mut self, dot: Point) {
|
fn push(&mut self, dot: Point) {
|
||||||
if self.head >= self.points.len() -1 {
|
if self.head >= self.points.len() - 1 {
|
||||||
self.head = 0
|
self.head = 0
|
||||||
} else {
|
} else {
|
||||||
self.head += 1
|
self.head += 1
|
||||||
@@ -123,71 +192,143 @@ impl Graph {
|
|||||||
self.points[self.head] = dot;
|
self.points[self.head] = dot;
|
||||||
}
|
}
|
||||||
fn draw(&self) {
|
fn draw(&self) {
|
||||||
self.points.into_iter().enumerate().for_each(|(index, point) |{
|
self.points
|
||||||
// dots fade
|
.into_iter()
|
||||||
let virtual_index = if index > self.head {
|
.enumerate()
|
||||||
index-self.head
|
.for_each(|(index, point)| {
|
||||||
} else {
|
// dots fade
|
||||||
index + (self.points.len() - self.head)
|
let virtual_index = if index > self.head {
|
||||||
};
|
index - self.head
|
||||||
let faded = virtual_index as f32 / self.points.len() as f32;
|
} else {
|
||||||
let faded_inverse = 1. - faded;
|
index + (self.points.len() - self.head)
|
||||||
let color = Color { r: faded_inverse, g: faded, b: 0.2, a: faded+0.1};
|
};
|
||||||
|
let faded = virtual_index as f32 / self.points.len() as f32;
|
||||||
|
let faded_inverse = 1. - faded;
|
||||||
|
let color = Color {
|
||||||
|
r: faded_inverse,
|
||||||
|
g: faded,
|
||||||
|
b: 0.2,
|
||||||
|
a: faded + 0.1,
|
||||||
|
};
|
||||||
|
|
||||||
let prev = self.previous(index);
|
let prev = self.previous(index);
|
||||||
|
|
||||||
if point.x == 0. || point.y == 0. || prev.x == -1. || prev.y == -1. {
|
if point.x == 0. || point.y == 0. || prev.x == -1. || prev.y == -1. {
|
||||||
// Don't have lines that cross the whole screen while using 1D graph
|
// Don't have lines that cross the whole screen while using 1D graph
|
||||||
// draw_circle(point.x, point.y,THICKNESS, color);
|
// draw_circle(point.x, point.y,THICKNESS, color);
|
||||||
} else if self.head == index {
|
} else if self.head == index {
|
||||||
// Draw the head differently
|
// Draw the head differently
|
||||||
draw_circle(point.x, point.y,THICKNESS*2., color);
|
draw_circle(point.x, point.y, THICKNESS * 2., color);
|
||||||
draw_line(point.x, point.y, prev.x, prev.y, THICKNESS, color);
|
draw_line(point.x, point.y, prev.x, prev.y, THICKNESS, color);
|
||||||
} else if prev == self.points[self.head] {
|
} else if prev == self.points[self.head] {
|
||||||
// Prevent the tail from connecting to the head
|
// Prevent the tail from connecting to the head
|
||||||
draw_circle(point.x, point.y,THICKNESS, color);
|
draw_circle(point.x, point.y, THICKNESS, color);
|
||||||
} else {
|
} else {
|
||||||
draw_line(point.x, point.y, prev.x, prev.y, THICKNESS, color);
|
draw_line(point.x, point.y, prev.x, prev.y, THICKNESS, color);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
fn previous(&self, index: usize) -> Point {
|
fn previous(&self, index: usize) -> Point {
|
||||||
let prev = if index > 0 {
|
let prev = if index > 0 {
|
||||||
index -1
|
index - 1
|
||||||
} else {
|
} else {
|
||||||
self.points.len() -1
|
self.points.len() - 1
|
||||||
};
|
};
|
||||||
self.points[prev]
|
self.points[prev]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_font() -> Option<Font> {
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
let fonts_path = "C:\\Windows\\Fonts";
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
let fonts_path = "/usr/share/fonts/";
|
||||||
|
|
||||||
|
if let Ok(dir) = read_dir(fonts_path) {
|
||||||
|
let selection = dir
|
||||||
|
.filter_map(|f| f.ok())
|
||||||
|
.map(|f| (f.file_name(), f.path()))
|
||||||
|
.map(|(a, b)| (a.into_string(), b))
|
||||||
|
.filter(|(a, _)| a.is_ok())
|
||||||
|
.map(|(a, b)| (a.unwrap(), b))
|
||||||
|
// Arial is a good windows default, Adwaita is a good Linux default
|
||||||
|
.filter(|(a, _)| a.contains("Arial") | a.contains("Adwaita"))
|
||||||
|
.map(|(_, b)| b)
|
||||||
|
.collect::<Vec<PathBuf>>();
|
||||||
|
if selection.len() > 0 {
|
||||||
|
if let Ok(dir) = read_dir(&selection[0]) {
|
||||||
|
let ttfs = dir
|
||||||
|
.filter_map(|f| f.ok())
|
||||||
|
.map(|f| (f.file_name(), f.path()))
|
||||||
|
.map(|(a, b)| (a.into_string(), b))
|
||||||
|
.filter(|(a, _)| a.is_ok())
|
||||||
|
.map(|(a, b)| (a.unwrap(), b))
|
||||||
|
.filter(|(a, _)| a.contains("Regular"))
|
||||||
|
.filter(|(a, _)| a.contains("Mono"))
|
||||||
|
.filter(|(a, _)| a.contains("ttf"))
|
||||||
|
.map(|(_, b)| b)
|
||||||
|
.collect::<Vec<PathBuf>>();
|
||||||
|
|
||||||
|
if ttfs.len() > 0 {
|
||||||
|
let selection = ttfs[0].to_str().expect("Bad path");
|
||||||
|
let ttf = load_ttf_font(selection)
|
||||||
|
.await
|
||||||
|
.expect("Cannot load ttf {selection}");
|
||||||
|
println!("Loaded \"{:?}\"", ttfs[0]);
|
||||||
|
return Some(ttf);
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"So sutable fonts found in the sub dir \"{:?}\"",
|
||||||
|
selection[0]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eprintln!("No fonts found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[macroquad::main("Graph")]
|
#[macroquad::main("Graph")]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
let font = get_font().await;
|
||||||
|
|
||||||
// Dot params
|
// Dot params
|
||||||
let mut graph = Graph::new(Axis::One);
|
let mut graph = Graph::new(Axis::One, font.as_ref());
|
||||||
|
|
||||||
// Tooling
|
// Tooling
|
||||||
let mut show_debug = true;
|
let mut show_debug = true;
|
||||||
let mut plot_delta_time = 0.;
|
let mut plot_delta_time = 0.;
|
||||||
|
let mut pause = false;
|
||||||
|
|
||||||
// Serial
|
// Serial
|
||||||
let mut port = get_serial_port();
|
let (rx, _handle) = get_serial_port_or_demo();
|
||||||
let mut serial_buf: Vec<u8> = vec![0; 8];
|
|
||||||
loop {
|
loop {
|
||||||
clear_background(BLACK);
|
clear_background(BLACK);
|
||||||
|
|
||||||
|
graph.recalculate_origin();
|
||||||
graph.draw_axises();
|
graph.draw_axises();
|
||||||
|
graph.draw_time();
|
||||||
|
|
||||||
let frame_delta_time = get_frame_time();
|
let frame_delta_time = get_frame_time();
|
||||||
// keep track of the delta time since last plot
|
// keep track of the delta time since last plot
|
||||||
plot_delta_time += frame_delta_time;
|
plot_delta_time += frame_delta_time;
|
||||||
|
|
||||||
if let Ok(x) = port.read(serial_buf.as_mut_slice()) {
|
if !pause {
|
||||||
let s: String = serial_buf.iter().take(x-1).map(|x| *x as char).collect();
|
match rx.try_recv() {
|
||||||
if let Ok(parse) = s.parse::<f32>() {
|
Ok(x) => {
|
||||||
// Only draw when requied
|
graph.place_next(plot_delta_time, 0., x as f32);
|
||||||
graph.place_next(plot_delta_time, 0., parse);
|
plot_delta_time = 0.;
|
||||||
plot_delta_time = 0.;
|
}
|
||||||
|
Err(x) => match x {
|
||||||
|
mpsc::TryRecvError::Empty => {}
|
||||||
|
mpsc::TryRecvError::Disconnected => {
|
||||||
|
eprintln!("Sender hung-up.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,39 +337,104 @@ async fn main() {
|
|||||||
if is_key_pressed(KeyCode::F3) {
|
if is_key_pressed(KeyCode::F3) {
|
||||||
show_debug = !show_debug;
|
show_debug = !show_debug;
|
||||||
}
|
}
|
||||||
// toggle debug box
|
if is_key_pressed(KeyCode::F1) {
|
||||||
if show_debug {
|
pause = !pause;
|
||||||
// Debug cursor information
|
|
||||||
let (mouse_x, mouse_y) = mouse_position();
|
|
||||||
let size = measure_text(&format!("x{mouse_x}, y{}",-(mouse_y-graph.y_origin)), None, 30,1.);
|
|
||||||
draw_rectangle(mouse_x, mouse_y+(size.offset_y/4.), size.width, -(size.height), WHITE);
|
|
||||||
draw_text(&format!("x{}, y{}", mouse_x+graph.x_origin,-(mouse_y-graph.y_origin)), mouse_x, mouse_y, 30., BLACK);
|
|
||||||
|
|
||||||
// Debug textbox
|
|
||||||
let mut debug = DebugWindow::new();
|
|
||||||
debug.add_line(format!("FPS {:04}, Frametime {:05.2}ms", get_fps(), frame_delta_time * 1000.0));
|
|
||||||
debug.add_line(format!("Tail Length {TAIL_LEN}, px/s {:.2}", graph.px_per_s));
|
|
||||||
debug.add_line(format!("Cursor Pos {:?}", mouse_position()));
|
|
||||||
debug.add_line(format!("Serial Port {}, Baud Rate {}", port.name().unwrap_or("Unknown".to_string()), port.baud_rate().map_or(String::from("N/A"), |f| f.to_string())));
|
|
||||||
debug.draw();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (_, my) = mouse_wheel();
|
||||||
|
graph.px_per_s += 10. * my;
|
||||||
|
|
||||||
|
// toggle debug box
|
||||||
|
if show_debug {
|
||||||
|
let mut debug = DebugWindow::new(font.as_ref());
|
||||||
|
let params = debug.get_params();
|
||||||
|
// Debug cursor information
|
||||||
|
let (mouse_x, mouse_y) = mouse_position();
|
||||||
|
let text = &format!("x{mouse_x}, y{}", -(mouse_y - graph.y_origin));
|
||||||
|
let size = measure_text(text, params.font, params.font_size, params.font_scale);
|
||||||
|
draw_rectangle(
|
||||||
|
mouse_x,
|
||||||
|
mouse_y + (size.offset_y / 4.),
|
||||||
|
size.width,
|
||||||
|
-(size.height),
|
||||||
|
BLUE,
|
||||||
|
);
|
||||||
|
draw_text_ex(text, mouse_x, mouse_y, params);
|
||||||
|
|
||||||
|
// Debug textbox
|
||||||
|
debug.add_line(format!(
|
||||||
|
"FPS {:04}, Frametime {:05.2}ms",
|
||||||
|
get_fps(),
|
||||||
|
frame_delta_time * 1000.0
|
||||||
|
));
|
||||||
|
debug.add_line(format!(
|
||||||
|
"Tail Length {TAIL_LEN}, px/s {:.2}",
|
||||||
|
graph.px_per_s
|
||||||
|
));
|
||||||
|
debug.add_line(format!("Cursor Pos {:?}", mouse_position()));
|
||||||
|
|
||||||
|
if let Some(port_name) = unsafe { PORT.clone() } {
|
||||||
|
debug.add_line(format!("Serial Port {port_name}, Baud Rate {BAUD_RATE}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
debug.draw();
|
||||||
|
}
|
||||||
next_frame().await;
|
next_frame().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_serial_port() -> Box<dyn SerialPort> {
|
type INT = i32;
|
||||||
let port = serialport::available_ports()
|
|
||||||
.expect("No ports found!")
|
fn get_serial_port_or_demo() -> (Receiver<INT>, JoinHandle<()>) {
|
||||||
.iter()
|
let (tx, rx): (Sender<INT>, Receiver<INT>) = mpsc::channel();
|
||||||
.filter(|x| x.port_name.contains("ACM"))
|
|
||||||
.fold(None, |_, x| {
|
let handle = match serialport::available_ports() {
|
||||||
let x = serialport::new(x.port_name.clone(), 57600)
|
Ok(ok) => {
|
||||||
.timeout(Duration::from_millis(10))
|
let x = ok
|
||||||
.open().expect("Failed to open port");
|
.iter()
|
||||||
Some(x)
|
.filter(|x| x.port_name.contains("ACM"))
|
||||||
});
|
.take(1)
|
||||||
let port = port.expect("Failed to find valid serial port");
|
.collect::<Vec<&serialport::SerialPortInfo>>();
|
||||||
port
|
if x.len() > 0 {
|
||||||
|
let port = x[0];
|
||||||
|
unsafe {
|
||||||
|
PORT = Some(port.port_name.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut x = serialport::new(port.port_name.clone(), BAUD_RATE)
|
||||||
|
.timeout(Duration::from_millis(10))
|
||||||
|
.open()
|
||||||
|
.expect("Failed to open port");
|
||||||
|
|
||||||
|
let handle = thread::spawn(move || loop {
|
||||||
|
let mut serial_buf: Vec<u8> = vec![0; 8];
|
||||||
|
if let Ok(x) = x.read(serial_buf.as_mut_slice()) {
|
||||||
|
for i in &serial_buf[..x - 1] {
|
||||||
|
// this data may need to be cleansed
|
||||||
|
let _err = tx.send(i.clone() as INT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
handle
|
||||||
|
} else {
|
||||||
|
dummy_port(tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_err) => dummy_port(tx),
|
||||||
|
};
|
||||||
|
|
||||||
|
(rx, handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dummy_port(tx: Sender<INT>) -> JoinHandle<()> {
|
||||||
|
let handle = thread::spawn(move || loop {
|
||||||
|
let a: u8 = std::random::random(..);
|
||||||
|
// center around y origin
|
||||||
|
let a: INT = a as INT - ((u8::MAX / 2) as INT);
|
||||||
|
|
||||||
|
let _err = tx.send(a);
|
||||||
|
thread::sleep(Duration::from_millis(10))
|
||||||
|
});
|
||||||
|
handle
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user