This commit fully implements the read and write key function

This commit included quite a lot of changes:

* The application arguments are now divided in a read and a write part.
  This is realized through structopt subcommands.
* The read and write commands are recognized in a match construction
  which takes place after the device is opened.
* I refactored some of the error messages and added more error messages
* The pedals_read() function now is able to read 1, 2, or 3 pedals.
  Furthermore, the table is now redrawn with box drawing symbols.
* The write function is tested and successfully writes a key to the
  device
This commit is contained in:
Dennis Potter 2018-07-26 00:35:25 +02:00
parent e792c72255
commit 551a97f359
2 changed files with 126 additions and 27 deletions

View File

@ -10,25 +10,48 @@ extern crate structopt;
extern crate hidapi; extern crate hidapi;
extern crate users; extern crate users;
use std::path::PathBuf;
use std::process; use std::process;
use structopt::StructOpt; use structopt::StructOpt;
#[derive(StructOpt, Debug)] #[derive(StructOpt, Debug)]
#[structopt(name = "rust-footswitch")] #[structopt(name = "rust-footswitch")]
struct Opt { struct Opt {
/// Read all pedals
#[structopt(short = "r", long = "read")]
read: bool,
/// Prints a table of all keys with <listkeys> rows /// Prints a table of all keys with <listkeys> rows
#[structopt(short = "l", long = "listkeys")] #[structopt(short = "l", long = "listkeys")]
listkeys: Option<usize>, listkeys: Option<usize>,
/// Select pedal (left: 1, middle: 2, right: 3) #[structopt(subcommand)]
#[structopt(short = "p", long = "pedal", parse(from_os_str))] cmd: Option<Command>,
output: Option<PathBuf>, }
#[derive(StructOpt, Debug)]
enum Command {
/// Write to the footpedal
#[structopt(name = "write")]
Write {
/// Specify pedal to modify with following command. Possible values: [0 | 1 | 2]
#[structopt(short = "p", long = "pedal")]
pedal: Vec<u8>,
/// Command to apply. Possible values: [set_key | del_key | append_key | append_str]
#[structopt(short = "c", long = "command")]
command: Vec<String>,
/// Value to apply
#[structopt(short = "v", long = "value")]
value: Vec<String>,
},
#[structopt(name = "read")]
Read {
/// Read all pedals
#[structopt(short = "a", long = "all")]
all: bool,
/// Specify specific pedals. Possible values: [0 | 1 | 2]
#[structopt(short = "p", long = "pedal")]
pedals: Vec<u8>,
}
} }
fn main() { fn main() {
@ -66,23 +89,74 @@ fn main() {
} }
} }
let dev = api.open_path(dev_path.as_str()).unwrap(); let dev = api.open_path(dev_path.as_str()).unwrap();
println!("Succesfully opened device."); println!("Succesfully opened device.");
//ToDo: This part of the code is just there to test functions
pedals.set_key(0, "b");
pedals.write_pedals(& dev);
// All options that need the device to be open // All options that need the device to be open
if opt.read { match opt.cmd {
pedals.read_pedals(& dev); Some(Command::Write {pedal: ped_list, command: cmd_list, value: val_list}) => {
if ped_list.len() != cmd_list.len() && ped_list.len() != val_list.len() {
eprintln!("Error: You must define as much pedals as you define commands and as you define values!");
process::exit(0);
}
for (i, cmd) in cmd_list.iter().enumerate() {
match cmd as &str {
"wr_key" => {
pedals.set_key(i, val_list[i].as_str());
}
"del_key" => {
}
"append_key" => {
}
"append_str" => {
}
_ => {
eprintln!("Error: Unkonwn command!");
process::exit(0);
}
}
}
// Since we ran the Write command without any errors, we are now writing everything
pedals.write_pedals(& dev);
println!("Succesfully wrote everything to footpedal!");
println!("The current state of the device is shown below.\n");
// Show user current state of pedal
pedals.read_pedals(&dev, vec![0,1,2]);
},
Some(Command::Read {all: all_var, pedals: ped_list}) => {
if ped_list.len() > 3 {
eprintln!("Error: Number of pedals may not be bigger than 3!");
process::exit(0);
}
if all_var {
pedals.read_pedals(&dev, vec![0,1,2]);
}
else if ped_list.len() > 0 {
pedals.read_pedals(&dev, ped_list)
}
else {
eprintln!("Error: You did not specify any command. Run './footswitch-rs read --help' for more information");
process::exit(0);
}
},
None => {
eprintln!("Error: You did not specify any command. Run './footswitch-rs --help' for more information.");
process::exit(0);
}
} }
} }
/// Checks if user is super user /// Checks if user is super user
fn check_sudo() { fn check_sudo() {
if users::get_current_uid() != 0 { if users::get_current_uid() != 0 {
panic!("Please execute this application as super user!"); eprintln!("Error: Please execute this application as super user!");
process::exit(0);
} }
} }

View File

@ -1,6 +1,7 @@
#[path = "key_operations.rs"] mod key_operations; #[path = "key_operations.rs"] mod key_operations;
extern crate hidapi; extern crate hidapi;
use std::process;
pub struct PedalsData { pub struct PedalsData {
header: [u8; 8], header: [u8; 8],
@ -49,7 +50,7 @@ impl Pedals {
} }
} }
fn read_pedal(&self, dev: & hidapi::HidDevice, ped:u8) -> [u8; 8] { pub fn read_pedal(&self, dev: & hidapi::HidDevice, ped:& u8) -> [u8; 8] {
let mut buf = [0u8; 8]; let mut buf = [0u8; 8];
let mut query = [0x01u8, 0x82, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00]; let mut query = [0x01u8, 0x82, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00];
@ -65,26 +66,49 @@ impl Pedals {
} }
/// Read the current values of the pedals /// Read the current values of the pedals
pub fn read_pedals(&self, dev: & hidapi::HidDevice) { pub fn read_pedals(&self, dev: & hidapi::HidDevice, peds: Vec<u8>) {
let column_width = 15; // This is kind of hacky, but for number of pedals == 2, the table shifts.
let total_width = (column_width+3)*3; let total_width = 62 + (peds.len() == 2) as usize;
let column_width = 60 / peds.len() + (3 - peds.len());
// Print header // Print header
println!(" {}", "-".repeat(total_width)); println!("{}", "".repeat(total_width));
println!("{name:^width$}", name = "Programmed Keys", width = total_width - 2); println!("{name:^width$}", name = "Programmed Keys", width = total_width);
println!(" {}", "-".repeat(total_width)); println!("{}", "".repeat(total_width));
// Print space before pedal number row
print!(" ");
// Print pedal numbers
for i in peds.iter() {
// Check if passed pedal number is valid
if *i > 2 {
eprintln!("Error: Pedal value {} is larger than 2 and thus not valid!", i);
process::exit(0);
}
// Print pedal numbers
print!("{ped_nr:^-width$}", ped_nr = i, width = column_width);
}
println!("\n{}", "".repeat(total_width));
// Print space before value row
print!(" ");
// Read and print keys // Read and print keys
for i in 0..3 { for i in peds.iter() {
// Read value from pedal and directly translate it to a key
let key_name = match key_operations::print_key(&self.read_pedal(dev, i)) { let key_name = match key_operations::print_key(&self.read_pedal(dev, i)) {
Some(key) => key, Some(key) => key,
None => "< None >".to_string(), None => "< None >".to_string(),
}; };
print!("{name:^-width$}", name = key_name, width = column_width);
print!("{name:^-width$}", name = key_name, width = column_width);
} }
// Print simple footer // Print simple footer
println!("\n {}", "-".repeat(total_width)); println!("\n{}", "".repeat(total_width));
} }
fn write_pedal(&self, dev: & hidapi::HidDevice, ped:usize) { fn write_pedal(&self, dev: & hidapi::HidDevice, ped:usize) {
@ -125,7 +149,8 @@ impl Pedals {
self.ped_data[ped].data[3] = encoded_key; self.ped_data[ped].data[3] = encoded_key;
} }
else { else {
//ToDo: add "print list" if value is not recognized eprintln!("Error: Key '{}' is not recognized! Please provide a valid key, listed in './footswitch-rs --listkeys 4'", key);
process::exit(0);
} }
} }