184 lines
5.4 KiB
Rust
184 lines
5.4 KiB
Rust
#![allow(non_upper_case_globals)]
|
|
#![allow(non_camel_case_types)]
|
|
#![allow(non_snake_case)]
|
|
|
|
use libc::{c_int, c_char};
|
|
use getopts::Options;
|
|
use std::process::exit;
|
|
|
|
|
|
mod radio;
|
|
|
|
const COPYRIGHT: &'static str = "Copyright (C) 2018 Serge Vakulenko KK6ABQ";
|
|
const VERSION: Option<&'static str> = option_env!("VERSION");
|
|
|
|
|
|
fn print_usage() {
|
|
let version = VERSION.unwrap_or("-----");
|
|
|
|
print!("DMR Config, Version {}, {}", version, COPYRIGHT);
|
|
|
|
let msg = r#"
|
|
Usage:
|
|
dmrconfig -r [-t]
|
|
Read codeplug from the radio to a file 'device.img'.
|
|
Save configuration to a text file 'device.conf'.
|
|
dmrconfig -w [-t] file.img
|
|
Write codeplug to the radio.
|
|
dmrconfig -v [-t] file.conf
|
|
Verify configuration script for the radio.
|
|
dmrconfig -c [-t] file.conf
|
|
Apply configuration script to the radio.
|
|
dmrconfig -c file.img file.conf
|
|
Apply configuration script to the codeplug image.
|
|
Store modified copy to a file 'device.img'.
|
|
dmrconfig file.img
|
|
Display configuration from the codeplug image.
|
|
dmrconfig -u [-t] file.csv
|
|
Update contacts database from CSV file.
|
|
Options:
|
|
-r Read codeplug from the radio.
|
|
-w Write codeplug to the radio.
|
|
-c Configure the radio from a text script.
|
|
-v Verify config file.
|
|
-u Update contacts database.
|
|
-l List all supported radios.
|
|
-t Trace USB protocol."#;
|
|
print!("{}", msg);
|
|
exit(-1);
|
|
}
|
|
|
|
fn get_options() -> Options {
|
|
let mut opts = Options::new();
|
|
opts.optflag("t", "", "Trace USB protocol.");
|
|
opts.optflag("r", "", "Read codeplug from the radio to a file 'device.img'.\nSave configuration to a text file 'device.conf'.");
|
|
opts.optflag("w", "", "Write codeplug to the radio.");
|
|
opts.optflag("c", "", "Verify configuration script for the radio.");
|
|
opts.optflag("u", "", "Update contacts database from CSV file.");
|
|
opts.optflag("l", "", "List all supported radios.");
|
|
opts.optflag("v", "", "Verify configuration script for the radio.");
|
|
opts
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_main(_argc: c_int, _argv: *const *const c_char) -> c_int {
|
|
|
|
let args = std::env::args().skip(1);
|
|
let matches = match get_options().parse(args) {
|
|
Ok(m) => m,
|
|
Err(fail) => {
|
|
eprintln!("{}", fail);
|
|
exit(-1);
|
|
}
|
|
};
|
|
|
|
let list_flag = matches.opt_present("l");
|
|
let verify_flag = matches.opt_present("v");
|
|
let read_flag = matches.opt_present("r");
|
|
let write_flag = matches.opt_present("w");
|
|
let config_flag = matches.opt_present("c");
|
|
let csv_flag = matches.opt_present("u");
|
|
|
|
if list_flag {
|
|
radio::list();
|
|
exit(0);
|
|
}
|
|
|
|
if [read_flag, write_flag, config_flag, csv_flag, verify_flag].iter().filter(|x| **x).count() > 1 {
|
|
eprintln!("Only one of -r, -w, -c, -v or -u options is allowed.");
|
|
print_usage();
|
|
}
|
|
|
|
if write_flag {
|
|
if matches.free.len() != 1 {
|
|
print_usage();
|
|
}
|
|
let device = radio::connect();
|
|
radio::read_image(&matches.free[0]);
|
|
radio::print_version(device);
|
|
radio::upload(device, 0);
|
|
radio::disconnect();
|
|
} else if config_flag {
|
|
let conf_args = matches.free.len();
|
|
if !(conf_args == 1 || conf_args == 2) {
|
|
print_usage();
|
|
}
|
|
let (config_filename, image_filename) = if conf_args == 2 {
|
|
(matches.free[1].clone(), Some(matches.free[0].clone()))
|
|
} else {
|
|
(matches.free[0].clone(), None)
|
|
};
|
|
|
|
if let Some(img) = image_filename {
|
|
// Apply text config to image file.
|
|
let device = radio::connect(); //NOTE this changes the semantics of the program
|
|
radio::read_image(&img);
|
|
radio::print_version(device);
|
|
radio::parse_config(device, &config_filename);
|
|
radio::verify_config(device);
|
|
radio::save_image(device, "device.img");
|
|
} else {
|
|
// Update device from text config file.
|
|
let device = radio::connect();
|
|
radio::download(device);
|
|
radio::print_version(device);
|
|
radio::save_image(device, "device.img");
|
|
radio::parse_config(device, &config_filename);
|
|
radio::verify_config(device);
|
|
radio::upload(device, 1);
|
|
radio::disconnect();
|
|
}
|
|
} else if verify_flag {
|
|
if matches.free.len() != 1 {
|
|
print_usage();
|
|
}
|
|
// Verify text config file.
|
|
let device = radio::connect();
|
|
radio::parse_config(device, &matches.free[0]);
|
|
radio::verify_config(device);
|
|
radio::disconnect();
|
|
} else if read_flag {
|
|
if matches.free.len() != 0 {
|
|
print_usage();
|
|
}
|
|
|
|
// Dump device to image file.
|
|
let device = radio::connect();
|
|
radio::download(device);
|
|
radio::print_version(device);
|
|
radio::disconnect();
|
|
radio::save_image(device, "device.img");
|
|
|
|
// Print configuration to file.
|
|
let filename = "device.conf";
|
|
println!("Print configuration to file '{}.", filename);
|
|
|
|
radio::print_config(device, filename);
|
|
|
|
} else if csv_flag {
|
|
if matches.free.len() != 1 {
|
|
print_usage();
|
|
}
|
|
|
|
let device = radio::connect();
|
|
radio::write_csv(device, &matches.free[0]);
|
|
radio::disconnect();
|
|
} else {
|
|
if matches.free.len() != 1 {
|
|
print_usage();
|
|
}
|
|
let device = radio::read_image(&matches.free[0]);
|
|
radio::print_config_to_stdout(device);
|
|
}
|
|
|
|
exit(0);
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
#[test]
|
|
fn it_works() {
|
|
assert_eq!(2 + 2, 4);
|
|
}
|
|
}
|