Ported code from rusb to webusb

This commit is contained in:
G2-Games 2023-10-09 08:39:50 -05:00
parent 9190a66a3c
commit cafd518f9d
5 changed files with 493 additions and 194 deletions

View file

@ -9,8 +9,9 @@ authors = ["G2 <g2@g2games.dev>"]
license = "AGPL-3.0" license = "AGPL-3.0"
[dependencies] [dependencies]
rusb = "0.9.3" hex = "0.4.3"
translit = "0.5.0" translit = "0.5.0"
webusb = "0.5.0"
[dependencies.minidisc-rs] [dependencies.minidisc-rs]
path = "minidisc-rs" path = "minidisc-rs"

View file

@ -14,10 +14,15 @@ readme = "README.md"
[dependencies] [dependencies]
diacritics = "0.2.0" diacritics = "0.2.0"
encoding_rs = "0.8.33" encoding_rs = "0.8.33"
magic-crypt = "3.1.12"
nofmt = "1.0.0" nofmt = "1.0.0"
once_cell = "1.18.0" once_cell = "1.18.0"
regex = "1.9.5" regex = "1.9.5"
rusb = "0.9.3"
unicode-jp = "0.4.0" unicode-jp = "0.4.0"
unicode-normalization = "0.1.22" unicode-normalization = "0.1.22"
hex = "0.4.3"
des = "0.8.1"
webusb = "0.5.0"
[lib]
crate-type = ["cdylib", "rlib"]

View file

@ -1,14 +1,10 @@
use nofmt; use nofmt;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use rusb::{DeviceDescriptor, DeviceHandle, Direction, GlobalContext, Recipient, RequestType}; use webusb::{UsbDevice, UsbRecipient, UsbRequestType, UsbControlTransferParameters};
use std::error::Error; use std::error::Error;
const DEFAULT_TIMEOUT: std::time::Duration = std::time::Duration::new(9999999, 0); const DEFAULT_TIMEOUT: std::time::Duration = std::time::Duration::new(9999999, 0);
const STANDARD_SEND: u8 =
rusb::request_type(Direction::Out, RequestType::Vendor, Recipient::Interface);
const STANDARD_RECV: u8 =
rusb::request_type(Direction::In, RequestType::Vendor, Recipient::Interface);
const BULK_WRITE_ENDPOINT: u8 = 0x02; const BULK_WRITE_ENDPOINT: u8 = 0x02;
const BULK_READ_ENDPOINT: u8 = 0x81; const BULK_READ_ENDPOINT: u8 = 0x81;
@ -87,7 +83,7 @@ pub struct DeviceId {
} }
pub struct NetMD { pub struct NetMD {
device_connection: DeviceHandle<GlobalContext>, device_connection: UsbDevice,
model: DeviceId, model: DeviceId,
status: Option<Status>, status: Option<Status>,
} }
@ -97,12 +93,11 @@ impl NetMD {
/// Creates a new `NetMD` struct /// Creates a new `NetMD` struct
pub fn new( pub fn new(
device: DeviceHandle<GlobalContext>, device: UsbDevice,
device_desc: DeviceDescriptor,
) -> Result<Self, Box<dyn Error>> { ) -> Result<Self, Box<dyn Error>> {
let mut model = DeviceId { let mut model = DeviceId {
vendor_id: device_desc.vendor_id(), vendor_id: device.vendor_id,
product_id: device_desc.product_id(), product_id: device.product_id,
name: None, name: None,
}; };
@ -144,37 +139,36 @@ impl NetMD {
/// Poll the device to get either the result /// Poll the device to get either the result
/// of the previous command, or the status /// of the previous command, or the status
fn poll(&self) -> Result<(u16, [u8; 4]), Box<dyn Error>> { pub fn poll(&mut self) -> Result<(u16, [u8; 4]), Box<dyn Error>> {
// Create an array to store the result of the poll let poll_result: [u8; 4] = match self.device_connection.control_transfer_in(
let mut poll_result = [0u8; 4]; UsbControlTransferParameters {
request_type: UsbRequestType::Vendor,
let _status = match self.device_connection.read_control( recipient: UsbRecipient::Interface,
STANDARD_RECV, request: 0x01,
0x01, value: 0,
0, index: 0,
0, },
&mut poll_result, 4
DEFAULT_TIMEOUT,
) { ) {
Ok(size) => size, Ok(result) => result.try_into().unwrap(),
Err(error) => return Err(error.into()), Err(error) => return Err(format!("USB error: {:?}", error).into()),
}; };
let length_bytes = [poll_result[2], poll_result[3]]; let length_bytes = [poll_result[2], poll_result[3]];
Ok((u16::from_le_bytes(length_bytes), poll_result)) Ok((u16::from_le_bytes(length_bytes), poll_result))
} }
pub fn send_command(&self, command: Vec<u8>) -> Result<(), Box<dyn Error>> { pub fn send_command(&mut self, command: Vec<u8>) -> Result<(), Box<dyn Error>> {
self._send_command(command, false) self._send_command(command, false)
} }
pub fn send_factory_command(&self, command: Vec<u8>) -> Result<(), Box<dyn Error>> { pub fn send_factory_command(&mut self, command: Vec<u8>) -> Result<(), Box<dyn Error>> {
self._send_command(command, false) self._send_command(command, true)
} }
/// Send a control message to the device /// Send a control message to the device
fn _send_command( fn _send_command(
&self, &mut self,
command: Vec<u8>, command: Vec<u8>,
use_factory_command: bool, use_factory_command: bool,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
@ -192,25 +186,27 @@ impl NetMD {
true => 0xff, true => 0xff,
}; };
match self.device_connection.write_control( match self.device_connection.control_transfer_out(
STANDARD_SEND, UsbControlTransferParameters {
request_type: UsbRequestType::Vendor,
recipient: UsbRecipient::Interface,
request, request,
0, value: 0,
0, index: 0,
&command, },
DEFAULT_TIMEOUT, &command
) { ) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(error) => Err(error.into()), Err(error) => Err(format!("USB error: {:?}", error).into()),
} }
} }
pub fn read_reply(&self, override_length: Option<i32>) -> Result<Vec<u8>, Box<dyn Error>> { pub fn read_reply(&mut self, override_length: Option<i32>) -> Result<Vec<u8>, Box<dyn Error>> {
self._read_reply(false, override_length) self._read_reply(false, override_length)
} }
pub fn read_factory_reply( pub fn read_factory_reply(
&self, &mut self,
override_length: Option<i32>, override_length: Option<i32>,
) -> Result<Vec<u8>, Box<dyn Error>> { ) -> Result<Vec<u8>, Box<dyn Error>> {
self._read_reply(true, override_length) self._read_reply(true, override_length)
@ -219,7 +215,7 @@ impl NetMD {
/// Poll to see if a message is ready, /// Poll to see if a message is ready,
/// and if so, recieve it /// and if so, recieve it
fn _read_reply( fn _read_reply(
&self, &mut self,
use_factory_command: bool, use_factory_command: bool,
override_length: Option<i32>, override_length: Option<i32>,
) -> Result<Vec<u8>, Box<dyn Error>> { ) -> Result<Vec<u8>, Box<dyn Error>> {
@ -246,31 +242,31 @@ impl NetMD {
}; };
// Create a buffer to fill with the result // Create a buffer to fill with the result
let mut buf: Vec<u8> = vec![0; length as usize]; match self.device_connection.control_transfer_in(
UsbControlTransferParameters {
match self.device_connection.read_control( request_type: UsbRequestType::Vendor,
STANDARD_RECV, recipient: UsbRecipient::Interface,
request, request,
0, value: 0,
0, index: 0,
&mut buf, },
DEFAULT_TIMEOUT, length as usize
) { ) {
Ok(_) => Ok(buf), Ok(data) => Ok(data),
Err(error) => return Err(error.into()), Err(error) => return Err(format!("USB error: {:?}", error).into()),
} }
} }
// Default chunksize should be 0x10000 // Default chunksize should be 0x10000
// TODO: Make these Async eventually // TODO: Make these Async eventually
pub fn read_bulk(&self, length: u32, chunksize: u32) -> Result<Vec<u8>, Box<dyn Error>> { pub fn read_bulk(&mut self, length: u32, chunksize: u32) -> Result<Vec<u8>, Box<dyn Error>> {
let result = self.read_bulk_to_array(length, chunksize)?; let result = self.read_bulk_to_array(length, chunksize)?;
Ok(result.to_vec()) Ok(result)
} }
pub fn read_bulk_to_array( pub fn read_bulk_to_array(
&self, &mut self,
length: u32, length: u32,
chunksize: u32, chunksize: u32,
) -> Result<Vec<u8>, Box<dyn Error>> { ) -> Result<Vec<u8>, Box<dyn Error>> {
@ -279,23 +275,31 @@ impl NetMD {
while done < length { while done < length {
let to_read = std::cmp::min(chunksize, length - done); let to_read = std::cmp::min(chunksize, length - done);
let mut buffer: Vec<u8> = vec![0; to_read as usize]; done -= to_read;
let mut buffer;
done += self.device_connection.read_bulk( buffer = match self.device_connection.transfer_in(
BULK_READ_ENDPOINT, BULK_READ_ENDPOINT,
&mut buffer, to_read as usize,
DEFAULT_TIMEOUT, ) {
)? as u32; Ok(result) => result,
Err(error) => return Err(format!("USB error: {:?}", error).into())
};
final_result.extend_from_slice(&mut buffer); final_result.extend_from_slice(&mut buffer);
} }
Ok(final_result) Ok(final_result)
} }
pub fn write_bulk(&self, data: &mut Vec<u8>) -> Result<usize, Box<dyn Error>> { pub fn write_bulk(&mut self, data: &mut Vec<u8>) -> Result<usize, Box<dyn Error>> {
let written = let written = match self.device_connection.transfer_out(
self.device_connection BULK_WRITE_ENDPOINT,
.write_bulk(BULK_WRITE_ENDPOINT, data, DEFAULT_TIMEOUT)?; data
) {
Ok(output) => output,
Err(error) => return Err(format!("USB error: {:?}", error).into())
};
Ok(written) Ok(written)
} }

View file

@ -5,9 +5,13 @@ use crate::netmd::utils::{
sanitize_full_width_title, sanitize_half_width_title, time_to_duration sanitize_full_width_title, sanitize_half_width_title, time_to_duration
}; };
use encoding_rs::*; use encoding_rs::*;
use rusb;
use std::collections::HashMap; use std::collections::HashMap;
use std::error::Error; use std::error::Error;
use magic_crypt::{MagicCrypt, SecureBit, MagicCryptTrait, new_magic_crypt};
use hex;
use std::thread::sleep;
use std::time::Duration;
use webusb;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
enum Action { enum Action {
@ -188,14 +192,13 @@ impl NetMDInterface {
const INTERIM_RESPONSE_RETRY_INTERVAL: u32 = 100; const INTERIM_RESPONSE_RETRY_INTERVAL: u32 = 100;
pub fn new( pub fn new(
device: rusb::DeviceHandle<rusb::GlobalContext>, device: webusb::UsbDevice,
descriptor: rusb::DeviceDescriptor,
) -> Result<Self, Box<dyn Error>> { ) -> Result<Self, Box<dyn Error>> {
let net_md_device = base::NetMD::new(device, descriptor).unwrap(); let net_md_device = base::NetMD::new(device).unwrap();
Ok(NetMDInterface { net_md_device }) Ok(NetMDInterface { net_md_device })
} }
fn construct_multibyte(&self, buffer: &Vec<u8>, n: u8, offset: &mut usize) -> u32 { fn construct_multibyte(&mut self, buffer: &Vec<u8>, n: u8, offset: &mut usize) -> u32 {
let mut output: u32 = 0; let mut output: u32 = 0;
for _ in 0..n as usize { for _ in 0..n as usize {
output <<= 8; output <<= 8;
@ -206,7 +209,7 @@ impl NetMDInterface {
} }
// TODO: Finish proper implementation // TODO: Finish proper implementation
fn disc_subunit_identifier(&self) -> Result<NetMDLevel, Box<dyn Error>> { fn disc_subunit_identifier(&mut self) -> Result<NetMDLevel, Box<dyn Error>> {
self.change_descriptor_state( self.change_descriptor_state(
&Descriptor::DiscSubunitIdentifier, &Descriptor::DiscSubunitIdentifier,
&DescriptorAction::OpenRead, &DescriptorAction::OpenRead,
@ -291,7 +294,7 @@ impl NetMDInterface {
} }
/* TODO: Finish implementation /* TODO: Finish implementation
fn factory(&self) -> Result<NetMDLevel, Box<dyn Error>> { fn factory(&mut self) -> Result<NetMDLevel, Box<dyn Error>> {
let device_name = self.net_md_device.device_name().expect("The device has no name"); let device_name = self.net_md_device.device_name().expect("The device has no name");
let himd = device_name.contains("MZ-RH") || device_name.contains("MZ-NH"); let himd = device_name.contains("MZ-RH") || device_name.contains("MZ-NH");
@ -302,13 +305,13 @@ impl NetMDInterface {
} }
*/ */
fn net_md_level(&self) -> Result<NetMDLevel, Box<dyn Error>> { fn net_md_level(&mut self) -> Result<NetMDLevel, Box<dyn Error>> {
let result = self.disc_subunit_identifier()?; let result = self.disc_subunit_identifier()?;
Ok(result) Ok(result)
} }
fn change_descriptor_state(&self, descriptor: &Descriptor, action: &DescriptorAction) { fn change_descriptor_state(&mut self, descriptor: &Descriptor, action: &DescriptorAction) {
let mut query = format_query("1808".to_string(), vec![]).unwrap(); let mut query = format_query("1808".to_string(), vec![]).unwrap();
query.append(&mut descriptor.get_array()); query.append(&mut descriptor.get_array());
@ -322,7 +325,7 @@ impl NetMDInterface {
/// Send a query to the NetMD player /// Send a query to the NetMD player
fn send_query( fn send_query(
&self, &mut self,
query: &mut Vec<u8>, query: &mut Vec<u8>,
test: bool, test: bool,
accept_interim: bool, accept_interim: bool,
@ -334,7 +337,7 @@ impl NetMDInterface {
Ok(result) Ok(result)
} }
fn send_command(&self, query: &mut Vec<u8>, test: bool) -> Result<(), Box<dyn Error>> { fn send_command(&mut self, query: &mut Vec<u8>, test: bool) -> Result<(), Box<dyn Error>> {
let status_byte = match test { let status_byte = match test {
true => Status::GeneralInquiry, true => Status::GeneralInquiry,
false => Status::Control, false => Status::Control,
@ -350,7 +353,7 @@ impl NetMDInterface {
Ok(()) Ok(())
} }
fn read_reply(&self, accept_interim: bool) -> Result<Vec<u8>, Box<dyn Error>> { fn read_reply(&mut self, accept_interim: bool) -> Result<Vec<u8>, Box<dyn Error>> {
let mut current_attempt = 0; let mut current_attempt = 0;
let mut data; let mut data;
@ -390,7 +393,7 @@ impl NetMDInterface {
Err("The max retries is set to 0".into()) Err("The max retries is set to 0".into())
} }
fn playback_control(&self, action: Action) -> Result<(), Box<dyn Error>> { fn playback_control(&mut self, action: Action) -> Result<(), Box<dyn Error>> {
let mut query = format_query( let mut query = format_query(
"18c3 00 %b 000000".to_string(), "18c3 00 %b 000000".to_string(),
vec![QueryValue::Number(action as i64)], vec![QueryValue::Number(action as i64)],
@ -403,24 +406,24 @@ impl NetMDInterface {
Ok(()) Ok(())
} }
pub fn play(&self) -> Result<(), Box<dyn Error>> { pub fn play(&mut self) -> Result<(), Box<dyn Error>> {
self.playback_control(Action::Play) self.playback_control(Action::Play)
} }
pub fn fast_forward(&self) -> Result<(), Box<dyn Error>> { pub fn fast_forward(&mut self) -> Result<(), Box<dyn Error>> {
self.playback_control(Action::FastForward) self.playback_control(Action::FastForward)
} }
pub fn rewind(&self) -> Result<(), Box<dyn Error>> { pub fn rewind(&mut self) -> Result<(), Box<dyn Error>> {
self.playback_control(Action::Rewind) self.playback_control(Action::Rewind)
} }
pub fn pause(&self) -> Result<(), Box<dyn Error>> { pub fn pause(&mut self) -> Result<(), Box<dyn Error>> {
self.playback_control(Action::Pause) self.playback_control(Action::Pause)
} }
//TODO: Implement fix for LAM-1 //TODO: Implement fix for LAM-1
pub fn stop(&self) -> Result<(), Box<dyn Error>> { pub fn stop(&mut self) -> Result<(), Box<dyn Error>> {
let mut query = format_query("18c5 ff 00000000".to_string(), vec![])?; let mut query = format_query("18c5 ff 00000000".to_string(), vec![])?;
let reply = self.send_query(&mut query, false, false)?; let reply = self.send_query(&mut query, false, false)?;
@ -430,7 +433,7 @@ impl NetMDInterface {
Ok(()) Ok(())
} }
fn acquire(&self) -> Result<(), Box<dyn Error>> { fn acquire(&mut self) -> Result<(), Box<dyn Error>> {
let mut query = format_query( let mut query = format_query(
"ff 010c ffff ffff ffff ffff ffff ffff".to_string(), "ff 010c ffff ffff ffff ffff ffff ffff".to_string(),
vec![], vec![],
@ -442,7 +445,7 @@ impl NetMDInterface {
Ok(()) Ok(())
} }
fn release(&self) -> Result<(), Box<dyn Error>> { fn release(&mut self) -> Result<(), Box<dyn Error>> {
let mut query = format_query( let mut query = format_query(
"ff 0100 ffff ffff ffff ffff ffff ffff".to_string(), "ff 0100 ffff ffff ffff ffff ffff ffff".to_string(),
vec![], vec![],
@ -455,7 +458,7 @@ impl NetMDInterface {
Ok(()) Ok(())
} }
pub fn status(&self) -> Result<Vec<u8>, Box<dyn Error>> { pub fn status(&mut self) -> Result<Vec<u8>, Box<dyn Error>> {
self.change_descriptor_state( self.change_descriptor_state(
&Descriptor::OperatingStatusBlock, &Descriptor::OperatingStatusBlock,
&DescriptorAction::OpenRead, &DescriptorAction::OpenRead,
@ -480,7 +483,7 @@ impl NetMDInterface {
Ok(final_array) Ok(final_array)
} }
pub fn disc_present(&self) -> Result<bool, Box<dyn Error>> { pub fn disc_present(&mut self) -> Result<bool, Box<dyn Error>> {
let status = self.status()?; let status = self.status()?;
println!("{:X?}", status); println!("{:X?}", status);
@ -488,7 +491,7 @@ impl NetMDInterface {
Ok(status[4] == 0x40) Ok(status[4] == 0x40)
} }
fn full_operating_status(&self) -> Result<(u8, u16), Box<dyn Error>> { fn full_operating_status(&mut self) -> Result<(u8, u16), Box<dyn Error>> {
// WARNING: Does not work for all devices. See https://github.com/cybercase/webminidisc/issues/21 // WARNING: Does not work for all devices. See https://github.com/cybercase/webminidisc/issues/21
self.change_descriptor_state( self.change_descriptor_state(
&Descriptor::OperatingStatusBlock, &Descriptor::OperatingStatusBlock,
@ -521,13 +524,13 @@ impl NetMDInterface {
Ok((status_mode, operating_status_number)) Ok((status_mode, operating_status_number))
} }
pub fn operating_status(&self) -> Result<u16, Box<dyn Error>> { pub fn operating_status(&mut self) -> Result<u16, Box<dyn Error>> {
let status = self.full_operating_status()?.1; let status = self.full_operating_status()?.1;
Ok(status) Ok(status)
} }
fn playback_status_query(&self, p1: u32, p2: u32) -> Result<Vec<u8>, Box<dyn Error>> { fn playback_status_query(&mut self, p1: u32, p2: u32) -> Result<Vec<u8>, Box<dyn Error>> {
self.change_descriptor_state( self.change_descriptor_state(
&Descriptor::OperatingStatusBlock, &Descriptor::OperatingStatusBlock,
&DescriptorAction::OpenRead, &DescriptorAction::OpenRead,
@ -550,15 +553,15 @@ impl NetMDInterface {
Ok(res.unwrap()[0].to_vec().unwrap()) Ok(res.unwrap()[0].to_vec().unwrap())
} }
pub fn playback_status1(&self) -> Result<Vec<u8>, Box<dyn Error>> { pub fn playback_status1(&mut self) -> Result<Vec<u8>, Box<dyn Error>> {
self.playback_status_query(0x8801, 0x8807) self.playback_status_query(0x8801, 0x8807)
} }
pub fn playback_status2(&self) -> Result<Vec<u8>, Box<dyn Error>> { pub fn playback_status2(&mut self) -> Result<Vec<u8>, Box<dyn Error>> {
self.playback_status_query(0x8802, 0x8806) self.playback_status_query(0x8802, 0x8806)
} }
pub fn position(&self) -> Result<[u16; 5], Box<dyn Error>> { pub fn position(&mut self) -> Result<[u16; 5], Box<dyn Error>> {
self.change_descriptor_state( self.change_descriptor_state(
&Descriptor::OperatingStatusBlock, &Descriptor::OperatingStatusBlock,
&DescriptorAction::OpenRead, &DescriptorAction::OpenRead,
@ -591,14 +594,14 @@ impl NetMDInterface {
Ok(final_result) Ok(final_result)
} }
pub fn eject_disc(&self) -> Result<(), Box<dyn Error>> { pub fn eject_disc(&mut self) -> Result<(), Box<dyn Error>> {
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)?; let _reply = self.send_query(&mut query, false, false)?;
Ok(()) Ok(())
} }
pub fn can_eject_disc(&self) -> Result<bool, Box<dyn Error>> { pub fn can_eject_disc(&mut self) -> Result<bool, Box<dyn Error>> {
let mut query = format_query("18c1 ff 6000".to_string(), vec![]).unwrap(); let mut query = format_query("18c1 ff 6000".to_string(), vec![]).unwrap();
match self.send_query(&mut query, true, false) { match self.send_query(&mut query, true, false) {
@ -608,7 +611,7 @@ impl NetMDInterface {
} }
/* Track control */ /* Track control */
pub fn go_to_track(&self, track_number: u16) -> Result<u16, Box<dyn Error>> { pub fn go_to_track(&mut self, track_number: u16) -> Result<u16, Box<dyn Error>> {
let mut query = format_query( let mut query = format_query(
"1850 ff010000 0000 %w".to_string(), "1850 ff010000 0000 %w".to_string(),
vec![QueryValue::Number(track_number as i64)], vec![QueryValue::Number(track_number as i64)],
@ -625,7 +628,7 @@ impl NetMDInterface {
} }
pub fn go_to_time( pub fn go_to_time(
&self, &mut self,
track_number: u16, track_number: u16,
hour: u8, hour: u8,
minute: u8, minute: u8,
@ -653,7 +656,7 @@ impl NetMDInterface {
Ok(value as u16) Ok(value as u16)
} }
fn _track_change(&self, direction: Track) -> Result<(), Box<dyn Error>> { fn _track_change(&mut self, direction: Track) -> Result<(), Box<dyn Error>> {
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)],
@ -668,22 +671,22 @@ impl NetMDInterface {
} }
/// Change to the next track (skip forward) /// Change to the next track (skip forward)
pub fn next_track(&self) -> Result<(), Box<dyn Error>> { pub fn next_track(&mut self) -> Result<(), Box<dyn Error>> {
self._track_change(Track::Next) self._track_change(Track::Next)
} }
/// Change to the next track (skip back) /// Change to the next track (skip back)
pub fn previous_track(&self) -> Result<(), Box<dyn Error>> { pub fn previous_track(&mut self) -> Result<(), Box<dyn Error>> {
self._track_change(Track::Next) self._track_change(Track::Next)
} }
/// Change to the next track (skip to beginning of track) /// Change to the next track (skip to beginning of track)
pub fn restart_track(&self) -> Result<(), Box<dyn Error>> { pub fn restart_track(&mut self) -> Result<(), Box<dyn Error>> {
self._track_change(Track::Next) self._track_change(Track::Next)
} }
/* Content access and control */ /* Content access and control */
pub fn erase_disc(&self) -> Result<(), Box<dyn Error>> { pub fn erase_disc(&mut self) -> Result<(), Box<dyn Error>> {
let mut query = format_query("1840 ff 0000".to_string(), vec![]).unwrap(); let mut query = format_query("1840 ff 0000".to_string(), vec![]).unwrap();
let reply = self.send_query(&mut query, false, false)?; let reply = self.send_query(&mut query, false, false)?;
scan_query(reply, "1840 00 0000".to_string())?; scan_query(reply, "1840 00 0000".to_string())?;
@ -692,7 +695,7 @@ impl NetMDInterface {
// TODO: Ensure this is returning the correct value, it // TODO: Ensure this is returning the correct value, it
// looks like it actually might be a 16 bit integer // looks like it actually might be a 16 bit integer
pub fn disc_flags(&self) -> Result<u8, Box<dyn Error>> { pub fn disc_flags(&mut self) -> Result<u8, Box<dyn Error>> {
self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead); self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead);
let mut query = let mut query =
format_query("1806 01101000 ff00 0001000b".to_string(), vec![]).unwrap(); format_query("1806 01101000 ff00 0001000b".to_string(), vec![]).unwrap();
@ -707,7 +710,7 @@ impl NetMDInterface {
} }
/// The number of tracks on the disc /// The number of tracks on the disc
pub fn track_count(&self) -> Result<u16, Box<dyn Error>> { pub fn track_count(&mut self) -> Result<u16, Box<dyn Error>> {
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead); self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead);
let mut query = format_query( let mut query = format_query(
@ -729,7 +732,7 @@ impl NetMDInterface {
Ok(res[0].to_i64().unwrap() as u16) Ok(res[0].to_i64().unwrap() as u16)
} }
fn _disc_title(&self, wchar: bool) -> Result<String, Box<dyn Error>> { fn _disc_title(&mut self, wchar: bool) -> Result<String, Box<dyn Error>> {
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead); self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead);
self.change_descriptor_state(&Descriptor::DiscTitleTD, &DescriptorAction::OpenRead); self.change_descriptor_state(&Descriptor::DiscTitleTD, &DescriptorAction::OpenRead);
@ -792,7 +795,7 @@ impl NetMDInterface {
} }
/// Gets the disc title /// Gets the disc title
pub fn disc_title(&self, wchar: bool) -> Result<String, Box<dyn Error>> { pub fn disc_title(&mut self, wchar: bool) -> Result<String, Box<dyn Error>> {
let mut title = self._disc_title(wchar)?; let mut title = self._disc_title(wchar)?;
let delim = match wchar { let delim = match wchar {
@ -818,9 +821,7 @@ impl NetMDInterface {
} }
/// Gets all groups on the disc /// Gets all groups on the disc
pub fn track_group_list( pub fn track_group_list(&mut self) -> Result<Vec<(Option<String>, Option<String>, Vec<u16>)>, Box<dyn Error>> {
&self,
) -> Result<Vec<(Option<String>, Option<String>, Vec<u16>)>, Box<dyn Error>> {
let raw_title = self._disc_title(false)?; let raw_title = self._disc_title(false)?;
let group_list = raw_title.split("//"); let group_list = raw_title.split("//");
let mut track_dict: HashMap<u16, (String, u16)> = HashMap::new(); let mut track_dict: HashMap<u16, (String, u16)> = HashMap::new();
@ -904,7 +905,7 @@ impl NetMDInterface {
} }
/// Gets a list of track titles from a set /// Gets a list of track titles from a set
pub fn track_titles(&self, tracks: Vec<u16>, wchar: bool) -> Result<Vec<String>, Box<dyn Error>> { pub fn track_titles(&mut self, tracks: Vec<u16>, wchar: bool) -> Result<Vec<String>, Box<dyn Error>> {
let wchar_value = match wchar { let wchar_value = match wchar {
true => 3, true => 3,
false => 2, false => 2,
@ -945,13 +946,17 @@ impl NetMDInterface {
} }
/// Gets the title of a track at an index /// Gets the title of a track at an index
pub fn track_title(&self, track: u16, wchar: bool) -> Result<String, Box<dyn Error>> { pub fn track_title(&mut self, track: u16, wchar: bool) -> Result<String, Box<dyn Error>> {
let title = self.track_titles([track].into(), wchar).unwrap()[0].clone(); let title = match self.track_titles([track].into(), wchar) {
Ok(titles) => titles[0].clone(),
Err(error) if error.to_string() == "Rejected" => String::new(),
Err(error) => return Err(error)
};
Ok(title) Ok(title)
} }
// Sets the title of the disc // Sets the title of the disc
pub fn set_disc_title(&self, title: String, wchar: bool) -> Result<(), Box<dyn Error>> { pub fn set_disc_title(&mut self, title: String, wchar: bool) -> Result<(), Box<dyn Error>> {
let current_title = self._disc_title(wchar)?; let current_title = self._disc_title(wchar)?;
if current_title == title { if current_title == title {
return Ok(()); return Ok(());
@ -1004,7 +1009,7 @@ impl NetMDInterface {
} }
/// Sets the title of a track /// Sets the title of a track
pub fn set_track_title(&self, track: u16, title: String, wchar: bool) -> Result<(), Box<dyn Error>> { pub fn set_track_title(&mut self, track: u16, title: String, wchar: bool) -> Result<(), Box<dyn Error>> {
let new_title: Vec<u8>; let new_title: Vec<u8>;
let (wchar_value, descriptor) = match wchar { let (wchar_value, descriptor) = match wchar {
true => { true => {
@ -1055,7 +1060,7 @@ impl NetMDInterface {
} }
/// Removes a track from the UTOC /// Removes a track from the UTOC
pub fn erase_track(&self, track: u16) -> Result<(), Box<dyn Error>> { pub fn erase_track(&mut self, track: u16) -> Result<(), Box<dyn Error>> {
let mut query = format_query( let mut query = format_query(
"1840 ff01 00 201001 %w".to_string(), "1840 ff01 00 201001 %w".to_string(),
vec![ vec![
@ -1069,7 +1074,7 @@ impl NetMDInterface {
} }
/// Moves a track to another position on the disc /// Moves a track to another position on the disc
pub fn move_track(&self, source: u16, dest: u16) -> Result<(), Box<dyn Error>> { pub fn move_track(&mut self, source: u16, dest: u16) -> Result<(), Box<dyn Error>> {
let mut query = format_query( let mut query = format_query(
"1843 ff00 00 201001 %w 201001 %w".to_string(), "1843 ff00 00 201001 %w 201001 %w".to_string(),
vec![ vec![
@ -1083,7 +1088,7 @@ impl NetMDInterface {
Ok(()) Ok(())
} }
fn _track_info(&self, track: u16, p1: i32, p2: i32) -> Result<Vec<u8>, Box<dyn Error>> { fn _track_info(&mut self, track: u16, p1: i32, p2: i32) -> Result<Vec<u8>, Box<dyn Error>> {
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead); self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead);
let mut query = format_query( let mut query = format_query(
@ -1104,7 +1109,7 @@ impl NetMDInterface {
} }
/// Gets the length of tracks as a `std::time::Duration` from a set /// Gets the length of tracks as a `std::time::Duration` from a set
pub fn track_lengths(&self, tracks: Vec<u16>) -> Result<Vec<std::time::Duration>, Box<dyn Error>> { pub fn track_lengths(&mut self, tracks: Vec<u16>) -> Result<Vec<std::time::Duration>, Box<dyn Error>> {
let mut times: Vec<std::time::Duration> = vec![]; let mut times: Vec<std::time::Duration> = vec![];
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead); self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead);
@ -1136,12 +1141,12 @@ impl NetMDInterface {
} }
/// Gets the length of a track as a `std::time::Duration` /// Gets the length of a track as a `std::time::Duration`
pub fn track_length(&self, track: u16) -> Result<std::time::Duration, Box<dyn Error>> { pub fn track_length(&mut self, track: u16) -> Result<std::time::Duration, Box<dyn Error>> {
Ok(self.track_lengths([track].into())?[0]) Ok(self.track_lengths([track].into())?[0])
} }
/// Gets the encoding of a track (SP, LP2, LP4) /// Gets the encoding of a track (SP, LP2, LP4)
pub fn track_encoding(&self, track_number: u16) -> Result<Encoding, Box<dyn Error>> { pub fn track_encoding(&mut self, track_number: u16) -> Result<Encoding, Box<dyn Error>> {
let raw_value = self._track_info(track_number, 0x3080, 0x0700)?; let raw_value = self._track_info(track_number, 0x3080, 0x0700)?;
let result = scan_query(raw_value, "07 0004 0110 %b %b".to_string())?; let result = scan_query(raw_value, "07 0004 0110 %b %b".to_string())?;
@ -1157,7 +1162,7 @@ impl NetMDInterface {
} }
/// Gets a track's flags /// Gets a track's flags
pub fn track_flags(&self, track: u16) -> Result<u8, Box<dyn Error>> { pub fn track_flags(&mut self, track: u16) -> Result<u8, Box<dyn Error>> {
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead); self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead);
let mut query = format_query( let mut query = format_query(
"1806 01201001 %w ff00 00010008".to_string(), "1806 01201001 %w ff00 00010008".to_string(),
@ -1175,7 +1180,7 @@ impl NetMDInterface {
} }
/// Gets the disc capacity as a `std::time::Duration` /// Gets the disc capacity as a `std::time::Duration`
pub fn disc_capacity(&self) -> Result<[std::time::Duration; 3], Box<dyn Error>> { pub fn disc_capacity(&mut self) -> Result<[std::time::Duration; 3], Box<dyn Error>> {
self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead); self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead);
let mut query = format_query( let mut query = format_query(
"1806 02101000 3080 0300 ff00 00000000".to_string(), "1806 02101000 3080 0300 ff00 00000000".to_string(),
@ -1203,7 +1208,7 @@ impl NetMDInterface {
Ok(result) Ok(result)
} }
pub fn recording_parameters(&self) -> Result<Vec<u8>, Box<dyn Error>> { pub fn recording_parameters(&mut self) -> Result<Vec<u8>, Box<dyn Error>> {
self.change_descriptor_state(&Descriptor::OperatingStatusBlock, &DescriptorAction::OpenRead); self.change_descriptor_state(&Descriptor::OperatingStatusBlock, &DescriptorAction::OpenRead);
let mut query = format_query( let mut query = format_query(
"1809 8001 0330 8801 0030 8805 0030 8807 00 ff00 00000000".to_string(), "1809 8001 0330 8801 0030 8805 0030 8807 00 ff00 00000000".to_string(),
@ -1222,7 +1227,7 @@ impl NetMDInterface {
/// Gets the bytes of a track /// Gets the bytes of a track
/// ///
/// This can only be executed on an MZ-RH1 / M200 /// This can only be executed on an MZ-RH1 / M200
pub fn save_track_to_array(&self, track: u16) -> Result<(DiscFormat, u16, Vec<u8>), Box<dyn Error>> { pub fn save_track_to_array(&mut self, track: u16) -> Result<(DiscFormat, u16, Vec<u8>), Box<dyn Error>> {
let mut query = format_query( let mut query = format_query(
"1800 080046 f003010330 ff00 1001 %w".to_string(), "1800 080046 f003010330 ff00 1001 %w".to_string(),
vec![ vec![
@ -1254,4 +1259,332 @@ impl NetMDInterface {
Ok((format, frames, result)) Ok((format, frames, result))
} }
pub fn disable_new_track_protection(&mut self, val: u16) -> Result<(), Box<dyn Error>> {
let mut query = format_query(
"1800 080046 f0030103 2b ff %w".to_string(),
vec![
QueryValue::Number(val as i64)
],
)?;
let reply = self.send_query(&mut query, false, false)?;
scan_query(reply, "1800 080046 f0030103 2b 00 %?%?".to_string())?;
Ok(())
}
pub fn enter_secure_session(&mut self) -> Result<(), Box<dyn Error>> {
let mut query = format_query(
"1800 080046 f0030103 80 ff".to_string(),
vec![],
)?;
let reply = self.send_query(&mut query, false, false)?;
scan_query(reply, "1800 080046 f0030103 80 00".to_string())?;
Ok(())
}
pub fn leave_secure_session(&mut self) -> Result<(), Box<dyn Error>> {
let mut query = format_query(
"1800 080046 f0030103 81 ff".to_string(),
vec![],
)?;
let reply = self.send_query(&mut query, false, false)?;
scan_query(reply, "1800 080046 f0030103 81 00".to_string())?;
Ok(())
}
/**
Read the leaf ID of the present NetMD device. The leaf ID tells
which keys the device posesses, which is needed to find out which
parts of the EKB needs to be sent to the device for it to decrypt
the root key.
The leaf ID is a 8-byte constant
**/
pub fn leaf_id(&mut self) -> Result<Vec<u8>, Box<dyn Error>> {
let mut query = format_query(
"1800 080046 f0030103 11 ff".to_string(),
vec![],
)?;
let reply = self.send_query(&mut query, false, false)?;
let res = scan_query(reply, "1800 080046 f0030103 11 00 %*".to_string())?;
Ok(res[0].to_vec().unwrap())
}
pub fn send_key_data(&mut self, ekbid: i32, keychain: Vec<[u8; 16]>, depth: i32, ekbsignature: Vec<u8>) -> Result<Vec<u8>, Box<dyn Error>> {
let chainlen = keychain.len();
let databytes = 16 + 16 * chainlen + 24;
if depth < 1 || depth > 63 {
return Err("Supplied depth is invalid".into());
}
if ekbsignature.len() != 24 {
return Err("Supplied EKB signature length wrong".into());
}
let keychains = keychain.concat();
let mut query = format_query(
"1800 080046 f0030103 12 ff %w 0000 %w %d %d %d 00000000 %* %*".to_string(),
vec![
QueryValue::Number(databytes as i64),
QueryValue::Number(databytes as i64),
QueryValue::Number(chainlen as i64),
QueryValue::Number(depth as i64),
QueryValue::Number(ekbid as i64),
QueryValue::Array(keychains),
QueryValue::Array(ekbsignature),
],
)?;
let reply = self.send_query(&mut query, false, false)?;
let res = scan_query(reply, "1800 080046 f0030103 12 01 %?%? %?%?%?%?".to_string())?;
Ok(res[0].to_vec().unwrap())
}
pub fn session_key_exchange(&mut self, hostnonce: Vec<u8>) -> Result<Vec<u8>, Box<dyn Error>> {
if hostnonce.len() != 8 {
return Err("Supplied host nonce length wrong".into());
}
let mut query = format_query(
"1800 080046 f0030103 20 ff 000000 %*".to_string(),
vec![QueryValue::Array(hostnonce)],
)?;
let reply = self.send_query(&mut query, false, false)?;
let res = scan_query(reply, "1800 080046 f0030103 20 %? 000000 %#".to_string())?;
Ok(res[0].to_vec().unwrap())
}
pub fn session_key_forget(&mut self) -> Result<(), Box<dyn Error>> {
let mut query = format_query(
"1800 080046 f0030103 21 ff 000000".to_string(),
vec![],
)?;
let reply = self.send_query(&mut query, false, false)?;
let _ = scan_query(reply, "1800 080046 f0030103 21 00 000000".to_string())?;
Ok(())
}
pub fn setup_download(&mut self, contentid: Vec<u8>, keyenckey: Vec<u8>, hex_session_key: String) -> Result<(), Box<dyn Error>> {
if contentid.len() != 20 {
return Err("Supplied content ID length wrong".into());
}
if keyenckey.len() != 8 {
return Err("Supplied Key Encryption Key length wrong".into());
}
if hex_session_key.len() != 16 {
return Err("Supplied Session Key length wrong".into());
}
let message = vec![vec![1, 1, 1, 1], contentid, keyenckey].concat();
let mc = MagicCrypt::new(
hex_session_key,
SecureBit::Bit256,
None::<String>
);
let encryptedarg = mc.decrypt_bytes_to_bytes(&message)?;
let mut query = format_query(
"1800 080046 f0030103 22 ff 0000 %*".to_string(),
vec![
QueryValue::Array(encryptedarg)
],
)?;
let reply = self.send_query(&mut query, false, false)?;
scan_query(reply, "1800 080046 f0030103 22 00 0000".to_string())?;
Ok(())
}
pub fn commit_track(&mut self, track_number: u16, hex_session_key: String) -> Result<(), Box<dyn Error>> {
if hex_session_key.len() != 16 {
return Err("Supplied Session Key length wrong".into());
}
let mc = new_magic_crypt!(hex::encode(hex_session_key), 256);
let authentication = mc.encrypt_str_to_bytes(hex::encode("0000000000000000"));
let mut query = format_query(
"1800 080046 f0030103 22 ff 0000 %*".to_string(),
vec![
QueryValue::Number(track_number as i64),
QueryValue::Array(authentication)
],
)?;
let reply = self.send_query(&mut query, false, false)?;
scan_query(reply, "1800 080046 f0030103 22 00 0000".to_string())?;
Ok(())
}
pub fn send_track(&mut self,
wireformat: u8,
discformat: u8,
frames: i32,
pkt_size: u32,
// key // iv // data
packets: Vec<(Vec<u8>, Vec<u8>, Vec<u8>)>,
hex_session_key: String
) -> Result<(i64, String, String), Box<dyn Error>> {
if hex_session_key.len() != 16 {
return Err("Supplied Session Key length wrong".into());
}
// Sharps are slow
sleep(Duration::from_millis(200));
let total_bytes = pkt_size + 24; //framesizedict[wireformat] * frames + pktcount * 24;
let mut query = format_query("1800 080046 f0030103 28 ff 000100 1001 ffff 00 %b %b %d %d".to_string(),
vec![
QueryValue::Number(wireformat as i64),
QueryValue::Number(discformat as i64),
QueryValue::Number(frames as i64),
QueryValue::Number(total_bytes as i64),
]
)?;
let mut reply = self.send_query(&mut query, false, true)?;
scan_query(reply, "1800 080046 f0030103 28 00 000100 1001 %?%? 00 %*".to_string())?;
// Sharps are slow
sleep(Duration::from_millis(200));
let mut packet_count = 0;
let mut written_bytes = 0;
for (key, iv, data) in packets {
let mut binpack;
if packet_count == 0 {
let packed_length: Vec<u8> = pkt_size.to_le_bytes().to_vec();
binpack = vec![vec![0, 0, 0, 0], packed_length, key, iv, data.clone()].concat();
} else {
binpack = data.clone();
}
self.net_md_device.write_bulk(&mut binpack)?;
packet_count += 1;
written_bytes += data.len();
}
reply = self.read_reply(false)?;
self.net_md_device.poll()?;
let res = scan_query(reply, "1800 080046 f0030103 28 00 000100 1001 %w 00 %?%? %?%?%?%? %?%?%?%? %*".to_string())?;
let mc = MagicCrypt::new(
hex_session_key,
SecureBit::Bit256,
Some("0000000000000000")
);
let reply_data = String::from_utf8(mc.decrypt_bytes_to_bytes(&res[1].to_vec().unwrap())?).unwrap().chars().collect::<Vec<char>>();
let part1 = String::from_iter(reply_data.clone()[0..8].into_iter());
let part2 = String::from_iter(reply_data.clone()[12..32].into_iter());
Ok((res[0].to_i64().unwrap(), part1, part2))
}
pub fn track_uuid(&mut self, track: u16) -> Result<String, Box<dyn Error>> {
let mut query = format_query(
"1800 080046 f0030103 23 ff 1001 %w".to_string(),
vec![
QueryValue::Number(track as i64),
],
)?;
let reply = self.send_query(&mut query, false, false)?;
let res = scan_query(reply, "1800 080046 f0030103 23 00 1001 %?%? %*".to_string())?;
Ok(String::from_utf8_lossy(&res[0].to_vec().unwrap()).to_string())
}
pub fn terminate(&mut self) -> Result<(), Box<dyn Error>> {
let mut query = format_query(
"1800 080046 f0030103 2a ff00".to_string(),
vec![],
)?;
self.send_query(&mut query, false, false)?;
Ok(())
}
}
pub fn retailmac(
key: Vec<u8>,
value: Vec<u8>,
iv: Vec<u8>
) -> Result<(), Box<dyn Error>> {
let subkey_a = key[0..8].to_vec();
let beginning = value[0..value.len() - 8].to_vec();
let end = value[value.len() - 8..].to_vec();
let mc = MagicCrypt::new(
String::from_utf8(subkey_a).unwrap(),
SecureBit::Bit256,
Some(String::from_utf8(iv).unwrap())
);
let step1 = mc.encrypt_bytes_to_bytes(&beginning);
let iv2 = String::from_utf8(step1);
Ok(())
}
struct EKBOpenSource {
}
impl EKBOpenSource {
fn root_key(&mut self) -> [u8; 16] {
[
0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
0x0f, 0xed, 0xcb, 0xa9, 0x87, 0x65, 0x43, 0x21
]
}
fn ekb_id(&mut self) -> i32 {
0x26422642
}
/* What's this for?
ekb_data_for_leaf_id(): [Uint8Array[], number, Uint8Array] {
return [
[
new Uint8Array([0x25, 0x45, 0x06, 0x4d, 0xea, 0xca, 0x14, 0xf9, 0x96, 0xbd, 0xc8, 0xa4, 0x06, 0xc2, 0x2b, 0x81]),
new Uint8Array([0xfb, 0x60, 0xbd, 0xdd, 0x0d, 0xbc, 0xab, 0x84, 0x8a, 0x00, 0x5e, 0x03, 0x19, 0x4d, 0x3e, 0xda]),
],
9,
new Uint8Array([
0x8f, 0x2b, 0xc3, 0x52, 0xe8, 0x6c, 0x5e, 0xd3, 0x06, 0xdc, 0xae, 0x18,
0xd2, 0xf3, 0x8c, 0x7f, 0x89, 0xb5, 0xe1, 0x85, 0x55, 0xa1, 0x05, 0xea
])
];
}
*/
}
struct MDTrack {
title: String,
format: WireFormat,
data: Vec<u8>,
chunk_size: i32,
full_width_title: Option<String>,
}
impl MDTrack {
} }

View file

@ -2,94 +2,50 @@ use std::thread::sleep;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use minidisc_rs::netmd::interface; use minidisc_rs::netmd::interface;
use rusb; use webusb;
fn main() { fn main() {
let mut die = false; let webusb_context = webusb::Context::init().unwrap();
for device in rusb::devices().unwrap().iter() {
if die {
break;
}
let device_desc = device.device_descriptor().unwrap(); for mut device in webusb_context.devices().unwrap() {
match device.open() {
let new_device = match device.open() {
Ok(device) => device, Ok(device) => device,
Err(_) => continue, Err(_) => break,
}; };
die = true;
device.claim_interface(0).unwrap();
println!( println!(
"Connected to Bus {:03} Device {:03} VID: {:04x}, PID: {:04x}, {:?}", "Connected to {} {}; VID: {:04x}, PID: {:04x}",
device.bus_number(), device.manufacturer_name.clone().unwrap_or("".to_string()),
device.address(), device.product_name.clone().unwrap_or("".to_string()),
device_desc.vendor_id(), device.vendor_id,
device_desc.product_id(), device.product_id
new_device.read_product_string_ascii(&device_desc)
); );
// Ensure the player is a minidisc player and not some other random device // Ensure the player is a minidisc player and not some other random device
let player_controller = match interface::NetMDInterface::new(new_device, device_desc) { let mut player_controller = match interface::NetMDInterface::new(device) {
Ok(player) => player, Ok(player) => player,
Err(_) => continue Err(_) => continue
}; };
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); println!("Player Model: {}", player_controller.net_md_device.device_name().clone().unwrap());
println!(
"Player Model: {}",
player_controller.net_md_device.device_name().clone().unwrap()
);
//println!("TEST CASE: {:?}", player_controller.set_track_title(3, "初音ミクの消失".to_string(), false).unwrap());
let now = std::time::Instant::now();
println!("Disc Title: {} | {}",
player_controller.disc_title(false).unwrap_or("".to_string()),
player_controller.disc_title(true).unwrap_or("".to_string())
);
let track_count = player_controller.track_count().unwrap(); let track_count = player_controller.track_count().unwrap();
let track_titles = player_controller.track_titles((0..track_count).collect(), false).unwrap();
let now = std::time::SystemTime::now(); let track_titlesw = player_controller.track_titles((0..track_count).collect(), true).unwrap();
let times = player_controller.track_lengths((0u16..track_count).collect()).unwrap(); let track_lengths = player_controller.track_lengths((0..track_count).collect()).unwrap();
let titles_hw = player_controller.track_titles((0u16..track_count).collect(), false).unwrap(); for (i, track) in track_titles.iter().enumerate() {
let titles_fw = player_controller.track_titles((0u16..track_count).collect(), true).unwrap(); println!("Track {i} Info:\n Title: {track} | {}\n Length: {:?}",
track_titlesw[i],
/* track_lengths[i]
let now = std::time::SystemTime::now();
for i in 0..player_controller.track_count().unwrap() {
player_controller.track_length(i as u16);
player_controller.track_title(i as u16, false);
player_controller.track_title(i as u16, true);
}
println!("Individual: {}ms", now.elapsed().unwrap().as_millis());
*/
println!(
"
Tracks: {:0>2}, Length: {:0>2} minutes
Half Width Full Width
Disc Title: {: >21} {}
",
track_count,
player_controller.disc_capacity().unwrap()[0].as_secs() / 60,
player_controller.disc_title(false).unwrap(),
player_controller.disc_title(true).unwrap()
);
for i in 0..track_count {
println!(
" {: >2} │ {:0>2}:{:0>2}:{:0>2} │ {: >21} │ {}",
i + 1,
(times[i as usize].as_secs() / 60) / 60,
(times[i as usize].as_secs() / 60) % 60,
times[i as usize].as_secs() % 60,
titles_hw[i as usize],
titles_fw[i as usize]
); );
} }
println!("────┴──────────┴───────────────────────┴─────────────────────────\nFinished in: [{}ms]", now.elapsed().unwrap().as_millis()); println!("{:?}", now.elapsed());
println!("\n\n\nAttempting to get track 1");
let returned_bytes = player_controller.save_track_to_array(0);
println!("\n{:?}", returned_bytes);
} }
} }