extern crate serialport;
use byteorder::{BigEndian, ByteOrder};
use prust_core::sp::{services, SpacePacket};
use serialport::prelude::*;
use serialport::{available_ports, open_with_settings, SerialPortSettings};
use std::string::String;
use std::thread;
use std::time::Duration;
extern crate clap;
use clap::{App, AppSettings, Arg, SubCommand};
use rustyline::Editor;
use rustyline::{config::Configurer, error::ReadlineError};
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use text_io::scan;
use utils::list_ports;
const ERROR_NAMES: [&str; prust_core::error::ERR_CODE_COUNT] = [
"UnsupportedRequest",
"InvalidPacket",
"CorruptData",
"InvalidPacketName",
"InvalidVersionNo",
"InvalidApid",
"InvalidFuncId",
"PeripheralError",
"BorrowMutError",
"NoneError",
"UnitType",
"InvalidArg",
"CapacityError",
];
fn main() {
let app = App::new("tc")
.global_setting(AppSettings::NoBinaryName)
.subcommand(SubCommand::with_name("q").about("quit"))
.subcommand(
SubCommand::with_name("exec_func")
.about("Sends a request to execute a function defined")
.arg(
Arg::with_name("func_name")
.required(true)
.help("func_id of the function")
.number_of_values(1),
)
.arg(
Arg::with_name("args")
.required(true)
.min_values(0)
.help("arguments of the function"),
),
)
.subcommand(
SubCommand::with_name("new_report")
.about("Creates new housekeeping report structure")
.arg(
Arg::with_name("hk_id")
.number_of_values(1)
.required(true)
.help("housekeeping structure id"),
)
.arg(
Arg::with_name("param_ids")
.required(true)
.min_values(1)
.help("parameters that will be reported in this structure"),
),
)
.subcommand(
SubCommand::with_name("one_shot")
.about("Sends a one shot request for the specified hk id")
.arg(
Arg::with_name("hk_ids")
.required(true)
.min_values(1)
.help("Housekeeping structure id to be reported"),
),
)
.subcommand(
SubCommand::with_name("periodic_en")
.about("Enables peridic report of parameters of the given struct ids")
.arg(
Arg::with_name("structure_ids")
.required(true)
.min_values(1)
.required(true)
.help("Housekeeping structure id to be configured"),
),
)
.subcommand(
SubCommand::with_name("periodic_dis")
.about("Disables peridic report of parameters of the given struct ids")
.arg(
Arg::with_name("structure_ids")
.required(true)
.min_values(1)
.help("Housekeeping structure id to be configured"),
),
);
let mut rl = Editor::<()>::new();
rl.set_auto_add_history(true);
print!("Please specify device index: ");
if list_ports() == 0 {
return;
};
let idx: usize;
scan!("{}", idx);
let s = SerialPortSettings {
baud_rate: 115_200,
data_bits: DataBits::Eight,
flow_control: FlowControl::None,
parity: Parity::None,
stop_bits: StopBits::One,
timeout: Duration::from_millis(100),
};
let mut serialport = open_with_settings(
&available_ports()
.expect("No serial port")
.get(idx)
.expect("No serial port listed")
.port_name,
&s,
)
.expect("Failed to open serial port");
let mut clone = serialport.try_clone().expect("Failed to clone");
std::thread::sleep(std::time::Duration::from_millis(100));
thread::spawn(move || {
let path = Path::new("out.txt");
let mut file = match File::create(&path) {
Err(why) => panic!("couldn't open file: {}", why),
Ok(file) => file,
};
loop {
let mut buf: Vec<u8> = vec![0; 1024];
while clone.read_data_set_ready().unwrap() {}
if clone.read_exact(&mut buf[0..6]).is_err() {
continue;
};
let ph = match prust_core::sp::PrimaryHeader::from_bytes(&buf[0..6]) {
Ok(p) => p,
Err(_) => {
continue;
}
};
let data_len = ph.get_data_len() + 1;
if data_len + 6 > 1024 || clone.read_exact(&mut buf[6..data_len + 6]).is_err() {
continue;
}
let data_len = data_len + 6;
let ser_type = match prust_core::sp::get_service_type(&buf[0..data_len]) {
Ok(res) => res,
_ => continue,
};
if ser_type == (1, 7) {
writeln!(file, "TM SUCCESS RESPONSE").unwrap();
let res_pack = SpacePacket::<
prust_core::sp::tm::TmPacket<services::service_1::ServiceSuccess>,
>::from_bytes(&buf[0..data_len])
.unwrap();
writeln!(file, "TM pack:\n{:#?}", res_pack).unwrap();
} else if ser_type == (1, 8) {
writeln!(file, "TM FAILURE RESPONSE").unwrap();
let res_pack = SpacePacket::<
prust_core::sp::tm::TmPacket<services::service_1::Service1_8>,
>::from_bytes(&buf[0..data_len])
.unwrap();
let (code, data) = res_pack.get_err();
writeln!(file, "TM pack:\n{:#?}", res_pack).unwrap();
writeln!(
file,
"Error Type:{:?}\nError Data:{:?}",
ERROR_NAMES[code as usize],
String::from_utf8(data).unwrap()
)
.unwrap();
} else if ser_type == (3, 25) {
writeln!(file, "Tm Parameter Response").unwrap();
let res_pack = SpacePacket::<
prust_core::sp::tm::TmPacket<services::service_3::service_3_25::Service3_25>,
>::from_bytes(&buf[0..data_len])
.unwrap();
writeln!(file, "TM pack:\n{:#?}", res_pack).unwrap();
writeln!(
file,
"PERIPHERAL VALUE RECIEVED:{}",
BigEndian::read_u16(res_pack.get_parameter_values().as_slice())
)
.unwrap();
} else {
continue;
}
writeln!(
file,
"The packet recieved (in bytes):\n{:?}",
&buf[0..data_len]
)
.unwrap();
}
});
loop {
let input = match rl.readline(">> ") {
Ok(l) => l,
Err(ReadlineError::Interrupted) => {
println!("CTRL-C");
std::process::exit(0x0000)
}
Err(ReadlineError::Eof) => {
println!("CTRL-D");
std::process::exit(0x0000)
}
Err(err) => {
println!("Error: {:?}", err);
std::process::exit(0x0100)
}
};
let args: Vec<&str> = input.split_ascii_whitespace().collect();
let matc = match app.clone().get_matches_from_safe(args) {
Ok(m) => m,
Err(e) => {
println!("{}", e.message);
continue;
}
};
let mes: Vec<u8> = match matc.subcommand() {
("exec_func", Some(exec_matches)) => {
let func_id = exec_matches.value_of("func_name").unwrap();
let args_field: Vec<u8> = exec_matches
.values_of("args")
.unwrap_or_default()
.map(|s| s.parse::<u8>().unwrap())
.collect();
SpacePacket::new_service_8_1(
42,
0,
func_id.to_string(),
args_field.len() as u8,
args_field,
)
.unwrap()
.to_bytes()
}
("new_report", Some(new_matches)) => {
let report_id = new_matches
.value_of("hk_id")
.unwrap()
.parse()
.expect("hk_id should be u8");
let params: Vec<u8> = new_matches
.values_of("param_ids")
.unwrap()
.map(|s| s.parse::<u8>().unwrap())
.collect();
SpacePacket::new_service_3_1(42, 0, report_id, 1, params.len() as u8, params)
.unwrap()
.to_bytes()
}
("periodic_en", Some(ids)) => {
let ids: Vec<u8> = ids
.values_of("structure_ids")
.unwrap()
.map(|s| s.parse::<u8>().unwrap())
.collect();
SpacePacket::new_service_3_5(42, 0, ids.len() as u8, ids)
.unwrap()
.to_bytes()
}
("periodic_dis", Some(ids)) => {
let ids: Vec<u8> = ids
.values_of("structure_ids")
.unwrap()
.map(|s| s.parse::<u8>().unwrap())
.collect();
SpacePacket::new_service_3_6(42, 0, ids.len() as u8, ids)
.unwrap()
.to_bytes()
}
("one_shot", Some(shot_matches)) => {
let params: Vec<u8> = shot_matches
.values_of("hk_ids")
.unwrap()
.map(|s| s.parse::<u8>().unwrap())
.collect();
SpacePacket::new_service_3_27(42, 0, params.len() as u8, params)
.unwrap()
.to_bytes()
}
("q", _) => std::process::exit(0x0000),
_ => Vec::new(),
};
if mes.len() == 0 {
continue;
}
println!("The packet send:\n{:?}", mes);
serialport.write(mes.as_slice()).unwrap();
}
}