diff --git a/src/cat.rs b/src/cat.rs index df69cc8..c215a4a 100644 --- a/src/cat.rs +++ b/src/cat.rs @@ -10,10 +10,10 @@ use crate::link::Protocol; /// CAT Protocol opcodes enum Opcode { - GET = 0x47, // G - SET = 0x53, // S + GET = 0x47, // G + SET = 0x53, // S DATA = 0x44, // D - ACK = 0x41, // A + ACK = 0x41, // A } impl TryFrom for Opcode { @@ -33,9 +33,9 @@ impl TryFrom for Opcode { /// CAT Protocol IDs #[derive(Copy, Clone)] enum ID { - INFO = 0x494E, // IN - FREQRX = 0x5246, // RF - FREQTX = 0x5446, // TF + INFO = 0x494E, // IN + FREQRX = 0x5246, // RF + FREQTX = 0x5446, // TF FILETRANSFER = 0x4654, // FT } @@ -46,10 +46,15 @@ const HZ_IN_MHZ: f64 = 1000000.0; fn get(id: ID) -> Vec { let mut link = Link::acquire(); - let cmd: Vec = vec![Opcode::GET as u8, - ((id as u16 >> 8) & 0xff) as u8, - (id as u16 & 0xff) as u8]; - let frame = Frame{proto: Protocol::CAT, data: cmd}; + let cmd: Vec = vec![ + Opcode::GET as u8, + ((id as u16 >> 8) & 0xff) as u8, + (id as u16 & 0xff) as u8, + ]; + let frame = Frame { + proto: Protocol::CAT, + data: cmd, + }; link.send(frame); // Loop until we get a message of the right protocol @@ -66,9 +71,15 @@ fn get(id: ID) -> Vec { match opcode { Opcode::ACK => match data[1] { 0 => (), - status => println!("Error in GET request: {:?}", Errno::try_from(status).unwrap()), + status => println!( + "Error in GET request: {:?}", + Errno::try_from(status).unwrap() + ), }, // Error? - Opcode::DATA => { data.remove(0); () }, // Correct response! + Opcode::DATA => { + data.remove(0); + () + } // Correct response! _ => panic!("Error while parsing GET response"), }; link.release(); @@ -79,11 +90,16 @@ fn get(id: ID) -> Vec { fn set(id: ID, data: &[u8]) { let mut link = Link::acquire(); - let mut cmd: Vec = vec![Opcode::SET as u8, - ((id as u16 >> 8) & 0xff) as u8, - (id as u16 & 0xff) as u8]; + let mut cmd: Vec = vec![ + Opcode::SET as u8, + ((id as u16 >> 8) & 0xff) as u8, + (id as u16 & 0xff) as u8, + ]; cmd.extend(data); - let frame = Frame{proto: Protocol::CAT, data: cmd}; + let frame = Frame { + proto: Protocol::CAT, + data: cmd, + }; link.send(frame); let mut frame: Frame; @@ -100,7 +116,10 @@ fn set(id: ID, data: &[u8]) { match opcode { Opcode::ACK => match data[1] { 0 => (), - status => println!("Error in SET request: {:?}", Errno::try_from(status).unwrap()), + status => println!( + "Error in SET request: {:?}", + Errno::try_from(status).unwrap() + ), }, // Error? _ => panic!("Error while parsing SET response"), }; @@ -130,7 +149,7 @@ pub fn freq(data: Option, is_tx: bool) { true => println!("Tx: {freq} MHz"), false => println!("Rx: {freq} MHz"), }; - }, + } // SET Some(data) => { let freq: f64 = data.parse::().unwrap(); @@ -138,7 +157,7 @@ pub fn freq(data: Option, is_tx: bool) { let mut data: [u8; 4] = [0, 0, 0, 0]; LittleEndian::write_u32(&mut data, freq); set(id, &data); - }, + } }; } diff --git a/src/dat.rs b/src/dat.rs index b3c1b2a..90f4d8d 100644 --- a/src/dat.rs +++ b/src/dat.rs @@ -1,10 +1,10 @@ //! This module handles the Data Transfer Protocol portion of rtxlink -use text_colorizer::*; -use std::fs::{File, read}; +use std::fs::{read, File}; use std::io::Write; use std::io::{Error, ErrorKind}; use std::sync::mpsc::Sender; +use text_colorizer::*; use crate::link::Errno; use crate::link::Frame; @@ -16,7 +16,10 @@ const DAT_PAYLOAD_SIZE: usize = DAT_FRAME_SIZE - 2; /// This function sends an ACK to signal the correct reception of a DAT frame pub fn send_ack(link: &mut Link) { - let frame = Frame{proto: Protocol::DAT, data: vec![0x06]}; + let frame = Frame { + proto: Protocol::DAT, + data: vec![0x06], + }; link.send(frame); } @@ -36,13 +39,21 @@ pub fn wait_ack() { let ack = frame.data[0]; match ack { 0x06 => (), - status => println!("{}: {:?}", "Error".bold().red(), Errno::try_from(status).unwrap()), + status => println!( + "{}: {:?}", + "Error".bold().red(), + Errno::try_from(status).unwrap() + ), } link.release(); } /// This function receives data using the DAT protocol -pub fn receive(file_name: &str, size: usize, progress: Option<&Sender<(usize, usize)>>) -> std::io::Result<()> { +pub fn receive( + file_name: &str, + size: usize, + progress: Option<&Sender<(usize, usize)>>, +) -> std::io::Result<()> { let mut receive_size: usize = 0; let mut prev_block: i16 = -1; let mut file = File::create(&file_name)?; @@ -61,9 +72,11 @@ pub fn receive(file_name: &str, size: usize, progress: Option<&Sender<(usize, us // Check sanity of block number and its inverse let block_number = frame.data[0]; let inv_block_number = frame.data[1]; - if (block_number + inv_block_number != 255) || - (block_number != (prev_block + 1) as u8) { - return Err(Error::new(ErrorKind::Other, "Error in DAT protocol receive: bad block indexing!")); + if (block_number + inv_block_number != 255) || (block_number != (prev_block + 1) as u8) { + return Err(Error::new( + ErrorKind::Other, + "Error in DAT protocol receive: bad block indexing!", + )); } prev_block = block_number as i16; receive_size += frame.data.len() - 2; @@ -95,13 +108,20 @@ pub fn send(file_name: &str, size: usize, progress: Option<&Sender<(usize, usize chunk[0] = i as u8; chunk[1] = 255 - i as u8; let remaining_data: usize = size - (i - 1) * DAT_PAYLOAD_SIZE; - let chunk_size: usize = if remaining_data < DAT_PAYLOAD_SIZE {remaining_data} else {DAT_PAYLOAD_SIZE}; - let start_offset = (i-1) * DAT_PAYLOAD_SIZE; + let chunk_size: usize = if remaining_data < DAT_PAYLOAD_SIZE { + remaining_data + } else { + DAT_PAYLOAD_SIZE + }; + let start_offset = (i - 1) * DAT_PAYLOAD_SIZE; let end_offset = start_offset + chunk_size; chunk[2..chunk_size + 2].copy_from_slice(&file_content[start_offset..end_offset]); chunk.resize(chunk_size, 0); let mut link = Link::acquire(); - let frame = Frame{proto: Protocol::DAT, data: chunk}; + let frame = Frame { + proto: Protocol::DAT, + data: chunk, + }; link.send(frame); link.release(); send_size += chunk_size; diff --git a/src/flow.rs b/src/flow.rs index 438c0fb..5ecbc30 100644 --- a/src/flow.rs +++ b/src/flow.rs @@ -1,6 +1,6 @@ -use url::Url; -use std::sync::mpsc::Sender; use std::env::current_dir; +use std::sync::mpsc::Sender; +use url::Url; use crate::cat; use crate::fmp; @@ -23,8 +23,7 @@ pub fn backup(dest_path: Option, progress: Option<&Sender<(usize, usize) file_name.push_str(&radio_name); file_name.push_str("_"); file_name.push_str(&mem.to_string()); - file_name.push_str(&chrono::offset::Local::now().format("_%d%m%Y") - .to_string()); + file_name.push_str(&chrono::offset::Local::now().format("_%d%m%Y").to_string()); file_name.push_str(".bin"); match fmp::dump(i, &mem, &file_name, progress) { Err(why) => panic!("Error while storing backup on {}: {}", file_name, why), @@ -33,11 +32,16 @@ pub fn backup(dest_path: Option, progress: Option<&Sender<(usize, usize) } } -pub fn restore(mem_index: Option, src_path: Option, progress: Option<&Sender<(usize, usize)>>) { +pub fn restore( + mem_index: Option, + src_path: Option, + progress: Option<&Sender<(usize, usize)>>, +) { // Parse parameters - let mem_index = mem_index.expect("Error: memory index not found!") - .parse::() - .expect("Error: invalid memory index!"); + let mem_index = mem_index + .expect("Error: memory index not found!") + .parse::() + .expect("Error: invalid memory index!"); let src_path = src_path.expect("Error: backup file not found!"); let mem_list = fmp::meminfo(); if mem_index > mem_list.len() { diff --git a/src/fmp.rs b/src/fmp.rs index 5b1aa5d..daa76d8 100644 --- a/src/fmp.rs +++ b/src/fmp.rs @@ -3,30 +3,30 @@ use std::ffi::CStr; use std::fmt; use std::str; -use text_colorizer::*; use std::sync::mpsc::Sender; +use text_colorizer::*; +use crate::dat; use crate::link::Errno; use crate::link::Frame; use crate::link::Link; use crate::link::Protocol; -use crate::dat; /// FMP Protocol Opcodes #[derive(PartialEq, Eq, Debug)] pub enum Opcode { - ACK = 0x00, + ACK = 0x00, MEMINFO = 0x01, - DUMP = 0x02, - FLASH = 0x03, - READ = 0x04, - WRITE = 0x05, - LIST = 0x06, - MOVE = 0x07, - COPY = 0x08, - MKDIR = 0x09, - RM = 0x0a, - RESET = 0xff, + DUMP = 0x02, + FLASH = 0x03, + READ = 0x04, + WRITE = 0x05, + LIST = 0x06, + MOVE = 0x07, + COPY = 0x08, + MKDIR = 0x09, + RM = 0x0a, + RESET = 0xff, } impl TryFrom for Opcode { @@ -54,7 +54,7 @@ impl TryFrom for Opcode { #[repr(C)] #[derive(Copy, Clone)] pub struct MemInfo { - size: u32, // Size of the memory in Bytes + size: u32, // Size of the memory in Bytes flags: u8, // Flags name: [u8; 27], // Name of the memory } @@ -62,41 +62,50 @@ pub struct MemInfo { // Useful for terminal printing impl fmt::Debug for MemInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, - "{} ({}B)", - str::from_utf8(&self.name).unwrap(), - self.size) + write!( + f, + "{} ({}B)", + str::from_utf8(&self.name).unwrap(), + self.size + ) } } // Used for deriving file names impl std::fmt::Display for MemInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, - "{}_{}", - unsafe{ CStr::from_ptr(self.name.as_ptr() as *const i8).to_str() - .unwrap() - .replace(" ", "") }, - self.size) + write!( + f, + "{}_{}", + unsafe { + CStr::from_ptr(self.name.as_ptr() as *const i8) + .to_str() + .unwrap() + .replace(" ", "") + }, + self.size + ) } } impl From<&Vec> for MemInfo { fn from(v: &Vec) -> MemInfo { - unsafe{ *std::mem::transmute::<*const u8, *const MemInfo>(v.as_ptr()) } + unsafe { *std::mem::transmute::<*const u8, *const MemInfo>(v.as_ptr()) } } } /// This function sends an FMP command pub fn send_cmd(opcode: Opcode, params: Vec>) { let mut link = Link::acquire(); - let mut cmd: Vec = vec![opcode as u8, - params.len() as u8]; + let mut cmd: Vec = vec![opcode as u8, params.len() as u8]; for p in params { cmd.push(p.len() as u8); cmd.extend(p); + } + let frame = Frame { + proto: Protocol::FMP, + data: cmd, }; - let frame = Frame{proto: Protocol::FMP, data: cmd}; link.send(frame); link.release(); } @@ -116,14 +125,21 @@ pub fn wait_reply(opcode: Opcode) -> Vec> { } let rx_opcode = Opcode::try_from(frame.data[0]).expect("Opcode not implemented!"); if rx_opcode != opcode { - eprintln!("{}: mismatched opcode in FMP response!", "Error".bold().red()); - return vec![] + eprintln!( + "{}: mismatched opcode in FMP response!", + "Error".bold().red() + ); + return vec![]; } // Parse status byte let status = frame.data[1]; match status { 0 => (), - status => println!("{}: {:?}", "Error".bold().red(), Errno::try_from(status).unwrap()), + status => println!( + "{}: {:?}", + "Error".bold().red(), + Errno::try_from(status).unwrap() + ), } // Extract parameters let nparams = frame.data[2] as usize; @@ -150,14 +166,17 @@ pub fn meminfo() -> Vec { // Receive MEMINFO response let available_mem = wait_reply(Opcode::MEMINFO); // Return MEMINFO response - let mem_list = available_mem.iter() - .map(|m| MemInfo::from(m)) - .collect(); + let mem_list = available_mem.iter().map(|m| MemInfo::from(m)).collect(); mem_list } /// Dump memory device into a file -pub fn dump(mem_id: usize, mem: &MemInfo, file_name: &str, progress: Option<&Sender<(usize, usize)>>) -> std::io::Result<()> { +pub fn dump( + mem_id: usize, + mem: &MemInfo, + file_name: &str, + progress: Option<&Sender<(usize, usize)>>, +) -> std::io::Result<()> { // Send Dump FMP command then listen for incoming DAT transfer send_cmd(Opcode::DUMP, [[mem_id as u8].to_vec()].to_vec()); wait_reply(Opcode::DUMP); @@ -165,7 +184,12 @@ pub fn dump(mem_id: usize, mem: &MemInfo, file_name: &str, progress: Option<&Sen } /// Flash a given file into a particular memory device of a radio -pub fn flash(mem_id: usize, mem: &MemInfo, file_name: &str, progress: Option<&Sender<(usize, usize)>>) { +pub fn flash( + mem_id: usize, + mem: &MemInfo, + file_name: &str, + progress: Option<&Sender<(usize, usize)>>, +) { // Send Fump FMP command then send content over DAT send_cmd(Opcode::FLASH, [[mem_id as u8].to_vec()].to_vec()); wait_reply(Opcode::FLASH); diff --git a/src/link.rs b/src/link.rs index da49351..f3b30c1 100644 --- a/src/link.rs +++ b/src/link.rs @@ -9,7 +9,7 @@ | END | ProtoID | Data | CRC8 | END | ``` -Following the leading END marker, the first byte of each frame is a protocol identifier describing the frame content, while the last byte of the frame contains the CRC-8 of the protocol ID and data fields. The polynomial used for the CRC is 0xA6, ensuring a minimum hamming distance of 2 for data blocks composed by more than 2048 bytes. +Following the leading END marker, the first byte of each frame is a protocol identifier describing the frame content, while the last byte of the frame contains the CRC-8 of the protocol ID and data fields. The polynomial used for the CRC is 0xA6, ensuring a minimum hamming distance of 2 for data blocks composed by more than 2048 bytes. The recognized protocol IDs are the following: @@ -25,11 +25,11 @@ The recognized protocol IDs are the following: use crc16::*; use serialport::SerialPort; -use std::convert::TryFrom; use std::collections::VecDeque; -use std::time::Duration; +use std::convert::TryFrom; use std::io; use std::mem::replace; +use std::time::Duration; use crate::slip; @@ -38,15 +38,15 @@ pub enum Protocol { STDIO = 0x00, CAT = 0x01, FMP = 0x02, - DAT = 0x03 + DAT = 0x03, } /// POSIX Errors #[derive(Debug)] pub enum Errno { - OK = 0, // Success - E2BIG = 7, // Argument list too long - EBADR = 53, // Invalid request descriptor + OK = 0, // Success + E2BIG = 7, // Argument list too long + EBADR = 53, // Invalid request descriptor EBADRQC = 56, // Invalid request code EGENERIC = 255, // Generic error } @@ -103,7 +103,7 @@ impl Frame { } pub struct Link { - port: Option>, + port: Option>, } impl Link { @@ -113,17 +113,17 @@ impl Link { unsafe { assert!(!LINK.port.is_some(), "Serial port created more than once!"); let serial_port = serialport::new(port, 115_200) - .timeout(Duration::from_millis(2000)) - .open()?; - LINK = Link{port: Some(serial_port)}; + .timeout(Duration::from_millis(2000)) + .open()?; + LINK = Link { + port: Some(serial_port), + }; Ok(()) } } pub fn acquire() -> Link { - unsafe { - replace(&mut LINK, Link { port: None }) - } + unsafe { replace(&mut LINK, Link { port: None }) } } pub fn release(self) { @@ -141,7 +141,11 @@ impl Link { let encoded: Vec = slip::encode(&bin_frame); // Send frame down the serial port // println!("Tx: {:x?}", encoded); - self.port.as_mut().unwrap().write_all(encoded.as_slice()).expect("Error in sending frame"); + self.port + .as_mut() + .unwrap() + .write_all(encoded.as_slice()) + .expect("Error in sending frame"); } /// This function listens on the serial line for a frame, unwraps it, @@ -151,7 +155,12 @@ impl Link { let mut decode_buffer = VecDeque::::new(); let frames: Vec> = loop { let mut receive_buffer: Vec = vec![0; 1024]; - let nread = self.port.as_mut().unwrap().read(&mut receive_buffer).expect("Error during serial rx"); + let nread = self + .port + .as_mut() + .unwrap() + .read(&mut receive_buffer) + .expect("Error during serial rx"); for i in 0..nread { decode_buffer.push_back(receive_buffer[i]); } @@ -161,7 +170,7 @@ impl Link { let frames = slip::decode_frames(&mut decode_buffer).expect("Error in SLIP decode"); // println!("Rx Frames: {:x?}", frames); if frames.len() > 0 { - break frames + break frames; } }; @@ -174,7 +183,10 @@ impl Link { let proto = Protocol::try_from(frames[0][0]).expect("Protocol not implemented!"); // Trim proto (1 byte at beginning) and CRC (1 byte at end) let data = &frames[0][1..frames[0].len() - 2]; - let frame = Frame {proto: proto, data: Vec::from(data)}; + let frame = Frame { + proto: proto, + data: Vec::from(data), + }; Ok(frame) } } diff --git a/src/main.rs b/src/main.rs index 9f18dc2..d18f518 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use std::env; use std::process; -use text_colorizer::*; use std::sync::mpsc::channel; +use text_colorizer::*; mod cat; mod dat; @@ -35,7 +35,7 @@ fn print_info() { for mem in mem_list { println!("[{}]: {:?}", i, mem); i += 1; - }; + } } fn cli_backup(port: String) { @@ -84,7 +84,9 @@ fn main() { let args: Vec = env::args().collect(); // Print usage information - if args.len() < 3 { print_usage(&args[0]); } + if args.len() < 3 { + print_usage(&args[0]); + } let serial_port = &args[1]; let command = &args[2]; @@ -92,9 +94,18 @@ fn main() { let data_1 = env::args().nth(4); match &command as &str { - "info" => { link::Link::new(serial_port).expect("Error in opening serial port!"); print_info() }, - "freqrx" => { link::Link::new(serial_port).expect("Error in opening serial port!"); cat::freq(data_0, false) }, - "freqtx" => { link::Link::new(serial_port).expect("Error in opening serial port!"); cat::freq(data_0, true) }, + "info" => { + link::Link::new(serial_port).expect("Error in opening serial port!"); + print_info() + } + "freqrx" => { + link::Link::new(serial_port).expect("Error in opening serial port!"); + cat::freq(data_0, false) + } + "freqtx" => { + link::Link::new(serial_port).expect("Error in opening serial port!"); + cat::freq(data_0, true) + } "backup" => cli_backup(serial_port.clone()), "restore" => cli_restore(serial_port.clone(), data_0, data_1), _ => print_usage(&args[0]), diff --git a/src/slip.rs b/src/slip.rs index fef6802..35dcb90 100644 --- a/src/slip.rs +++ b/src/slip.rs @@ -22,7 +22,6 @@ pub fn encode(data: &[u8]) -> Vec { } _ => encoded_data.push(*byte), } - } encoded_data.push(END); @@ -66,11 +65,14 @@ pub fn decode_frames(data: &mut VecDeque) -> Result>> { } x => { if escaped { - return Err(Error::new(ErrorKind::InvalidData, "Invalid SLIP escape sequence")); + return Err(Error::new( + ErrorKind::InvalidData, + "Invalid SLIP escape sequence", + )); } if in_packet { packet.push(x); - } + } } } } diff --git a/src/tests.rs b/src/tests.rs index 6d23f43..3a48847 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,7 +1,5 @@ #[cfg(test)] - //use super::*; - #[test] fn example() { assert_eq!(1, 1);