diff --git a/Cargo.toml b/Cargo.toml index 7631bb9..4386ed8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bcd-numbers = "1.0.11" encoding_rs = "0.8.33" nofmt = "1.0.0" once_cell = "1.18.0" diff --git a/src/main.rs b/src/main.rs index 84dddcd..fff1f5d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,6 +36,11 @@ fn main() { println!("Track Count: {:?}", player_controller.track_count()); println!("Disc Title: {:?}", player_controller.disc_title(false)); + println!("TEST CASE: {:?}", player_controller.operating_status()); + + let _ = player_controller.play(); + + /* for i in 0..player_controller.track_count().unwrap() { println!( "Track {: >2}: {: >21} | {}", @@ -43,7 +48,7 @@ fn main() { player_controller.track_title(i as u16, false).unwrap(), player_controller.track_title(i as u16, true).unwrap() ); - } + }*/ /* let mut request: [u8; 19] = [0x00, 0x18, 0x06, 0x02, 0x20, 0x18, diff --git a/src/netmd/interface.rs b/src/netmd/interface.rs index 64601d4..32384a3 100644 --- a/src/netmd/interface.rs +++ b/src/netmd/interface.rs @@ -1,3 +1,4 @@ +use crate::netmd::query_utils::{format_query, scan_query}; use crate::netmd::utils; use crate::NetMD; use encoding_rs::*; @@ -383,8 +384,6 @@ impl NetMDInterface { let result = self.send_query(&mut query, false, false)?; - utils::check_result(result, &[0x18, 0xc5, 0x00, action as u8, 0x00, 0x00, 0x00])?; - Ok(()) } @@ -409,8 +408,6 @@ impl NetMDInterface { let result = self.send_query(&mut query, false, false)?; - utils::check_result(result, &[0x18, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00])?; - Ok(()) } @@ -420,13 +417,8 @@ impl NetMDInterface { 0xff, ]; let reply = self.send_query(&mut query, false, false)?; - utils::check_result( - reply, - &[ - 0xff, 0x01, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, - ], - ) + + Ok(()) } fn release(&self) -> Result<(), Box> { @@ -435,13 +427,8 @@ impl NetMDInterface { 0xff, ]; let reply = self.send_query(&mut query, false, false)?; - utils::check_result( - reply, - &[ - 0xff, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, - ], - ) + + Ok(()) } fn status(&self) -> Result, Box> { @@ -471,18 +458,26 @@ impl NetMDInterface { } fn full_operating_status(&self) -> Result<(u8, u16), Box> { + // WARNING: Does not work for all devices. See https://github.com/cybercase/webminidisc/issues/21 self.change_descriptor_state( &Descriptor::OperatingStatusBlock, &DescriptorAction::OpenRead, ); - let mut query = vec![ - 0x18, 0x09, 0x80, 0x01, 0x03, 0x30, 0x88, 0x02, 0x00, 0x30, 0x88, 0x05, 0x00, 0x30, - 0x88, 0x06, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let response = self.send_query(&mut query, false, false)?; + let mut query = format_query( + "1809 8001 0330 8802 0030 8805 0030 8806 00 ff00 00000000".to_string(), + vec![], + vec![], + ) + .unwrap(); + let reply = self.send_query(&mut query, false, false)?; - let operating_status = response[27..].to_vec(); - let status_mode = response[20]; + let result = scan_query( + reply, + "1809 8001 0330 8802 0030 8805 0030 8806 00 1000 00%?0000 00%b 8806 %x".to_string(), + )?; + + let operating_status = result[1].to_vec().unwrap(); + let status_mode = result[0].to_i64().unwrap() as u8; self.change_descriptor_state(&Descriptor::OperatingStatusBlock, &DescriptorAction::Close); @@ -490,49 +485,48 @@ impl NetMDInterface { return Err("Unparsable operating system".into()); } - let status_bytes = [operating_status[0], operating_status[1]]; - - let operating_status_number = u16::from_le_bytes(status_bytes); + let operating_status_number = + (operating_status[0] as u16) << 8 | operating_status[1] as u16; Ok((status_mode, operating_status_number)) } - fn operating_status(&self) -> Result> { + pub fn operating_status(&self) -> Result> { let status = self.full_operating_status()?.1; Ok(status) } - fn playback_status_query(&self, p1: [u8; 2], p2: [u8; 2]) -> Result, Box> { + fn playback_status_query(&self, p1: u32, p2: u32) -> Result, Box> { self.change_descriptor_state( &Descriptor::OperatingStatusBlock, &DescriptorAction::OpenRead, ); - let mut query = vec![ - 0x18, 0x09, 0x80, 0x01, 0x03, 0x30, 0x00, 0x00, 0x00, 0x30, 0x88, 0x05, 0x00, 0x30, - 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; + let mut query = format_query( + "1809 8001 0330 %w 0030 8805 0030 %w 00 ff00 00000000".to_string(), + vec![Some(p1 as i64), Some(p2 as i64)], + vec![], + ) + .unwrap(); - query[6] = p1[0]; - query[7] = p1[1]; - query[14] = p2[0]; - query[15] = p2[1]; + let reply = self.send_query(&mut query, false, false)?; - let response = self.send_query(&mut query, false, false)?; - - let playback_status = response[24..].to_vec(); + let res = scan_query( + reply, + "1809 8001 0330 %?%? %?%? %?%? %?%? %?%? %? 1000 00%?0000 %x %?".to_string(), + ); self.change_descriptor_state(&Descriptor::OperatingStatusBlock, &DescriptorAction::Close); - Ok(playback_status) + Ok(res.unwrap()[0].to_vec().unwrap()) } pub fn playback_status1(&self) -> Result, Box> { - self.playback_status_query([0x88, 0x01], [0x88, 0x07]) + self.playback_status_query(0x8801, 0x8807) } pub fn playback_status2(&self) -> Result, Box> { - self.playback_status_query([0x88, 0x02], [0x88, 0x06]) + self.playback_status_query(0x8802, 0x8806) } pub fn position(&self) -> Result<[u16; 5], Box> { @@ -541,10 +535,12 @@ impl NetMDInterface { &DescriptorAction::OpenRead, ); - let mut query = vec![ - 0x18, 0x09, 0x80, 0x01, 0x04, 0x30, 0x88, 0x02, 0x00, 0x30, 0x88, 0x05, 0x00, 0x30, - 0x00, 0x03, 0x00, 0x30, 0x00, 0x02, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; + let mut query = format_query( + "1809 8001 0430 8802 0030 8805 0030 0003 0030 0002 00 ff00 00000000".to_string(), + vec![], + vec![], + ) + .unwrap(); let reply = match self.send_query(&mut query, false, false) { Ok(result) => result, @@ -552,19 +548,14 @@ impl NetMDInterface { Err(e) => return Err(e), }; - let track_number = u16::from_be_bytes([reply[35], reply[36]]); - - let hour = utils::byte_from_bcd(reply[37])?; - let minute = utils::byte_from_bcd(reply[38])?; - let second = utils::byte_from_bcd(reply[39])?; - let frame = utils::byte_from_bcd(reply[40])?; + let result = scan_query(reply, "1809 8001 0430 %?%? %?%? %?%? %?%? %?%? %?%? %?%? %? %?00 00%?0000 000b 0002 0007 00 %w %B %B %B %B".to_string())?; let final_result = [ - track_number, - hour as u16, - minute as u16, - second as u16, - frame as u16, + result[0].to_i64().unwrap() as u16, + result[1].to_i64().unwrap() as u16, + result[2].to_i64().unwrap() as u16, + result[3].to_i64().unwrap() as u16, + result[4].to_i64().unwrap() as u16, ]; self.change_descriptor_state(&Descriptor::OperatingStatusBlock, &DescriptorAction::Close); @@ -573,13 +564,15 @@ impl NetMDInterface { } pub fn eject_disc(&self) -> Result<(), Box> { - let mut query = vec![0x18, 0xc1, 0xff, 0x60, 0x00]; + let mut query = format_query("18c1 ff 6000".to_string(), vec![], vec![]).unwrap(); + let _reply = self.send_query(&mut query, false, false)?; Ok(()) } pub fn can_eject_disc(&self) -> Result> { - let mut query = vec![0x18, 0xc1, 0xff, 0x60, 0x00]; + let mut query = format_query("18c1 ff 6000".to_string(), vec![], vec![]).unwrap(); + match self.send_query(&mut query, true, false) { Ok(_) => Ok(true), Err(error) => Err(error), @@ -587,18 +580,21 @@ impl NetMDInterface { } /* Track control */ - pub fn go_to_track(&self, track_number: u16) -> Result> { - let mut query = vec![0x18, 0x50, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0b00, 0b00]; - - let bytes = track_number.to_le_bytes(); - - query[8] = bytes[1]; - query[9] = bytes[0]; + let mut query = format_query( + "1850 ff010000 0000 %w".to_string(), + vec![Some(track_number as i64)], + vec![], + ) + .unwrap(); let reply = self.send_query(&mut query, false, false)?; - Ok(u16::from_be_bytes([reply[8], reply[9]])) + let res = scan_query(reply, "1850 00010000 0000 %w".to_string())?; + + let value = res[0].to_i64()?; + + Ok(value as u16) } pub fn go_to_time( @@ -609,34 +605,39 @@ impl NetMDInterface { second: u8, frame: u8, ) -> Result> { - let mut query = vec![ - 0x18, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0b00, 0b00, 0b00, 0b00, 0b00, 0b00, - ]; - - let bytes = track_number.to_le_bytes(); - query[8] = bytes[1]; - query[9] = bytes[0]; - - query[10] = utils::bcd_from_byte(hour)?; - query[11] = utils::bcd_from_byte(minute)?; - query[12] = utils::bcd_from_byte(second)?; - query[13] = utils::bcd_from_byte(frame)?; + let mut query = format_query( + "1850 ff000000 0000 %w %B%B%B%B".to_string(), + vec![ + Some(track_number as i64), + Some(hour as i64), + Some(minute as i64), + Some(second as i64), + Some(frame as i64), + ], + vec![], + ) + .unwrap(); let reply = self.send_query(&mut query, false, false)?; - Ok(u16::from_be_bytes([reply[8], reply[9]])) + let res = scan_query(reply, "1850 00000000 %?%? %w %B%B%B%B".to_string())?; + + let value = res[0].to_i64()?; + + Ok(value as u16) } fn _track_change(&self, direction: Track) -> Result<(), Box> { - let mut query = vec![0x18, 0x50, 0xff, 0x10, 0x00, 0x00, 0x00, 0x00, 0b00, 0b00]; + let mut query = format_query( + "1850 ff10 00000000 %w".to_string(), + vec![Some(direction as i64)], + vec![], + ) + .unwrap(); - let direction_number = direction as u16; - let direction_bytes = direction_number.to_le_bytes(); + let reply = self.send_query(&mut query, false, false)?; - query[8] = direction_bytes[1]; - query[9] = direction_bytes[0]; - - let _ = self.send_query(&mut query, false, false); + scan_query(reply, "1850 0010 00000000 %?%?".to_string())?; Ok(()) } @@ -655,42 +656,49 @@ impl NetMDInterface { /* Content access and control */ pub fn erase_disc(&self) -> Result<(), Box> { - let mut query = vec![0x18, 0x40, 0xff, 0x00, 0x00]; + let mut query = format_query("1840 ff 0000".to_string(), vec![], vec![]).unwrap(); let reply = self.send_query(&mut query, false, false)?; - utils::check_result(reply, &[0x18, 0x40, 0x00, 0x00, 0x00]) + scan_query(reply, "1840 00 0000".to_string())?; + Ok(()) } // TODO: Ensure this is returning the correct value, it // looks like it actually might be a 16 bit integer pub fn disc_flags(&self) -> Result> { self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead); - let mut query = vec![ - 0x18, 0x06, 0x01, 0x10, 0x10, 0x00, 0xff, 0x00, 0x00, 0x01, 0x00, 0x0b, - ]; + let mut query = + format_query("1806 01101000 ff00 0001000b".to_string(), vec![], vec![]).unwrap(); let reply = self.send_query(&mut query, false, false)?; - let flags = reply[12]; + let res = scan_query(reply, "1806 01101000 1000 0001000b %b".to_string()).unwrap(); + self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::Close); - Ok(flags) + Ok(res[0].to_i64().unwrap() as u8) } pub fn track_count(&self) -> Result> { self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead); - let mut query = vec![ - 0x18, 0x06, 0x02, 0x10, 0x10, 0x01, 0x30, 0x00, 0x10, 0x00, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, - ]; + let mut query = format_query( + "1806 02101001 3000 1000 ff00 00000000".to_string(), + vec![], + vec![], + ) + .unwrap(); let reply = self.send_query(&mut query, false, false)?; - let track_count = reply[24]; + let res = scan_query( + reply, + "1806 02101001 %?%? %?%? 1000 00%?0000 0006 0010000200%b".to_string(), + ) + .unwrap(); self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::Close); - Ok(track_count) + Ok(res[0].to_i64().unwrap() as u8) } fn _disc_title(&self, wchar: bool) -> Result> { @@ -705,28 +713,26 @@ impl NetMDInterface { let mut chunk = String::new(); while done < total { - let mut query = vec![ - 0x18, 0x06, 0x02, 0x20, 0x18, 0x01, 0x00, 0b00, 0x30, 0x00, 0x0a, 0x00, 0xff, 0x00, - 0b00, 0b00, 0b00, 0b00, - ]; - - query[7] = match wchar { + let wchar_value = match wchar { true => 1, false => 0, }; - let remain_bytes = remaining.to_le_bytes(); - query[14] = remain_bytes[0]; - query[15] = remain_bytes[1]; - - let done_bytes = done.to_le_bytes(); - query[16] = done_bytes[0]; - query[17] = done_bytes[1]; + let mut query = format_query( + "1806 02201801 00%b 3000 0a00 ff00 %w%w".to_string(), + vec![ + wchar_value.into(), + (remaining as i64).into(), + (done as i64).into(), + ], + vec![], + ) + .unwrap(); let reply = self.send_query(&mut query, false, false)?; if remaining == 0 { - chunksize = u16::from_le_bytes([reply[13], reply[14]]); + let res = chunksize = u16::from_le_bytes([reply[13], reply[14]]); total = u16::from_le_bytes([reply[22], reply[23]]); chunk = SHIFT_JIS.decode(&reply[25..]).0.into(); @@ -865,15 +871,18 @@ impl NetMDInterface { /// Gets the title of a track at a specified index pub fn track_title(&self, track: u16, wchar: bool) -> Result> { - let mut query = vec![ - 0x18, 0x06, 0x02, 0x20, 0x18, 0b00, 0b00, 0b00, 0x30, 0x00, 0x0a, 0x00, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x00, - ]; - query[5] = match wchar { + let wchar_value = match wchar { true => 3, false => 2, }; + let mut query = format_query( + "1806 022018%b %w 3000 0a00 ff00 00000000".to_string(), + vec![wchar_value.into(), (track as i64).into()], + vec![], + ) + .unwrap(); + let descriptor_type = match wchar { true => Descriptor::AudioUTOC4TD, false => Descriptor::AudioUTOC1TD, @@ -881,17 +890,19 @@ impl NetMDInterface { self.change_descriptor_state(&descriptor_type, &DescriptorAction::OpenRead); - let track_bytes = track.to_le_bytes(); - query[6] = track_bytes[1]; - query[7] = track_bytes[0]; - let reply = self.send_query(&mut query, false, false)?; - let array_len = u16::from_le_bytes([reply[24], reply[23]]); - let title_array = &reply[25..array_len as usize + 25]; + let res = scan_query( + reply, + "1806 022018%? %?%? %?%? %?%? 1000 00%?0000 00%?000a %x".to_string(), + ) + .unwrap(); self.change_descriptor_state(&descriptor_type, &DescriptorAction::Close); - Ok(SHIFT_JIS.decode(title_array).0.to_string()) + Ok(encoding_rs::SHIFT_JIS + .decode(&res[0].to_vec().unwrap()) + .0 + .into()) } } diff --git a/src/netmd/mod.rs b/src/netmd/mod.rs index 8e41202..e325dd5 100644 --- a/src/netmd/mod.rs +++ b/src/netmd/mod.rs @@ -1,4 +1,4 @@ pub mod base; pub mod interface; -pub mod utils; pub mod query_utils; +pub mod utils; diff --git a/src/netmd/query_utils.rs b/src/netmd/query_utils.rs index 36afe18..77f9f6f 100644 --- a/src/netmd/query_utils.rs +++ b/src/netmd/query_utils.rs @@ -1,6 +1,7 @@ +use crate::netmd::utils; +use once_cell::sync::Lazy; use std::collections::hash_map::HashMap; use std::error::Error; -use once_cell::sync::Lazy; // prettier-ignore const FORMAT_TYPE_LEN_DICT: Lazy> = Lazy::new(|| { @@ -25,16 +26,237 @@ const FORMAT_TYPE_LEN_DICT: Lazy> = Lazy::new(|| { const DEBUG: bool = false; /// Formats a query using a standard input to send to the player -pub fn format_query(format: String, args: Vec) -> Result, Box> { +pub fn format_query( + format: String, + args: Vec>, + array_args: Vec>, +) -> Result, Box> { if DEBUG { println!("SENT>>> F: {}", format); } let mut result: Vec = Vec::new(); + let mut half: Option = None; + let mut arg_stack = args.into_iter(); + let mut array_arg_stack = array_args.into_iter(); + let mut endianness_override: Option = None; - for character in format.into_bytes().into_iter() { - println!("{}", character); + let mut escaped = false; + for character in format.chars() { + if escaped { + if endianness_override.is_none() && ['<', '>'].contains(&character) { + endianness_override = Some(character); + continue; + } + escaped = false; + let value = arg_stack.next().unwrap().unwrap(); + + match character { + character if FORMAT_TYPE_LEN_DICT.contains_key(&character) => { + match character { + 'b' => result.push(value as u8), + 'w' => { + let mut value_bytes = (value as i16).to_be_bytes().to_vec(); + result.append(&mut value_bytes) + } + 'd' => { + let mut value_bytes = (value as i32).to_be_bytes().to_vec(); + result.append(&mut value_bytes) + } + 'q' => { + let mut value_bytes = value.to_be_bytes().to_vec(); + result.append(&mut value_bytes) + } + _ => (), + }; + endianness_override = None; + } + character if character == 'x' || character == 's' || character == 'z' => { + let mut array_value = array_arg_stack.next().unwrap(); + + let mut array_length = array_value.len(); + + if character == 's' { + array_length += 1; + } + + if character != 'z' { + result.push(((array_length >> 8) & 0xFF) as u8) + } + result.push((array_length & 0xFF) as u8); + result.append(&mut array_value); + if character == 's' { + result.push(0); + } + } + character if character == '*' => { + let mut array_value = array_arg_stack.next().unwrap(); + result.append(&mut array_value); + } + character if character == 'B' || character == 'W' => { + let converted = utils::int_to_bcd(value as i32); + if character == 'W' { + result.push(((converted >> 8) & 0xFF) as u8); + } + result.push((converted & 0xFF) as u8); + } + _ => return Err(format!("Unrecognized format char {}", character).into()), + } + continue; + } + if character == '%' { + escaped = true; + continue; + } + if character == ' ' { + continue; + } + if half.is_none() { + half = Some(character); + } else { + result.push( + u8::from_str_radix(&String::from_iter([half.unwrap(), character]), 16).unwrap(), + ); + half = None; + } } - Ok(Vec::new()) + Ok(result) +} + +pub enum QueryResults { + Number(i64), + Array(Vec), +} + +impl QueryResults { + pub fn to_vec(&self) -> Result, Box> { + match self { + QueryResults::Array(a) => Ok(a.to_vec()), + _ => Err("Result was a number".into()), + } + } + + pub fn to_i64(&self) -> Result> { + match self { + QueryResults::Number(a) => Ok(*a), + _ => Err("Result was a number".into()), + } + } +} + +/// Scans a result using a standard input to recieve from the player +pub fn scan_query( + query_result: Vec, + format: String, +) -> Result, Box> { + let mut result: Vec = Vec::new(); + + let initial_length = query_result.len(); + let mut input_stack = query_result.into_iter(); + let mut half: Option = None; + let mut endianness_override: Option = None; + let mut escaped = false; + + // Remove an unknown byte at the beginning + // TODO: Find out what this is + input_stack.next(); + + for character in format.chars() { + println!("{}", character); + if escaped { + if endianness_override.is_none() && ['<', '>'].contains(&character) { + endianness_override = Some(character); + continue; + } + escaped = false; + + if character == '?' { + input_stack.next(); + continue; + } + + match character { + character if FORMAT_TYPE_LEN_DICT.contains_key(&character) => { + println!("Character: {}", character); + match character { + 'b' => { + let new_value = + u8::from_be_bytes(utils::get_bytes(&mut input_stack).unwrap()); + result.push(QueryResults::Number(new_value as i64)); + } + 'w' => { + let new_value = + i16::from_be_bytes(utils::get_bytes(&mut input_stack).unwrap()); + result.push(QueryResults::Number(new_value as i64)); + } + 'd' => { + let new_value = + i32::from_be_bytes(utils::get_bytes(&mut input_stack).unwrap()); + result.push(QueryResults::Number(new_value as i64)); + } + 'q' => { + let new_value = + i64::from_be_bytes(utils::get_bytes(&mut input_stack).unwrap()); + result.push(QueryResults::Number(new_value)); + } + _ => unreachable!(), + }; + endianness_override = None; + } + character if character == 'x' || character == 's' || character == 'z' => { + let length = match character { + 'z' => input_stack.next().unwrap() as u16, + _ => u16::from_be_bytes(utils::get_bytes(&mut input_stack).unwrap()), + }; + let mut result_buffer: Vec = Vec::new(); + for _ in 0..length { + result_buffer.push(input_stack.next().unwrap()); + } + result.push(QueryResults::Array(result_buffer)) + } + character if character == '*' || character == '#' => { + let mut result_buffer: Vec = Vec::new(); + let temp_stack = input_stack.clone(); + for entry in temp_stack.take(initial_length as usize) { + result_buffer.push(entry as i64); + } + } + character if character == 'B' => { + let v = input_stack.next().unwrap(); + result.push(QueryResults::Number(utils::bcd_to_int(v as i32) as i64)); + } + character if character == 'W' => { + let v = (input_stack.next().unwrap() as i32) << 8 + | input_stack.next().unwrap() as i32; + result.push(QueryResults::Number(utils::bcd_to_int(v) as i64)); + } + _ => return Err(format!("Unrecognized format char {}", character).into()), + } + continue; + } + if character == '%' { + assert_eq!(half, None); + escaped = true; + continue; + } + if character == ' ' { + continue; + } + if half.is_none() { + half = Some(character); + } else { + let input_value = input_stack.next().unwrap(); + let format_value = + u8::from_str_radix(&String::from_iter([half.unwrap(), character]), 16).unwrap(); + if format_value != input_value { + let i = initial_length - input_stack.len() - 1; + return Err(format!("Format and input mismatch at {i}: expected {format_value:#0x}, got {input_value:#0x} (format {format})").into()); + } + half = None; + } + } + + assert_eq!(input_stack.len(), 0); + Ok(result) } diff --git a/src/netmd/utils.rs b/src/netmd/utils.rs index 512e9bf..f8b4c3c 100644 --- a/src/netmd/utils.rs +++ b/src/netmd/utils.rs @@ -1,14 +1,35 @@ use std::collections::hash_map::HashMap; use std::error::Error; -pub fn check_result(result: Vec, expected: &[u8]) -> Result<(), Box> { - match result.as_slice().eq(expected) { - true => Ok(()), - false => Err("Response was not as expected!".into()), +pub fn bcd_to_int(bcd: i32) -> i32 { + let mut original = bcd; + let mut value = 0; + let mut nibble = 0; + while original != 0 { + let nibble_value = original & 0xf; + original = original >> 4; + value += nibble_value * i32::pow(10, nibble); + nibble += 1; } + + value } -pub fn byte_from_bcd(byte: u8) -> Result> { +pub fn int_to_bcd(mut value: i32) -> i32 { + let mut bcd = 0; + let mut shift = 0; + + while value > 0 { + let digit = value % 10; + bcd |= digit << shift; + shift += 4; + value /= 10; + } + + bcd +} + +pub fn int_from_bcd(byte: u8) -> Result> { let upper = (byte & 0xF0) >> 4; let lower = byte & 0x0F; @@ -23,7 +44,7 @@ pub fn byte_from_bcd(byte: u8) -> Result> { Ok(upper * 10 + lower) } -pub fn bcd_from_byte(byte: u8) -> Result> { +pub fn bcd_from_int(byte: u8) -> Result> { let mut new_byte: u8 = 0; let upper = (byte / 10) << 4; @@ -57,3 +78,18 @@ pub fn half_width_to_full_width_range(range: &String) -> String { .map(|char| mappings.get(&char).unwrap()) .collect() } + +pub fn get_bytes( + iterator: &mut std::vec::IntoIter, +) -> Result<[u8; S], Box> { + let mut bytes = [0; S]; + + for i in 0..S { + bytes[i] = match iterator.next() { + Some(byte) => byte, + None => return Err("Could not retrieve byte from file".into()), + }; + } + + Ok(bytes) +}