use crate::RecordIterator; use std::io::{BufRead, BufReader, Error, ErrorKind::InvalidData, Result, Write}; use std::net::{TcpStream, ToSocketAddrs}; #[derive(Debug)] pub struct R701 { tcp_stream: TcpStream, sequence_number: u16, } impl R701 { pub fn connect(connection_info: impl ToSocketAddrs) -> Result { // Create a new R701 struct let mut new = Self { tcp_stream: TcpStream::connect(connection_info)?, sequence_number: 0, }; // Try to ping the endpoint new.ping()?; Ok(new) } pub fn request(&mut self, payload: &[u8; 12]) -> Result> { // Create a blank request let mut request = [0x55, 0xaa, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // Insert the payload request[2..14].clone_from_slice(payload); // Insert the sequence number request[14..].clone_from_slice(&self.sequence_number.to_le_bytes()); self.sequence_number += 1; // Send the request self.tcp_stream.write_all(&request)?; // Create a buffer and return the response let mut buffer = BufReader::new(&self.tcp_stream); Ok(buffer.fill_buf()?.to_vec()) } pub fn ping(&mut self) -> Result<()> { // Create a request with a payload of `01 80 00 00 00 00 00 00 00 00 00 // 00` and get the response let response = self.request(&[0x01, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])?; // If the response is not `aa 55 01 01 00 00 00 00 00 00` then return an // error if response != [0xaa, 0x55, 0x01, 0x01, 0, 0, 0, 0, 0, 0] { return Err(Error::new(InvalidData, "Malformed response")); } Ok(()) } pub fn get_name(&mut self, id: u32) -> Result> { // Create a request with a payload of `01 c7 xx xx xx xx 00 00 00 00 14 // 00`, where `xx xx xx xx` is the employee ID in little endian let mut request = [0x01, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0x14, 0]; request[2..6].clone_from_slice(&id.to_le_bytes()); // Get the response let response = self.request(&request)?; // If the response length is right but the header is `01 00 00 00 00 00 // 00 00` then the request is been succesful but the name was not found if response.len() == 34 && response[..12] == [0xaa, 0x55, 0x01, 0, 0, 0, 0, 0, 0, 0, 0x55, 0xaa] { return Ok(None); } // If one between the response length or the response header is wrong // return an error if response.len() != 34 || response[..12] != [0xaa, 0x55, 0x01, 0x01, 0, 0, 0, 0, 0, 0, 0x55, 0xaa] { return Err(Error::new(InvalidData, "Malformed response")); } // Get the name as a UTF-8 string and delete the `\0` at the end let name = String::from_utf8_lossy(&response[12..22]) .trim_end_matches('\0') .to_string(); // Return None if the name is empty, else return the name wrapped into a // Some Ok(Some(name).filter(|name| !name.is_empty())) } pub fn get_total_record_count(&mut self) -> Result { // Create a request with a payload of `01 b4 08 00 00 00 00 00 ff ff 00 // 00` and get the response let response = self.request(&[0x01, 0xb4, 0x08, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0])?; // If one between the response length or the response header is wrong // return an error if response.len() != 10 || response[..4] != [0xaa, 0x55, 0x01, 0x01] || response[6..] != [0u8; 4] { return Err(Error::new(InvalidData, "Malformed response")); } // Convert the payload into a u16 and return it let mut record_count_le = [0u8; 2]; record_count_le.clone_from_slice(&response[4..6]); Ok(u16::from_le_bytes(record_count_le)) } pub fn get_record_bytes( &mut self, total_records: u16, sequence_number: u16, ) -> Result> { // Create a request with a payload of `01 a4 00 00 00 00 xx xx xx xx 00 // 04`, where `xx xx xx xx` changes meaning based on the sequence_number // value let mut request: [u8; 12] = [0x01, 0xa4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x04]; // If sequence_number is 0 then `xx xx xx xx` is `xx xx 00 00`, where // `xx xx` is total_records in little endian // // Else `xx xx xx xx` is `00 00 xx xx`, where `xx xx` is sequence_number // in little endian if sequence_number == 0 { request[6..8].clone_from_slice(&total_records.to_le_bytes()); } else { request[8..10].clone_from_slice(&sequence_number.to_le_bytes()); } // Get the response let response = self.request(&request)?; // If one between the response length, the response header or the last // two bits is wrong return an error if response.len() != 1038 || response[..12] != [0xaa, 0x55, 0x01, 0x01, 0, 0, 0, 0, 0, 0, 0x55, 0xaa] || response[1036..] != [0, 0] { return Err(Error::new(InvalidData, "Malformed response")); } // Return only the payload bits as a vector Ok(response[12..1036].to_vec()) } pub fn into_record_iter(&mut self) -> Result { RecordIterator::from(self) } }