diff --git a/Cargo.lock b/Cargo.lock index a689730..3197696 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -207,6 +207,7 @@ dependencies = [ "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", "signal-hook 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "warp 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1620,6 +1621,14 @@ dependencies = [ "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "toml" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tower-service" version = "0.3.0" @@ -2104,6 +2113,7 @@ dependencies = [ "checksum tokio-tls 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a70f4fcd7b3b24fb194f837560168208f669ca8cb70d0c4b862944452396343" "checksum tokio-tungstenite 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b8fe88007ebc363512449868d7da4389c9400072a3f666f212c7280082882a" "checksum tokio-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" +"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" "checksum tower-service 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" "checksum tungstenite 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cfea31758bf674f990918962e8e5f07071a3161bd7c4138ed23e416e1ac4264e" diff --git a/Cargo.toml b/Cargo.toml index bec5435..a52a999 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ clap = "2.33.1" gpio-cdev = "0.3.0" nix = "0.17.0" anyhow = "1.0.31" +toml = "0.5.6" [features] vendored = ["openssl-sys/vendored"] diff --git a/resources/config.toml b/resources/config.toml new file mode 100644 index 0000000..df87ca2 --- /dev/null +++ b/resources/config.toml @@ -0,0 +1,20 @@ +[gpio] +chip_name = "/dev/gpiochip0" + + [gpio.display] + rs = 14 + enable = 15 + data = [6, 13, 19, 26, 255, 255, 255, 255] + rw = 255 + four_bit = true + + [gpio.buttons] + mode = 27 + cycle = 17 + fn0 = 22 + fn1 = 23 + fn2 = 24 + +[tasks] +host = "localhost" +port = "3030" diff --git a/resources/systemd_files/desktopper_display.service b/resources/systemd_files/desktopper_display.service index d4f1bfc..23fe821 100644 --- a/resources/systemd_files/desktopper_display.service +++ b/resources/systemd_files/desktopper_display.service @@ -5,7 +5,7 @@ After=desktopper.service After=task_api.service [Service] -ExecStart=/usr/local/bin/desktopper --rs 14 --enable 15 --data_pins 6 13 19 26 255 255 255 255 -f --cycle_button 17 --mode_button 27 --fn_button_0 22 --fn_button_1 23 --fn_button_2 24 +ExecStart=/usr/local/bin/desktopper -c /etc/desktopper/config.toml Restart=on-failure [Install] diff --git a/resources/target_deploy.sh b/resources/target_deploy.sh index 3435a29..0d50522 100644 --- a/resources/target_deploy.sh +++ b/resources/target_deploy.sh @@ -4,6 +4,8 @@ systemctl stop desktopper task_api desktopper_display systemctl disable desktopper task_api desktopper_display echo "Moving files" mv systemd_files/* /etc/systemd/system/ +mkdir -p /etc/desktopper +mv config.toml /etc/desktopper mv $BIN_DIR/api_server /usr/local/bin/ mv $BIN_DIR/desktopper /usr/local/bin/ echo "Reloading service files" diff --git a/src/bin/desktopper.rs b/src/bin/desktopper.rs index ce47e53..32586db 100644 --- a/src/bin/desktopper.rs +++ b/src/bin/desktopper.rs @@ -16,6 +16,51 @@ use std::sync::mpsc; use std::sync::mpsc::TryRecvError; use std::time::Instant; +mod config { + use serde::Deserialize; + use std::io::BufReader; + + #[derive(Deserialize)] + pub struct Config { + pub gpio: GPIO, + pub tasks: Tasks, + } + + #[derive(Deserialize)] + pub struct GPIO { + pub chip_name: String, + pub display: DisplayConfig, + pub buttons: ButtonConfig, + } + #[derive(Deserialize)] + pub struct DisplayConfig { + pub rs: u8, + pub enable: u8, + pub data: [u8; 8], + pub rw: u8, + pub four_bit: bool, + } + + #[derive(Deserialize)] + pub struct ButtonConfig { + pub mode: u32, + pub cycle: u32, + pub fn0: u32, + pub fn1: u32, + pub fn2: u32, + } + + #[derive(Deserialize)] + pub struct Tasks { + pub host: String, + pub port: String, + } + + pub fn parse_file(file_location: &str) -> Config { + toml::from_str(std::fs::read_to_string(file_location).unwrap().as_str()).unwrap() + } +} + fn main() -> anyhow::Result<()> { // Always enable some form of logging if std::env::var_os("RUST_LOG").is_none() { @@ -24,142 +69,33 @@ fn main() -> anyhow::Result<()> { pretty_env_logger::init(); let matches = App::new("Desktopper") .arg( - Arg::with_name("api_host") - .short("a") - .long("api_host") - .value_name("API_HOST") - .default_value("localhost") - .takes_value(true), - ) - .arg( - Arg::with_name("api_port") - .short("p") - .long("api_port") - .long("API_PORT") - .default_value("3030") - .takes_value(true), - ) - .arg( - Arg::with_name("chip") + Arg::with_name("config_file") .short("c") - .long("chip") - .value_name("CHIP") - .help("Sets the chip to use for GPIO") - .default_value("/dev/gpiochip0") - .takes_value(true), - ) - .arg( - Arg::with_name("four_bit_mode") - .short("f") - .long("mode") - .help("Sets the bit mode for the LCD panel") - .takes_value(false), - ) - .arg( - Arg::with_name("rs") - .long("rs") - .value_name("RS_PIN") - .help("The pin to use for rs") - .takes_value(true) - .required(true), - ) - .arg( - Arg::with_name("rw") - .long("rw") - .value_name("RW_PIN") - .help("The pin to use for rw") - .default_value("255") - .takes_value(true), - ) - .arg( - Arg::with_name("enable") - .short("e") - .long("enable") - .value_name("ENABLE_PIN") - .help("The pin to use for enable") - .takes_value(true) - .required(true), - ) - .arg( - Arg::with_name("data_pins") - .short("d") - .long("data_pins") - .value_name("DATA_PINS") - .help("The 4/8 data pins") - .multiple(true) - .required(true), - ) - .arg( - Arg::with_name("mode_button") - .short("m") - .long("mode_button") - .value_name("MODE_PIN") - .help("The pin to change/reset the mode of the system") - .required(true), - ) - .arg( - Arg::with_name("cycle_button") - .long("cycle_button") - .value_name("CYCLE_PIN") - .help("The pin to cycle values in the system") - .required(true), - ) - .arg( - Arg::with_name("fn_button_0") - .long("fn_button_0") - .value_name("BUTTON_0") - .help("THe pin to use a function button 0") - .required(true), - ) - .arg( - Arg::with_name("fn_button_1") - .long("fn_button_1") - .value_name("BUTTON_1") - .help("THe pin to use a function button 1") - .required(true), - ) - .arg( - Arg::with_name("fn_button_2") - .long("fn_button_2") - .value_name("BUTTON_2") - .help("THe pin to use a function button 2") - .required(true), + .long("config") + .default_value("/etc/desktopper/config.toml"), ) .get_matches(); - let mut chip = Chip::new(matches.value_of("chip").unwrap())?; - - let data_pins_res: Vec> = matches - .values_of("data_pins") - .unwrap() - .map(|p| u8::from_str(p)) - .collect(); + let cfg = config::parse_file(matches.value_of("config_file").unwrap()); - let mut data_pins = Vec::new(); - - if data_pins_res.len() != 8 && data_pins_res.iter().any(|res| res.is_err()) { - return Err(anyhow!("Invalid number of data_pins, must be 4 or 8")); - } - data_pins_res.iter().for_each(|pin_res| { - data_pins.push(pin_res.as_ref().unwrap()); - }); + let mut chip = Chip::new(cfg.gpio.chip_name.clone())?; let lcd_driver = LcdDriver::new( 16, 2, - matches.value_of("chip").unwrap(), - true, - u8::from_str(matches.value_of("rs").unwrap()).unwrap(), - u8::from_str(matches.value_of("rw").unwrap()).unwrap(), - u8::from_str(matches.value_of("enable").unwrap()).unwrap(), - *data_pins[0], - *data_pins[1], - *data_pins[2], - *data_pins[3], - *data_pins[4], - *data_pins[5], - *data_pins[6], - *data_pins[7], + cfg.gpio.chip_name.as_str(), + cfg.gpio.display.four_bit, + cfg.gpio.display.rs, + cfg.gpio.display.rw, + cfg.gpio.display.enable, + cfg.gpio.display.data[0], + cfg.gpio.display.data[1], + cfg.gpio.display.data[2], + cfg.gpio.display.data[3], + cfg.gpio.display.data[4], + cfg.gpio.display.data[5], + cfg.gpio.display.data[6], + cfg.gpio.display.data[7], )?; let scheduled_lcd = ThreadedLcd::with_driver(lcd_driver); @@ -169,24 +105,24 @@ fn main() -> anyhow::Result<()> { let mut input_handler = InputHandler::new( &mut chip, tx, - u32::from_str(matches.value_of("mode_button").unwrap()).unwrap(), - u32::from_str(matches.value_of("cycle_button").unwrap()).unwrap(), - u32::from_str(matches.value_of("fn_button_0").unwrap()).unwrap(), - u32::from_str(matches.value_of("fn_button_1").unwrap()).unwrap(), - u32::from_str(matches.value_of("fn_button_2").unwrap()).unwrap(), + cfg.gpio.buttons.mode, + cfg.gpio.buttons.cycle, + cfg.gpio.buttons.fn0, + cfg.gpio.buttons.fn1, + cfg.gpio.buttons.fn2, ); input_handler.start(); let mut display_state = ScreenState::new(scheduled_lcd); + display_state.add(Box::new(ClockDisplay::new())); display_state.add(Box::new(TaskDisplay::new( - matches.value_of("api_host").unwrap(), - matches.value_of("api_port").unwrap(), + cfg.tasks.host.as_str(), + cfg.tasks.port.as_str(), ))); display_state.add(Box::new(TestDisplay {})); - display_state.add(Box::new(ClockDisplay::new())); - + display_state.next(); let mut button_state: Option; loop { diff --git a/src/frontend/screens.rs b/src/frontend/screens.rs index 42d035a..8e3a87f 100644 --- a/src/frontend/screens.rs +++ b/src/frontend/screens.rs @@ -191,7 +191,7 @@ impl Screen for ClockDisplay { } fn get_tick(&self) -> Option { - Some(Duration::from_millis(250)) + Some(Duration::from_secs(1)) } fn tick(&mut self, lcd: &mut ThreadedLcd) {