Buildable again

This commit is contained in:
hodasemi 2022-07-15 19:08:22 +02:00
parent efbad0d676
commit 5b8ffc8dd9
7 changed files with 73 additions and 93 deletions

7
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,7 @@
{
"workbench.colorCustomizations": {
"activityBar.background": "#0E3502",
"titleBar.activeBackground": "#144B03",
"titleBar.activeForeground": "#F1FEED"
}
}

View file

@ -17,4 +17,6 @@ path = "src/gui.rs"
[dependencies] [dependencies]
serialport = "*" serialport = "*"
gtk = { version = "*", features = ["v3_24"] } gtk = { version = "*", features = ["v3_24"] }
utilities = { git = "http://dimov.cloud:80/hodasemi/Context.git" } anyhow = "1.0"
serde = { version = "*", features = ["derive"] }
serde_json = "*"

View file

@ -2,7 +2,7 @@ use gtk;
use gtk::prelude::*; use gtk::prelude::*;
use gtk::{Builder, Window}; use gtk::{Builder, Window};
use utilities::prelude::*; use anyhow::{anyhow, Result};
use std::fs; use std::fs;
use std::path::Path; use std::path::Path;
@ -11,10 +11,10 @@ mod shared;
use shared::config::{Config, COMMAND_COUNT}; use shared::config::{Config, COMMAND_COUNT};
fn main() -> VerboseResult<()> { fn main() -> Result<()> {
gtk::init().map_err(|_| "failed to initialize GTK")?; gtk::init()?;
let builder = Builder::new_from_string(include_str!("../macro_ui.glade")); let builder = Builder::from_string(include_str!("../macro_ui.glade"));
setup_gui(builder)?; setup_gui(builder)?;
@ -23,15 +23,15 @@ fn main() -> VerboseResult<()> {
Ok(()) Ok(())
} }
fn setup_gui(builder: Builder) -> VerboseResult<()> { fn setup_gui(builder: Builder) -> Result<()> {
let config = load_config()?; let config = load_config()?;
apply_config(&builder, &config)?; apply_config(&builder, &config)?;
setup_save(&builder)?; setup_save(&builder)?;
let window: Window = builder let window: Window = builder
.get_object("MainWindow") .object("MainWindow")
.ok_or("failed getting main window")?; .ok_or(anyhow!("failed getting main window"))?;
window.show_all(); window.show_all();
@ -44,8 +44,8 @@ fn setup_gui(builder: Builder) -> VerboseResult<()> {
Ok(()) Ok(())
} }
fn load_config() -> VerboseResult<Config> { fn load_config() -> Result<Config> {
let home_dir = std::env::var("HOME").map_err(|_| "failed getting home directory")?; let home_dir = std::env::var("HOME")?;
if !Path::new(&format!("{}/.config", home_dir)).exists() { if !Path::new(&format!("{}/.config", home_dir)).exists() {
fs::create_dir(format!("{}/.config", home_dir))?; fs::create_dir(format!("{}/.config", home_dir))?;
@ -58,26 +58,26 @@ fn load_config() -> VerboseResult<Config> {
Config::open(&format!("{}/.config/MacroBoard/commands.cfg", home_dir)) Config::open(&format!("{}/.config/MacroBoard/commands.cfg", home_dir))
} }
fn setup_save(builder: &Builder) -> VerboseResult<()> { fn setup_save(builder: &Builder) -> Result<()> {
let mut text_fields = Vec::with_capacity(COMMAND_COUNT); let mut text_fields = Vec::with_capacity(COMMAND_COUNT);
for i in 0..COMMAND_COUNT { for i in 0..COMMAND_COUNT {
let command_text_field: gtk::Entry = builder let command_text_field: gtk::Entry = builder
.get_object(&format!("ButtonCommand{}", i + 1)) .object(&format!("ButtonCommand{}", i + 1))
.ok_or(format!("Failed getting Entry for command {}", i + 1))?; .ok_or(anyhow!("Failed getting Entry for command {}", i + 1))?;
text_fields.push(command_text_field); text_fields.push(command_text_field);
} }
let save_button: gtk::Button = builder let save_button: gtk::Button = builder
.get_object("SaveButton") .object("SaveButton")
.ok_or("Failed getting save button")?; .ok_or(anyhow!("Failed getting save button"))?;
save_button.connect_clicked(move |_| { save_button.connect_clicked(move |_| {
let mut config = Config::default(); let mut config = Config::default();
for i in 0..COMMAND_COUNT { for i in 0..COMMAND_COUNT {
let command = text_fields[i].get_buffer().get_text(); let command = text_fields[i].buffer().text();
config.commands[i] = Some(command); config.commands[i] = Some(command);
} }
@ -98,14 +98,14 @@ fn setup_save(builder: &Builder) -> VerboseResult<()> {
Ok(()) Ok(())
} }
fn apply_config(builder: &Builder, config: &Config) -> VerboseResult<()> { fn apply_config(builder: &Builder, config: &Config) -> Result<()> {
for i in 0..COMMAND_COUNT { for i in 0..COMMAND_COUNT {
if let Some(command) = &config.commands[i] { if let Some(command) = &config.commands[i] {
let command_text_field: gtk::Entry = builder let command_text_field: gtk::Entry = builder
.get_object(&format!("ButtonCommand{}", i + 1)) .object(&format!("ButtonCommand{}", i + 1))
.ok_or(format!("Failed getting Entry for command {}", i + 1))?; .ok_or(anyhow!("Failed getting Entry for command {}", i + 1))?;
command_text_field.get_buffer().set_text(command); command_text_field.buffer().set_text(command);
} }
} }

View file

@ -1,9 +1,9 @@
mod service_specific; mod service_specific;
use anyhow::Result;
use service_specific::*; use service_specific::*;
use utilities::prelude::*;
fn main() -> VerboseResult<()> { fn main() -> Result<()> {
let mut port = Port::open(SerialPortSettings { let mut port = Port::open(SerialPortSettings {
baud_rate: 9600, baud_rate: 9600,
data_bits: DataBits::Eight, data_bits: DataBits::Eight,

View file

@ -24,7 +24,7 @@ impl MessageBuilder {
if !self.complete { if !self.complete {
match msg.chars().position(|c| c == MESSAGE_END) { match msg.chars().position(|c| c == MESSAGE_END) {
Some(position) => { Some(position) => {
let mut remaining_msg = msg.split_off(position); let remaining_msg = msg.split_off(position);
self.message.push_str(&msg); self.message.push_str(&msg);
self.complete = true; self.complete = true;

View file

@ -1,11 +1,8 @@
use serialport; use anyhow::{anyhow, Result};
use serialport::prelude::*;
use utilities::prelude::*;
use std::io; use std::io;
pub use serialport::{DataBits, FlowControl, Parity, SerialPortSettings, StopBits}; pub use serialport::{DataBits, FlowControl, Parity, SerialPort, StopBits};
pub use std::time::Duration; pub use std::time::Duration;
pub enum SerialReadResult { pub enum SerialReadResult {
@ -13,60 +10,68 @@ pub enum SerialReadResult {
Timeout, Timeout,
} }
pub struct SerialPortSettings {
pub baud_rate: u32,
pub data_bits: DataBits,
pub parity: Parity,
pub stop_bits: StopBits,
pub flow_control: FlowControl,
pub timeout: Duration,
}
pub struct Port { pub struct Port {
serial_port: Box<dyn SerialPort>, serial_port: Box<dyn SerialPort>,
} }
impl Port { impl Port {
pub fn open(settings: SerialPortSettings) -> VerboseResult<Self> { pub fn open(settings: SerialPortSettings) -> Result<Self> {
let port_path = Self::find_macroboard()?; let port_path = Self::find_macroboard()?;
let port = serialport::open_with_settings(&port_path, &settings).map_err(|err| { let port = serialport::new(port_path, settings.baud_rate)
format!( .data_bits(settings.data_bits)
"could not open serial port ({:?}, {}, {})", .parity(settings.parity)
err.kind(), .stop_bits(settings.stop_bits)
err, .flow_control(settings.flow_control)
port_path .timeout(settings.timeout)
) .open()?;
})?;
Ok(Port { serial_port: port }) Ok(Port { serial_port: port })
} }
#[allow(unused)] #[allow(unused)]
pub fn read(&mut self) -> VerboseResult<SerialReadResult> { pub fn read(&mut self) -> Result<SerialReadResult> {
let mut buf: Vec<u8> = (0..255).collect(); let mut buf: Vec<u8> = (0..255).collect();
match self.serial_port.read(&mut buf[..]) { match self.serial_port.read(&mut buf[..]) {
Ok(t) => Ok(SerialReadResult::Message( Ok(t) => Ok(SerialReadResult::Message(
String::from_utf8(buf[0..t].to_vec()) String::from_utf8(buf[0..t].to_vec())
.map_err(|err| format!("failed converting utf8 buffer ({})", err))?, .map_err(|err| anyhow!("failed converting utf8 buffer ({})", err))?,
)), )),
Err(ref e) if e.kind() == io::ErrorKind::TimedOut => Ok(SerialReadResult::Timeout), Err(ref e) if e.kind() == io::ErrorKind::TimedOut => Ok(SerialReadResult::Timeout),
Err(err) => create_error!(format!("failed reading serial port ({})", err)), Err(err) => Err(anyhow!("failed reading serial port ({})", err)),
} }
} }
#[allow(unused)] #[allow(unused)]
pub fn write(&mut self, msg: &str) -> VerboseResult<()> { pub fn write(&mut self, msg: &str) -> Result<()> {
self.serial_port self.serial_port
.write(msg.as_bytes()) .write(msg.as_bytes())
.map_err(|err| format!("failed writing to serial port ({})", err))?; .map_err(|err| anyhow!("failed writing to serial port ({})", err))?;
Ok(()) Ok(())
} }
fn find_macroboard() -> VerboseResult<String> { fn find_macroboard() -> Result<String> {
let available_ports = serialport::available_ports() let available_ports = serialport::available_ports()
.map_err(|err| format!("error querying serial ports ( {})", err))?; .map_err(|err| anyhow!("error querying serial ports ( {})", err))?;
for available_port in available_ports.iter() { for available_port in available_ports.iter() {
if let serialport::SerialPortType::UsbPort(usb_info) = &available_port.port_type { if let serialport::SerialPortType::UsbPort(usb_info) = &available_port.port_type {
// check for the correct device // check for the correct device
if let Some(product_name) = &usb_info.product { if let Some(product_name) = &usb_info.product {
if product_name == "FT232R_USB_UART" if product_name == "FT232R_USB_UART"
&& usb_info.vid == 1027 && usb_info.vid == 0x0403
&& usb_info.pid == 24577 && usb_info.pid == 0x6001
{ {
return Ok(available_port.port_name.clone()); return Ok(available_port.port_name.clone());
} }
@ -74,6 +79,6 @@ impl Port {
} }
} }
create_error!("macro board not found on usb bus") return Err(anyhow!("macro board not found on usb bus".to_string()));
} }
} }

View file

@ -1,61 +1,27 @@
use utilities::prelude::*; use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::{fs::File, io::Write};
pub const COMMAND_COUNT: usize = 8; pub const COMMAND_COUNT: usize = 8;
const COMMANDS_TAG: &str = "Commands"; #[derive(Debug, Serialize, Deserialize)]
const COMMANDS: [&str; COMMAND_COUNT] = [
"command_1",
"command_2",
"command_3",
"command_4",
"command_5",
"command_6",
"command_7",
"command_8",
];
pub struct Config { pub struct Config {
pub commands: [Option<String>; COMMAND_COUNT], pub commands: [Option<String>; COMMAND_COUNT],
} }
impl Config { impl Config {
pub fn open(path: &str) -> VerboseResult<Config> { pub fn open(path: &str) -> Result<Config> {
let mut config = Config::default(); Ok(serde_json::from_str(&std::fs::read_to_string(path)?)?)
let config_loader = match ConfigHandler::read_config(path) {
Ok(config_loader) => config_loader,
Err(_) => return Ok(config),
};
if let Some(commands) = config_loader.get(COMMANDS_TAG) {
for i in 0..COMMAND_COUNT {
if let Some(command) = commands.get(COMMANDS[i]) {
config.commands[i] = Some(command.to_value()?);
}
}
} }
Ok(config) pub fn save(&self, path: &str) -> Result<()> {
} let mut file = File::create(path)?;
let s = serde_json::to_string(self)?;
pub fn save(&self, path: &str) -> VerboseResult<()> { write!(file, "{}", s)?;
let fields = (0..COMMAND_COUNT)
.collect::<Vec<usize>>()
.iter()
.map(|i| {
(
COMMANDS[*i],
match &self.commands[*i] {
Some(command) => Value::from_value(command),
None => Value::empty(),
},
)
})
.collect();
let data = &[(COMMANDS_TAG, fields)]; Ok(())
ConfigHandler::write_config(path, data)
} }
} }