Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow using stdio as a 'Device' #86

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ mod data;
mod gui;
mod io;
mod serial;
mod stdio;
mod toggle;

const APP_INFO: AppInfo = AppInfo {
Expand All @@ -34,12 +35,8 @@ const PREFS_KEY: &str = "config/gui";
const PREFS_KEY_SERIAL: &str = "config/serial_devices";

fn split(payload: &str) -> Vec<f32> {
let mut split_data: Vec<&str> = vec![];
for s in payload.split(':') {
split_data.extend(s.split(','));
}
split_data
.iter()
payload
.split(&[':', ',', '=', ' ', '\t'])
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was just to get the output of ping to look nice in the screenshot. I am happy to revert this if you want

.map(|x| x.trim())
.flat_map(|x| x.parse::<f32>())
.collect()
Expand Down
60 changes: 35 additions & 25 deletions src/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use serialport::{DataBits, FlowControl, Parity, SerialPort, StopBits};

use crate::data::{get_epoch_ms, SerialDirection};
use crate::{print_to_console, Packet, Print, APP_INFO, PREFS_KEY_SERIAL};
use crate::{print_to_console, stdio, Packet, Print, APP_INFO, PREFS_KEY_SERIAL};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SerialDevices {
Expand Down Expand Up @@ -112,32 +112,41 @@ pub fn serial_thread(

let device = get_device(&devices_lock, &device_lock);

let mut port = match serialport::new(&device.name, device.baud_rate)
.timeout(Duration::from_millis(100))
.open()
{
Ok(p) => {
if let Ok(mut connected) = connected_lock.write() {
*connected = true;
}
print_to_console(
&print_lock,
Print::Ok(format!(
"Connected to serial port: {} @ baud = {}",
device.name, device.baud_rate
)),
);
BufReader::new(p)
let mut port = if device.name == "stdio" {
if let Ok(mut connected) = connected_lock.write() {
*connected = true;
}
Err(err) => {
if let Ok(mut write_guard) = device_lock.write() {
write_guard.name.clear();
print_to_console(&print_lock, Print::Ok(format!("Connected to stdio")));

BufReader::new(Box::new(stdio::Stdio) as _)
} else {
match serialport::new(&device.name, device.baud_rate)
.timeout(Duration::from_millis(100))
.open()
{
Ok(p) => {
if let Ok(mut connected) = connected_lock.write() {
*connected = true;
}
print_to_console(
&print_lock,
Print::Ok(format!(
"Connected to serial port: {} @ baud = {}",
device.name, device.baud_rate
)),
);
BufReader::new(p)
}
Err(err) => {
if let Ok(mut write_guard) = device_lock.write() {
write_guard.name.clear();
}
print_to_console(
&print_lock,
Print::Error(format!("Error connecting: {}", err)),
);
continue;
}
print_to_console(
&print_lock,
Print::Error(format!("Error connecting: {}", err)),
);
continue;
}
};

Expand Down Expand Up @@ -176,6 +185,7 @@ fn available_devices() -> Vec<String> {
.unwrap()
.iter()
.map(|p| p.port_name.clone())
.chain(std::iter::once("stdio".into()))
.collect()
}

Expand Down
124 changes: 124 additions & 0 deletions src/stdio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
use std::{io, time};

pub struct Stdio;

impl serialport::SerialPort for Stdio {
Copy link
Author

@usbalbin usbalbin Oct 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A successful SerialPortBuilder::open returns Box<dyn SerialPort> however from what I have seen so far (might have missed something), we only seem to need io::Read and io::Write, if we could get a trait object of that instead of SerialPort for normal serial ports, we would not have to implement SerialPort for Stdio. Not sure if that is doable though...

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

implementing SerialPort for Stdio seems to be a bit hacky indeed. Could we create a new struct called Interface that implements io::Read and io::Write and then two builder functions: from_serial() and from_read() ?
Not sure how to handle the configuration of the serial port then (baud, parity etc)..

fn name(&self) -> Option<String> {
todo!()
}

fn baud_rate(&self) -> serialport::Result<u32> {
todo!()
}

fn data_bits(&self) -> serialport::Result<serialport::DataBits> {
todo!()
}

fn flow_control(&self) -> serialport::Result<serialport::FlowControl> {
todo!()
}

fn parity(&self) -> serialport::Result<serialport::Parity> {
todo!()
}

fn stop_bits(&self) -> serialport::Result<serialport::StopBits> {
todo!()
}

fn timeout(&self) -> time::Duration {
todo!()
}

fn set_baud_rate(&mut self, _baud_rate: u32) -> serialport::Result<()> {
todo!()
}

fn set_data_bits(&mut self, _data_bits: serialport::DataBits) -> serialport::Result<()> {
todo!()
}

fn set_flow_control(
&mut self,
_flow_control: serialport::FlowControl,
) -> serialport::Result<()> {
todo!()
}

fn set_parity(&mut self, _parity: serialport::Parity) -> serialport::Result<()> {
todo!()
}

fn set_stop_bits(&mut self, _stop_bits: serialport::StopBits) -> serialport::Result<()> {
todo!()
}

fn set_timeout(&mut self, _timeout: time::Duration) -> serialport::Result<()> {
todo!()
}

fn write_request_to_send(&mut self, _level: bool) -> serialport::Result<()> {
todo!()
}

fn write_data_terminal_ready(&mut self, _level: bool) -> serialport::Result<()> {
todo!()
}

fn read_clear_to_send(&mut self) -> serialport::Result<bool> {
todo!()
}

fn read_data_set_ready(&mut self) -> serialport::Result<bool> {
todo!()
}

fn read_ring_indicator(&mut self) -> serialport::Result<bool> {
todo!()
}

fn read_carrier_detect(&mut self) -> serialport::Result<bool> {
todo!()
}

fn bytes_to_read(&self) -> serialport::Result<u32> {
todo!()
}

fn bytes_to_write(&self) -> serialport::Result<u32> {
todo!()
}

fn clear(&self, _buffer_to_clear: serialport::ClearBuffer) -> serialport::Result<()> {
todo!()
}

fn try_clone(&self) -> serialport::Result<Box<dyn serialport::SerialPort>> {
todo!()
}

fn set_break(&self) -> serialport::Result<()> {
todo!()
}

fn clear_break(&self) -> serialport::Result<()> {
todo!()
}
}

impl io::Write for Stdio {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
io::stdout().write(buf)
}

fn flush(&mut self) -> io::Result<()> {
io::stdout().flush()
}
}

impl io::Read for Stdio {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
io::stdin().read(buf)
}
}