Started restructuring commands.rs, updated cross_usb to 0.3.0

This commit is contained in:
G2-Games 2024-03-24 07:08:29 -05:00
parent c292b4b533
commit 4151a4f5c0
5 changed files with 129 additions and 109 deletions

View file

@ -28,7 +28,7 @@ once_cell = "1.18.0"
unicode-normalization = "0.1.22" unicode-normalization = "0.1.22"
regex = "1.10.2" regex = "1.10.2"
lazy_static = "1.4.0" lazy_static = "1.4.0"
cross_usb = "0.2" cross_usb = "0.3"
num-derive = "0.3.3" num-derive = "0.3.3"
num-traits = "0.2.14" num-traits = "0.2.14"
rand = "0.8.5" rand = "0.8.5"

View file

@ -1,5 +1,5 @@
/// A crate for controlling NetMD and Hi-MD devices. /// A crate for controlling NetMD and Hi-MD devices.
/// ///
/// To use this library, first you need to get a device from [cross-usb] and then open a [netmd::interface::NetMDInterface] /// To use this library, first you need to get a device from [cross-usb] and then open [netmd::interface::NetMDInterface]
pub mod netmd; pub mod netmd;

View file

@ -6,8 +6,9 @@ use once_cell::sync::Lazy;
use thiserror::Error; use thiserror::Error;
// USB stuff // USB stuff
use cross_usb::usb::{ControlIn, ControlOut, ControlType, Device, Interface, Recipient, UsbError}; use cross_usb::prelude::*;
use cross_usb::{UsbDevice, UsbInterface}; use cross_usb::usb::{ControlIn, ControlOut, ControlType, Recipient, UsbError};
use cross_usb::{Interface, Descriptor};
use super::utils::cross_sleep; use super::utils::cross_sleep;
@ -116,7 +117,7 @@ pub enum NetMDError {
/// A USB connection to a NetMD device /// A USB connection to a NetMD device
pub struct NetMD { pub struct NetMD {
usb_interface: UsbInterface, usb_interface: Interface,
model: DeviceId, model: DeviceId,
} }
@ -124,10 +125,10 @@ impl NetMD {
const READ_REPLY_RETRY_INTERVAL: u32 = 10; const READ_REPLY_RETRY_INTERVAL: u32 = 10;
/// Creates a new interface to a NetMD device /// Creates a new interface to a NetMD device
pub async fn new(usb_device: &UsbDevice) -> Result<Self, NetMDError> { pub async fn new(usb_descriptor: Descriptor) -> Result<Self, NetMDError> {
let mut model = DeviceId { let mut model = DeviceId {
vendor_id: usb_device.vendor_id().await, vendor_id: usb_descriptor.vendor_id().await,
product_id: usb_device.product_id().await, product_id: usb_descriptor.product_id().await,
name: None, name: None,
}; };
@ -145,6 +146,7 @@ impl NetMD {
Some(_) => (), Some(_) => (),
} }
let usb_device = usb_descriptor.open().await?;
let usb_interface = usb_device.open_interface(0).await?; let usb_interface = usb_device.open_interface(0).await?;
Ok(Self { Ok(Self {

View file

@ -3,11 +3,12 @@ use num_derive::FromPrimitive;
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use std::error::Error; use std::error::Error;
use std::time::Duration; use std::time::Duration;
use cross_usb::Descriptor;
use super::interface::{MDSession, MDTrack, NetMDInterface}; use super::interface::{MDSession, MDTrack, NetMDInterface, Direction, InterfaceError};
use super::utils::cross_sleep; use super::utils::cross_sleep;
#[derive(FromPrimitive, PartialEq)] #[derive(FromPrimitive, PartialEq, Eq)]
pub enum OperatingStatus { pub enum OperatingStatus {
Ready = 50687, Ready = 50687,
Playing = 50037, Playing = 50037,
@ -33,71 +34,102 @@ pub struct DeviceStatus {
pub time: Time, pub time: Time,
} }
pub async fn device_status(interface: &mut NetMDInterface) -> Result<DeviceStatus, Box<dyn Error>> { pub struct NetMDContext {
let status = interface.status().await?; interface: NetMDInterface,
let playback_status = interface.playback_status2().await?; }
let b1: u16 = playback_status[4] as u16;
let b2: u16 = playback_status[5] as u16;
let position = interface.position().await?;
let operating_status = b1 << 8 | b2;
let track = position[0] as u8; impl NetMDContext {
let disc_present = status[4] != 0x80; /// Create a new context to control a NetMD device
let mut state: Option<OperatingStatus> = FromPrimitive::from_u16(operating_status); pub async fn new(device: Descriptor) -> Result<Self, InterfaceError> {
let interface = NetMDInterface::new(device).await?;
if state == Some(OperatingStatus::Playing) && !disc_present { Ok(Self {
state = Some(OperatingStatus::Ready); interface,
})
} }
let time = Time { /// Change to the next track (skip forward)
minute: position[2], pub async fn next_track(&mut self) -> Result<(), InterfaceError> {
second: position[3], self.interface.track_change(Direction::Next).await
frame: position[4],
};
Ok(DeviceStatus {
disc_present,
state,
track,
time,
})
}
pub async fn prepare_download(interface: &mut NetMDInterface) -> Result<(), Box<dyn Error>> {
while ![OperatingStatus::DiscBlank, OperatingStatus::Ready].contains(
&device_status(interface)
.await?
.state
.unwrap_or(OperatingStatus::NoDisc),
) {
cross_sleep(Duration::from_millis(200)).await;
} }
let _ = interface.session_key_forget().await; /// Change to the next track (skip back)
let _ = interface.leave_secure_session().await; pub async fn previous_track(&mut self) -> Result<(), InterfaceError> {
self.interface.track_change(Direction::Previous).await
}
interface.acquire().await?; /// Change to the next track (skip to beginning of track)
let _ = interface.disable_new_track_protection(1).await; pub async fn restart_track(&mut self) -> Result<(), InterfaceError> {
self.interface.track_change(Direction::Restart).await
}
Ok(()) pub async fn device_status(&mut self) -> Result<DeviceStatus, Box<dyn Error>> {
} let status = self.interface.status().await?;
let playback_status = self.interface.playback_status2().await?;
pub async fn download<F>( let b1: u16 = playback_status[4] as u16;
interface: &mut NetMDInterface, let b2: u16 = playback_status[5] as u16;
track: MDTrack, let position = self.interface.position().await?;
progress_callback: F, let operating_status = b1 << 8 | b2;
) -> Result<(u16, Vec<u8>, Vec<u8>), Box<dyn Error>>
where let track = position[0] as u8;
F: Fn(usize, usize), let disc_present = status[4] != 0x80;
{ let mut state: Option<OperatingStatus> = FromPrimitive::from_u16(operating_status);
prepare_download(interface).await?;
let mut session = MDSession::new(interface); if state == Some(OperatingStatus::Playing) && !disc_present {
session.init().await?; state = Some(OperatingStatus::Ready);
let result = session }
.download_track(track, progress_callback, None)
.await?; let time = Time {
session.close().await?; minute: position[2],
interface.release().await?; second: position[3],
frame: position[4],
Ok(result) };
Ok(DeviceStatus {
disc_present,
state,
track,
time,
})
}
pub async fn prepare_download(&mut self) -> Result<(), Box<dyn Error>> {
while ![OperatingStatus::DiscBlank, OperatingStatus::Ready].contains(
&self.device_status()
.await?
.state
.unwrap_or(OperatingStatus::NoDisc),
) {
cross_sleep(Duration::from_millis(200)).await;
}
let _ = self.interface.session_key_forget().await;
let _ = self.interface.leave_secure_session().await;
self.interface.acquire().await?;
let _ = self.interface.disable_new_track_protection(1).await;
Ok(())
}
pub async fn download<F>(
&mut self,
track: MDTrack,
progress_callback: F,
) -> Result<(u16, Vec<u8>, Vec<u8>), Box<dyn Error>>
where
F: Fn(usize, usize),
{
self.prepare_download().await?;
// Lock the interface by providing it to the session
let mut session = MDSession::new(&mut self.interface);
session.init().await?;
let result = session
.download_track(track, progress_callback, None)
.await?;
session.close().await?;
self.interface.release().await?;
Ok(result)
}
} }

View file

@ -29,7 +29,7 @@ enum Action {
Rewind = 0x49, Rewind = 0x49,
} }
enum Track { pub enum Direction {
Previous = 0x0002, Previous = 0x0002,
Next = 0x8001, Next = 0x8001,
Restart = 0x0001, Restart = 0x0001,
@ -260,7 +260,7 @@ pub enum InterfaceError {
/// An interface for interacting with a NetMD device /// An interface for interacting with a NetMD device
pub struct NetMDInterface { pub struct NetMDInterface {
pub net_md_device: NetMD, pub device: NetMD,
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -269,9 +269,9 @@ impl NetMDInterface {
const INTERIM_RESPONSE_RETRY_INTERVAL: u32 = 100; const INTERIM_RESPONSE_RETRY_INTERVAL: u32 = 100;
/// Get a new interface to a NetMD device /// Get a new interface to a NetMD device
pub async fn new(device: &cross_usb::UsbDevice) -> Result<Self, InterfaceError> { pub async fn new(device: cross_usb::Descriptor) -> Result<Self, InterfaceError> {
let net_md_device = base::NetMD::new(device).await?; let device = base::NetMD::new(device).await?;
Ok(NetMDInterface { net_md_device }) Ok(NetMDInterface { device })
} }
fn construct_multibyte(&mut self, buffer: &[u8], n: u8, offset: &mut usize) -> u32 { fn construct_multibyte(&mut self, buffer: &[u8], n: u8, offset: &mut usize) -> u32 {
@ -432,7 +432,7 @@ impl NetMDInterface {
new_query.push(status_byte as u8); new_query.push(status_byte as u8);
new_query.append(query); new_query.append(query);
self.net_md_device.send_command(new_query).await?; self.device.send_command(new_query).await?;
Ok(()) Ok(())
} }
@ -442,15 +442,15 @@ impl NetMDInterface {
let mut data; let mut data;
while current_attempt < Self::MAX_INTERIM_READ_ATTEMPTS { while current_attempt < Self::MAX_INTERIM_READ_ATTEMPTS {
data = self.net_md_device.read_reply(None).await?; data = self.device.read_reply(None).await?;
let status = NetmdStatus::try_from(data[0])?; let status = NetmdStatus::try_from(data[0])?;
match status { match status {
NetmdStatus::NotImplemented => { NetmdStatus::NotImplemented => {
return Err(InterfaceError::NotImplemented(format!("{:X?}", data))) return Err(InterfaceError::NotImplemented(format!("{:02X?}", data)))
} }
NetmdStatus::Rejected => return Err(InterfaceError::Rejected(format!("{:X?}", data))), NetmdStatus::Rejected => return Err(InterfaceError::Rejected(format!("{:02X?}", data))),
NetmdStatus::Interim if !accept_interim => { NetmdStatus::Interim if !accept_interim => {
let sleep_time = Self::INTERIM_RESPONSE_RETRY_INTERVAL let sleep_time = Self::INTERIM_RESPONSE_RETRY_INTERVAL
* (u32::pow(2, current_attempt as u32) - 1); * (u32::pow(2, current_attempt as u32) - 1);
@ -466,7 +466,7 @@ impl NetMDInterface {
} }
return Ok(data); return Ok(data);
} }
_ => return Err(InterfaceError::Unknown(format!("{:X?}", data))), _ => return Err(InterfaceError::Unknown(format!("{:02X?}", data))),
} }
} }
@ -693,6 +693,7 @@ impl NetMDInterface {
let mut query = format_query("18c1 ff 6000".to_string(), vec![]).unwrap(); let mut query = format_query("18c1 ff 6000".to_string(), vec![]).unwrap();
let _reply = self.send_query(&mut query, false, false).await?; let _reply = self.send_query(&mut query, false, false).await?;
Ok(()) Ok(())
} }
@ -753,7 +754,7 @@ impl NetMDInterface {
Ok(value as u16) Ok(value as u16)
} }
async fn track_change(&mut self, direction: Track) -> Result<(), InterfaceError> { pub async fn track_change(&mut self, direction: Direction) -> Result<(), InterfaceError> {
let mut query = format_query( let mut query = format_query(
"1850 ff10 00000000 %w".to_string(), "1850 ff10 00000000 %w".to_string(),
vec![QueryValue::Number(direction as i64)], vec![QueryValue::Number(direction as i64)],
@ -767,21 +768,6 @@ impl NetMDInterface {
Ok(()) Ok(())
} }
/// Change to the next track (skip forward)
pub async fn next_track(&mut self) -> Result<(), InterfaceError> {
self.track_change(Track::Next).await
}
/// Change to the next track (skip back)
pub async fn previous_track(&mut self) -> Result<(), InterfaceError> {
self.track_change(Track::Previous).await
}
/// Change to the next track (skip to beginning of track)
pub async fn restart_track(&mut self) -> Result<(), InterfaceError> {
self.track_change(Track::Restart).await
}
/// Erase the disc entirely /// Erase the disc entirely
pub async fn erase_disc(&mut self) -> Result<(), InterfaceError> { pub async fn erase_disc(&mut self) -> Result<(), InterfaceError> {
let mut query = format_query("1840 ff 0000".to_string(), vec![]).unwrap(); let mut query = format_query("1840 ff 0000".to_string(), vec![]).unwrap();
@ -1094,7 +1080,7 @@ impl NetMDInterface {
let new_len = new_title.len(); let new_len = new_title.len();
if self.net_md_device.vendor_id() == 0x04dd { if self.device.vendor_id() == 0x04dd {
self.change_descriptor_state(&Descriptor::AudioUTOC1TD, &DescriptorAction::OpenWrite) self.change_descriptor_state(&Descriptor::AudioUTOC1TD, &DescriptorAction::OpenWrite)
.await? .await?
} else { } else {
@ -1116,7 +1102,7 @@ impl NetMDInterface {
let _ = self.send_query(&mut query, false, false).await; let _ = self.send_query(&mut query, false, false).await;
if self.net_md_device.vendor_id() == 0x04dd { if self.device.vendor_id() == 0x04dd {
self.change_descriptor_state(&Descriptor::AudioUTOC1TD, &DescriptorAction::Close) self.change_descriptor_state(&Descriptor::AudioUTOC1TD, &DescriptorAction::Close)
.await? .await?
} else { } else {
@ -1414,7 +1400,7 @@ impl NetMDInterface {
let codec = res[1].to_i64().unwrap() as u8; let codec = res[1].to_i64().unwrap() as u8;
let length = res[2].to_i64().unwrap() as usize; let length = res[2].to_i64().unwrap() as usize;
let result = self.net_md_device.read_bulk(length, 0x10000).await?; let result = self.device.read_bulk(length, 0x10000).await?;
scan_query( scan_query(
self.read_reply(false).await?, self.read_reply(false).await?,
@ -1613,7 +1599,7 @@ impl NetMDInterface {
discformat: u8, discformat: u8,
frames: u32, frames: u32,
pkt_size: u32, pkt_size: u32,
// key // iv // data // key, iv, data
mut packets: UnboundedReceiver<(Vec<u8>, Vec<u8>, Vec<u8>)>, mut packets: UnboundedReceiver<(Vec<u8>, Vec<u8>, Vec<u8>)>,
hex_session_key: &[u8], hex_session_key: &[u8],
progress_callback: F, progress_callback: F,
@ -1644,7 +1630,7 @@ impl NetMDInterface {
reply, reply,
"1800 080046 f0030103 28 00 000100 1001 %?%? 00 %*".to_string(), "1800 080046 f0030103 28 00 000100 1001 %?%? 00 %*".to_string(),
)?; )?;
self.net_md_device.poll().await?; self.device.poll().await?;
// Sharps are slow // Sharps are slow
cross_sleep(Duration::from_millis(200)).await; cross_sleep(Duration::from_millis(200)).await;
@ -1659,7 +1645,7 @@ impl NetMDInterface {
} else { } else {
data data
}; };
self.net_md_device.write_bulk(&binpack).await?; self.device.write_bulk(&binpack).await?;
_written_bytes += binpack.len(); _written_bytes += binpack.len();
packet_count += 1; packet_count += 1;
(progress_callback)(total_bytes, _written_bytes); (progress_callback)(total_bytes, _written_bytes);
@ -1670,7 +1656,7 @@ impl NetMDInterface {
} }
reply = self.read_reply(false).await?; reply = self.read_reply(false).await?;
self.net_md_device.poll().await?; self.device.poll().await?;
let res = scan_query( let res = scan_query(
reply, reply,
"1800 080046 f0030103 28 00 000100 1001 %w 00 %?%? %?%?%?%? %?%?%?%? %*".to_string(), "1800 080046 f0030103 28 00 000100 1001 %w 00 %?%? %?%?%?%? %?%?%?%? %*".to_string(),
@ -1714,13 +1700,13 @@ type TDesCbcEnc = cbc::Encryptor<des::TdesEde3>;
pub fn retailmac(key: &[u8], value: &[u8], iv: &[u8; 8]) -> Vec<u8> { pub fn retailmac(key: &[u8], value: &[u8], iv: &[u8; 8]) -> Vec<u8> {
let mut subkey_a = [0u8; 8]; let mut subkey_a = [0u8; 8];
subkey_a.clone_from_slice(&key[0..8]); subkey_a.copy_from_slice(&key[0..8]);
let mut beginning = [0u8; 8]; let mut beginning = [0u8; 8];
beginning.clone_from_slice(&value[0..8]); beginning.copy_from_slice(&value[0..8]);
let mut end = [0u8; 8]; let mut end = [0u8; 8];
end.clone_from_slice(&value[8..]); end.copy_from_slice(&value[8..]);
DesCbcEnc::new(&subkey_a.into(), iv.into()) DesCbcEnc::new(&subkey_a.into(), iv.into())
.encrypt_padded_mut::<NoPadding>(&mut beginning, 8) .encrypt_padded_mut::<NoPadding>(&mut beginning, 8)
@ -1729,8 +1715,8 @@ pub fn retailmac(key: &[u8], value: &[u8], iv: &[u8; 8]) -> Vec<u8> {
let iv2 = &beginning[beginning.len() - 8..]; let iv2 = &beginning[beginning.len() - 8..];
let mut wonky_key = [0u8; 24]; let mut wonky_key = [0u8; 24];
wonky_key[0..16].clone_from_slice(key); wonky_key[0..16].copy_from_slice(key);
wonky_key[16..].clone_from_slice(&key[0..8]); wonky_key[16..].copy_from_slice(&key[0..8]);
TDesCbcEnc::new(&wonky_key.into(), iv2.into()) TDesCbcEnc::new(&wonky_key.into(), iv2.into())
.encrypt_padded_mut::<NoPadding>(&mut end, 8) .encrypt_padded_mut::<NoPadding>(&mut end, 8)
.unwrap(); .unwrap();
@ -1753,7 +1739,7 @@ pub struct EKBData {
signature: [u8; 24], signature: [u8; 24],
} }
pub struct EKBOpenSource {} pub struct EKBOpenSource;
impl EKBOpenSource { impl EKBOpenSource {
pub fn root_key(&self) -> [u8; 16] { pub fn root_key(&self) -> [u8; 16] {
@ -1954,7 +1940,7 @@ impl<'a> MDSession<'a> {
pub fn new(md: &'a mut NetMDInterface) -> Self { pub fn new(md: &'a mut NetMDInterface) -> Self {
MDSession { MDSession {
md, md,
ekb_object: EKBOpenSource {}, ekb_object: EKBOpenSource,
hex_session_key: None, hex_session_key: None,
} }
} }