#![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); } }