diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5a3c16b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "workbench.colorCustomizations": { + "activityBar.background": "#0E3502", + "titleBar.activeBackground": "#144B03", + "titleBar.activeForeground": "#F1FEED" + } +} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 874a5c2..b7cef6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,4 +17,6 @@ path = "src/gui.rs" [dependencies] serialport = "*" gtk = { version = "*", features = ["v3_24"] } -utilities = { git = "http://dimov.cloud:80/hodasemi/Context.git" } \ No newline at end of file +anyhow = "1.0" +serde = { version = "*", features = ["derive"] } +serde_json = "*" \ No newline at end of file diff --git a/src/gui.rs b/src/gui.rs index 899f4e5..2b8d327 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -2,7 +2,7 @@ use gtk; use gtk::prelude::*; use gtk::{Builder, Window}; -use utilities::prelude::*; +use anyhow::{anyhow, Result}; use std::fs; use std::path::Path; @@ -11,10 +11,10 @@ mod shared; use shared::config::{Config, COMMAND_COUNT}; -fn main() -> VerboseResult<()> { - gtk::init().map_err(|_| "failed to initialize GTK")?; +fn main() -> Result<()> { + 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)?; @@ -23,15 +23,15 @@ fn main() -> VerboseResult<()> { Ok(()) } -fn setup_gui(builder: Builder) -> VerboseResult<()> { +fn setup_gui(builder: Builder) -> Result<()> { let config = load_config()?; apply_config(&builder, &config)?; setup_save(&builder)?; let window: Window = builder - .get_object("MainWindow") - .ok_or("failed getting main window")?; + .object("MainWindow") + .ok_or(anyhow!("failed getting main window"))?; window.show_all(); @@ -44,8 +44,8 @@ fn setup_gui(builder: Builder) -> VerboseResult<()> { Ok(()) } -fn load_config() -> VerboseResult { - let home_dir = std::env::var("HOME").map_err(|_| "failed getting home directory")?; +fn load_config() -> Result { + let home_dir = std::env::var("HOME")?; if !Path::new(&format!("{}/.config", home_dir)).exists() { fs::create_dir(format!("{}/.config", home_dir))?; @@ -58,26 +58,26 @@ fn load_config() -> VerboseResult { 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); for i in 0..COMMAND_COUNT { let command_text_field: gtk::Entry = builder - .get_object(&format!("ButtonCommand{}", i + 1)) - .ok_or(format!("Failed getting Entry for command {}", i + 1))?; + .object(&format!("ButtonCommand{}", i + 1)) + .ok_or(anyhow!("Failed getting Entry for command {}", i + 1))?; text_fields.push(command_text_field); } let save_button: gtk::Button = builder - .get_object("SaveButton") - .ok_or("Failed getting save button")?; + .object("SaveButton") + .ok_or(anyhow!("Failed getting save button"))?; save_button.connect_clicked(move |_| { let mut config = Config::default(); 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); } @@ -98,14 +98,14 @@ fn setup_save(builder: &Builder) -> VerboseResult<()> { Ok(()) } -fn apply_config(builder: &Builder, config: &Config) -> VerboseResult<()> { +fn apply_config(builder: &Builder, config: &Config) -> Result<()> { for i in 0..COMMAND_COUNT { if let Some(command) = &config.commands[i] { let command_text_field: gtk::Entry = builder - .get_object(&format!("ButtonCommand{}", i + 1)) - .ok_or(format!("Failed getting Entry for command {}", i + 1))?; + .object(&format!("ButtonCommand{}", 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); } } diff --git a/src/service.rs b/src/service.rs index 13c604f..ee17c00 100644 --- a/src/service.rs +++ b/src/service.rs @@ -1,9 +1,9 @@ mod service_specific; +use anyhow::Result; use service_specific::*; -use utilities::prelude::*; -fn main() -> VerboseResult<()> { +fn main() -> Result<()> { let mut port = Port::open(SerialPortSettings { baud_rate: 9600, data_bits: DataBits::Eight, diff --git a/src/service_specific/message_builder.rs b/src/service_specific/message_builder.rs index 690cc2f..ffda862 100644 --- a/src/service_specific/message_builder.rs +++ b/src/service_specific/message_builder.rs @@ -24,7 +24,7 @@ impl MessageBuilder { if !self.complete { match msg.chars().position(|c| c == MESSAGE_END) { Some(position) => { - let mut remaining_msg = msg.split_off(position); + let remaining_msg = msg.split_off(position); self.message.push_str(&msg); self.complete = true; diff --git a/src/service_specific/port.rs b/src/service_specific/port.rs index 518eafd..5f6bad1 100644 --- a/src/service_specific/port.rs +++ b/src/service_specific/port.rs @@ -1,11 +1,8 @@ -use serialport; -use serialport::prelude::*; - -use utilities::prelude::*; +use anyhow::{anyhow, Result}; 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 enum SerialReadResult { @@ -13,60 +10,68 @@ pub enum SerialReadResult { 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 { serial_port: Box, } impl Port { - pub fn open(settings: SerialPortSettings) -> VerboseResult { + pub fn open(settings: SerialPortSettings) -> Result { let port_path = Self::find_macroboard()?; - let port = serialport::open_with_settings(&port_path, &settings).map_err(|err| { - format!( - "could not open serial port ({:?}, {}, {})", - err.kind(), - err, - port_path - ) - })?; + let port = serialport::new(port_path, settings.baud_rate) + .data_bits(settings.data_bits) + .parity(settings.parity) + .stop_bits(settings.stop_bits) + .flow_control(settings.flow_control) + .timeout(settings.timeout) + .open()?; Ok(Port { serial_port: port }) } #[allow(unused)] - pub fn read(&mut self) -> VerboseResult { + pub fn read(&mut self) -> Result { let mut buf: Vec = (0..255).collect(); match self.serial_port.read(&mut buf[..]) { Ok(t) => Ok(SerialReadResult::Message( 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(err) => create_error!(format!("failed reading serial port ({})", err)), + Err(err) => Err(anyhow!("failed reading serial port ({})", err)), } } #[allow(unused)] - pub fn write(&mut self, msg: &str) -> VerboseResult<()> { + pub fn write(&mut self, msg: &str) -> Result<()> { self.serial_port .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(()) } - fn find_macroboard() -> VerboseResult { + fn find_macroboard() -> Result { 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() { if let serialport::SerialPortType::UsbPort(usb_info) = &available_port.port_type { // check for the correct device if let Some(product_name) = &usb_info.product { if product_name == "FT232R_USB_UART" - && usb_info.vid == 1027 - && usb_info.pid == 24577 + && usb_info.vid == 0x0403 + && usb_info.pid == 0x6001 { 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())); } } diff --git a/src/shared/config.rs b/src/shared/config.rs index 92d32e0..8cf78e1 100644 --- a/src/shared/config.rs +++ b/src/shared/config.rs @@ -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; -const COMMANDS_TAG: &str = "Commands"; -const COMMANDS: [&str; COMMAND_COUNT] = [ - "command_1", - "command_2", - "command_3", - "command_4", - "command_5", - "command_6", - "command_7", - "command_8", -]; - +#[derive(Debug, Serialize, Deserialize)] pub struct Config { pub commands: [Option; COMMAND_COUNT], } impl Config { - pub fn open(path: &str) -> VerboseResult { - let mut config = Config::default(); - - 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 open(path: &str) -> Result { + Ok(serde_json::from_str(&std::fs::read_to_string(path)?)?) } - pub fn save(&self, path: &str) -> VerboseResult<()> { - let fields = (0..COMMAND_COUNT) - .collect::>() - .iter() - .map(|i| { - ( - COMMANDS[*i], - match &self.commands[*i] { - Some(command) => Value::from_value(command), - None => Value::empty(), - }, - ) - }) - .collect(); + pub fn save(&self, path: &str) -> Result<()> { + let mut file = File::create(path)?; + let s = serde_json::to_string(self)?; - let data = &[(COMMANDS_TAG, fields)]; + write!(file, "{}", s)?; - ConfigHandler::write_config(path, data) + Ok(()) } }