dmrconfig/src/lib.rs

190 lines
5.6 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 serial;
mod radio;
const COPYRIGHT: &'static str = "Copyright (C) 2018 Serge Vakulenko KK6ABQ";
const VERSION: Option<&'static str> = option_env!("VERSION");
fn version() -> &'static str {
VERSION.unwrap_or("-------")
}
fn print_usage() {
let version = version();
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 trace_flag = matches.opt_present("t");
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, trace_flag);
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, trace_flag);
radio::print_version(&device);
radio::save_image(&device, "device.img");
radio::parse_config(&device, &config_filename);
radio::verify_config(&device);
radio::upload(&device, 1, trace_flag);
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, trace_flag);
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, Some(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(&device, None);
}
exit(0);
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}