mirror of
https://github.com/G2-Games/minidisc-cli.git
synced 2025-04-19 03:32:53 -05:00
Improved documentation, fixed error while retrieving track position on empty disc
This commit is contained in:
parent
dba4ba0df4
commit
3646a4ac05
7 changed files with 213 additions and 130 deletions
|
@ -50,6 +50,7 @@ g2-unicode-jp = "0.4.1"
|
||||||
thiserror = "1.0.57"
|
thiserror = "1.0.57"
|
||||||
phf = { version = "0.11.2", features = ["phf_macros", "macros"] }
|
phf = { version = "0.11.2", features = ["phf_macros", "macros"] }
|
||||||
byteorder = "1.5.0"
|
byteorder = "1.5.0"
|
||||||
|
log = "0.4.22"
|
||||||
|
|
||||||
[target.'cfg(target_family = "wasm")'.dependencies]
|
[target.'cfg(target_family = "wasm")'.dependencies]
|
||||||
gloo = { version = "0.11.0", features = ["futures", "worker"] }
|
gloo = { version = "0.11.0", features = ["futures", "worker"] }
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
//! [futures_lite](https://docs.rs/futures-lite/) with the `block_on` function.
|
//! [futures_lite](https://docs.rs/futures-lite/) with the `block_on` function.
|
||||||
//!
|
//!
|
||||||
//! To use this library, first you need to get a device from [`cross_usb`] and
|
//! To use this library, first you need to get a device from [`cross_usb`] and
|
||||||
//! then open a [`NetMDContext`].
|
//! then open a [`netmd::NetMDContext`].
|
||||||
//!
|
//!
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! # tokio_test::block_on(async {
|
//! # tokio_test::block_on(async {
|
||||||
//! use cross_usb::get_device;
|
//! use cross_usb::get_device;
|
||||||
//! use minidisc::netmd::base::DEVICE_IDS_CROSSUSB;
|
//! use minidisc::netmd::base::DEVICE_IDS_CROSSUSB;
|
||||||
//! use minidisc::NetMDContext;
|
//! use minidisc::netmd::NetMDContext;
|
||||||
//!
|
//!
|
||||||
//! // Get a device using the built-in list of descriptors for minidisc devices
|
//! // Get a device using the built-in list of descriptors for minidisc devices
|
||||||
//! let dev_descriptor = cross_usb::get_device(DEVICE_IDS_CROSSUSB.to_vec()).await
|
//! let dev_descriptor = cross_usb::get_device(DEVICE_IDS_CROSSUSB.to_vec()).await
|
||||||
|
@ -28,6 +28,3 @@
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
pub mod netmd;
|
pub mod netmd;
|
||||||
|
|
||||||
#[doc(inline)]
|
|
||||||
pub use netmd::commands::NetMDContext;
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use thiserror::Error;
|
||||||
// USB stuff
|
// USB stuff
|
||||||
use cross_usb::prelude::*;
|
use cross_usb::prelude::*;
|
||||||
use cross_usb::usb::{ControlIn, ControlOut, ControlType, Recipient, UsbError};
|
use cross_usb::usb::{ControlIn, ControlOut, ControlType, Recipient, UsbError};
|
||||||
use cross_usb::{Descriptor, Interface};
|
use cross_usb::{DeviceInfo, Interface};
|
||||||
|
|
||||||
use super::utils::cross_sleep;
|
use super::utils::cross_sleep;
|
||||||
|
|
||||||
|
@ -117,7 +117,12 @@ pub enum NetMDError {
|
||||||
UsbError(#[from] UsbError),
|
UsbError(#[from] UsbError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A USB connection to a NetMD device
|
/// A low-level USB connection to a NetMD device.
|
||||||
|
///
|
||||||
|
/// With this you can send raw commands to the device and recieve raw data.
|
||||||
|
///
|
||||||
|
/// For simple communication with a NetMD device, you most likely want the
|
||||||
|
/// higher level [`super::NetMDInterface`] or [`super::NetMDContext`] interfaces
|
||||||
pub struct NetMD {
|
pub struct NetMD {
|
||||||
usb_interface: Interface,
|
usb_interface: Interface,
|
||||||
model: DeviceId,
|
model: DeviceId,
|
||||||
|
@ -127,7 +132,7 @@ 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_descriptor: Descriptor) -> Result<Self, NetMDError> {
|
pub async fn new(usb_descriptor: DeviceInfo) -> Result<Self, NetMDError> {
|
||||||
let mut model = DeviceId {
|
let mut model = DeviceId {
|
||||||
vendor_id: usb_descriptor.vendor_id().await,
|
vendor_id: usb_descriptor.vendor_id().await,
|
||||||
product_id: usb_descriptor.product_id().await,
|
product_id: usb_descriptor.product_id().await,
|
||||||
|
@ -202,15 +207,17 @@ impl NetMD {
|
||||||
Ok((length_bytes, poll_result))
|
Ok((length_bytes, poll_result))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send a control message to the device (Raw bytes)
|
||||||
pub async fn send_command(&mut self, command: Vec<u8>) -> Result<(), NetMDError> {
|
pub async fn send_command(&mut self, command: Vec<u8>) -> Result<(), NetMDError> {
|
||||||
self._send_command(command, false).await
|
self._send_command(command, false).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send a factory control message to the device (Raw bytes)
|
||||||
pub async fn send_factory_command(&mut self, command: Vec<u8>) -> Result<(), NetMDError> {
|
pub async fn send_factory_command(&mut self, command: Vec<u8>) -> Result<(), NetMDError> {
|
||||||
self._send_command(command, true).await
|
self._send_command(command, true).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a control message to the device
|
/// Send a control message to the device, can also send factory commands
|
||||||
async fn _send_command(
|
async fn _send_command(
|
||||||
&mut self,
|
&mut self,
|
||||||
command: Vec<u8>,
|
command: Vec<u8>,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#![cfg_attr(debug_assertions, allow(dead_code))]
|
#![cfg_attr(debug_assertions, allow(dead_code))]
|
||||||
use cross_usb::Descriptor;
|
use cross_usb::DeviceInfo;
|
||||||
use num_derive::FromPrimitive;
|
use num_derive::FromPrimitive;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
@ -278,7 +278,7 @@ pub struct NetMDContext {
|
||||||
|
|
||||||
impl NetMDContext {
|
impl NetMDContext {
|
||||||
/// Create a new context to control a NetMD device
|
/// Create a new context to control a NetMD device
|
||||||
pub async fn new(device: Descriptor) -> Result<Self, InterfaceError> {
|
pub async fn new(device: DeviceInfo) -> Result<Self, InterfaceError> {
|
||||||
let interface = NetMDInterface::new(device).await?;
|
let interface = NetMDInterface::new(device).await?;
|
||||||
|
|
||||||
Ok(Self { interface })
|
Ok(Self { interface })
|
||||||
|
@ -520,7 +520,7 @@ impl NetMDContext {
|
||||||
Ok((format, header))
|
Ok((format, header))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn prepare_download(&mut self) -> Result<(), Box<dyn Error>> {
|
async fn prepare_download(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
while ![OperatingStatus::DiscBlank, OperatingStatus::Ready].contains(
|
while ![OperatingStatus::DiscBlank, OperatingStatus::Ready].contains(
|
||||||
&self
|
&self
|
||||||
.device_status()
|
.device_status()
|
||||||
|
@ -543,13 +543,49 @@ impl NetMDContext {
|
||||||
/// Start downloading an [`MDTrack`] to the device.
|
/// Start downloading an [`MDTrack`] to the device.
|
||||||
///
|
///
|
||||||
/// Progress is updated in the `progress_callback` closure.
|
/// Progress is updated in the `progress_callback` closure.
|
||||||
pub async fn download<F>(
|
///
|
||||||
|
/// # Downloading a track:
|
||||||
|
/// ```no_run
|
||||||
|
/// # tokio_test::block_on(async {
|
||||||
|
/// use minidisc::netmd::DEVICE_IDS_CROSSUSB;
|
||||||
|
/// use minidisc::netmd::NetMDContext;
|
||||||
|
/// use minidisc::netmd::encryption::new_thread_encryptor;
|
||||||
|
/// use minidisc::netmd::interface::{MDTrack, NetMDInterface};
|
||||||
|
///
|
||||||
|
/// // Get the minidisc device from cross_usb
|
||||||
|
/// let device = cross_usb::get_device(DEVICE_IDS_CROSSUSB.to_vec()).await.unwrap();
|
||||||
|
///
|
||||||
|
/// // Obtain a NetMDContext and acquire it
|
||||||
|
/// let mut context = NetMDContext::new(device).await.unwrap();
|
||||||
|
/// context.interface_mut().acquire().await.unwrap();
|
||||||
|
///
|
||||||
|
/// // Read in an audio file to a vec, for LP2 and LP4 this must be encoded properly
|
||||||
|
/// let track_contents: Vec<u8> =
|
||||||
|
/// std::fs::read("audio_file.wav")
|
||||||
|
/// .expect("Could not read track")[0x60..].to_vec();
|
||||||
|
///
|
||||||
|
/// // Construct the track
|
||||||
|
/// let track = MDTrack {
|
||||||
|
/// chunk_size: 0x400,
|
||||||
|
/// title: String::from("My Track Title"),
|
||||||
|
/// format: minidisc::netmd::interface::WireFormat::LP2,
|
||||||
|
/// full_width_title: None,
|
||||||
|
/// data: track_contents,
|
||||||
|
/// encrypt_packets_iterator: Box::new(new_thread_encryptor),
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// // Download it to the player!
|
||||||
|
/// context.download(
|
||||||
|
/// track,
|
||||||
|
/// |out_of: usize, done: usize| println!("Done {} / {}", done, out_of)
|
||||||
|
/// ).await.expect("Starting download failed");
|
||||||
|
/// # })
|
||||||
|
/// ```
|
||||||
|
pub async fn download<F: Fn(usize, usize)>(
|
||||||
&mut self,
|
&mut self,
|
||||||
track: MDTrack,
|
track: MDTrack,
|
||||||
progress_callback: F,
|
progress_callback: F,
|
||||||
) -> Result<(u16, Vec<u8>, Vec<u8>), Box<dyn Error>>
|
) -> Result<(u16, Vec<u8>, Vec<u8>), Box<dyn Error>>
|
||||||
where
|
|
||||||
F: Fn(usize, usize),
|
|
||||||
{
|
{
|
||||||
self.prepare_download().await?;
|
self.prepare_download().await?;
|
||||||
// Lock the interface by providing it to the session
|
// Lock the interface by providing it to the session
|
||||||
|
|
|
@ -8,6 +8,7 @@ use crate::netmd::utils::{
|
||||||
use cbc::cipher::block_padding::NoPadding;
|
use cbc::cipher::block_padding::NoPadding;
|
||||||
use cbc::cipher::{BlockDecryptMut, BlockEncryptMut, KeyInit, KeyIvInit};
|
use cbc::cipher::{BlockDecryptMut, BlockEncryptMut, KeyInit, KeyIvInit};
|
||||||
use encoding_rs::SHIFT_JIS;
|
use encoding_rs::SHIFT_JIS;
|
||||||
|
use log::debug;
|
||||||
use num_derive::FromPrimitive;
|
use num_derive::FromPrimitive;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -19,6 +20,7 @@ use tokio::sync::mpsc::UnboundedReceiver;
|
||||||
use super::base::NetMD;
|
use super::base::NetMD;
|
||||||
use super::utils::{cross_sleep, to_sjis};
|
use super::utils::{cross_sleep, to_sjis};
|
||||||
|
|
||||||
|
/// An action to take on the player
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
enum Action {
|
enum Action {
|
||||||
Play = 0x75,
|
Play = 0x75,
|
||||||
|
@ -27,12 +29,14 @@ enum Action {
|
||||||
Rewind = 0x49,
|
Rewind = 0x49,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Direction of playback, or restart track
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
Previous = 0x0002,
|
Previous = 0x0002,
|
||||||
Next = 0x8001,
|
Next = 0x8001,
|
||||||
Restart = 0x0001,
|
Restart = 0x0001,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The format of the disc
|
||||||
#[derive(Debug, Clone, Copy, FromPrimitive, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, FromPrimitive, PartialEq, Eq)]
|
||||||
pub enum DiscFormat {
|
pub enum DiscFormat {
|
||||||
LP4 = 0,
|
LP4 = 0,
|
||||||
|
@ -41,6 +45,7 @@ pub enum DiscFormat {
|
||||||
SPStereo = 6,
|
SPStereo = 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The format of the audio
|
||||||
#[derive(Clone, Hash, Eq, PartialEq, FromPrimitive)]
|
#[derive(Clone, Hash, Eq, PartialEq, FromPrimitive)]
|
||||||
pub enum WireFormat {
|
pub enum WireFormat {
|
||||||
Pcm = 0x00,
|
Pcm = 0x00,
|
||||||
|
@ -69,6 +74,7 @@ impl WireFormat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The encoding of the audio
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Encoding {
|
pub enum Encoding {
|
||||||
SP = 0x90,
|
SP = 0x90,
|
||||||
|
@ -86,6 +92,7 @@ impl std::fmt::Display for Encoding {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The number of channels in the audio
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Channels {
|
pub enum Channels {
|
||||||
Mono = 0x01,
|
Mono = 0x01,
|
||||||
|
@ -106,6 +113,7 @@ enum ChannelCount {
|
||||||
Stereo = 2,
|
Stereo = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The protected flag on a track
|
||||||
#[derive(Debug, Clone, Copy, FromPrimitive)]
|
#[derive(Debug, Clone, Copy, FromPrimitive)]
|
||||||
pub enum TrackFlag {
|
pub enum TrackFlag {
|
||||||
Protected = 0x03,
|
Protected = 0x03,
|
||||||
|
@ -121,11 +129,13 @@ impl std::fmt::Display for TrackFlag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The write protect flag on a disc
|
||||||
pub enum DiscFlag {
|
pub enum DiscFlag {
|
||||||
Writable = 0x10,
|
Writable = 0x10,
|
||||||
WriteProtected = 0x40,
|
WriteProtected = 0x40,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
enum NetMDLevel {
|
enum NetMDLevel {
|
||||||
Level1 = 0x20, // Network MD
|
Level1 = 0x20, // Network MD
|
||||||
|
@ -180,6 +190,7 @@ enum DescriptorAction {
|
||||||
Close = 0,
|
Close = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
enum NetmdStatus {
|
enum NetmdStatus {
|
||||||
// NetMD Protocol return status (first byte of request)
|
// NetMD Protocol return status (first byte of request)
|
||||||
|
@ -199,8 +210,8 @@ enum NetmdStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Error, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
#[error("invalid status code")]
|
#[error("invalid status code: {}", 1)]
|
||||||
pub struct StatusError;
|
pub struct StatusError(u16);
|
||||||
|
|
||||||
impl TryFrom<u8> for NetmdStatus {
|
impl TryFrom<u8> for NetmdStatus {
|
||||||
type Error = StatusError;
|
type Error = StatusError;
|
||||||
|
@ -219,7 +230,7 @@ impl TryFrom<u8> for NetmdStatus {
|
||||||
0x0c => Ok(NetmdStatus::Implemented),
|
0x0c => Ok(NetmdStatus::Implemented),
|
||||||
0x0d => Ok(NetmdStatus::Changed),
|
0x0d => Ok(NetmdStatus::Changed),
|
||||||
0x0f => Ok(NetmdStatus::Interim),
|
0x0f => Ok(NetmdStatus::Interim),
|
||||||
_ => Err(StatusError),
|
code => Err(StatusError(code as u16)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,6 +243,7 @@ struct MediaInfo {
|
||||||
supports_md_clip: u8,
|
supports_md_clip: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An error when encrypting packets
|
||||||
#[derive(Error, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Error, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum EncryptionError {
|
pub enum EncryptionError {
|
||||||
#[error("supplied depth of {0} is invalid")]
|
#[error("supplied depth of {0} is invalid")]
|
||||||
|
@ -241,6 +253,7 @@ pub enum EncryptionError {
|
||||||
InvalidLength(&'static str, usize),
|
InvalidLength(&'static str, usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An error for any action in the interface
|
||||||
#[derive(Error, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Error, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum InterfaceError {
|
pub enum InterfaceError {
|
||||||
#[error("could not parse data from a device")]
|
#[error("could not parse data from a device")]
|
||||||
|
@ -297,7 +310,7 @@ 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::Descriptor) -> Result<Self, InterfaceError> {
|
pub async fn new(device: cross_usb::DeviceInfo) -> Result<Self, InterfaceError> {
|
||||||
let device = base::NetMD::new(device).await?;
|
let device = base::NetMD::new(device).await?;
|
||||||
Ok(NetMDInterface { device })
|
Ok(NetMDInterface { device })
|
||||||
}
|
}
|
||||||
|
@ -320,9 +333,9 @@ impl NetMDInterface {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut query = format_query("1809 00 ff00 0000 0000".to_string(), vec![])?;
|
let query = format_query("1809 00 ff00 0000 0000".to_string(), vec![])?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
let res = scan_query(
|
let res = scan_query(
|
||||||
reply,
|
reply,
|
||||||
|
@ -430,7 +443,7 @@ impl NetMDInterface {
|
||||||
|
|
||||||
query.push(0x00);
|
query.push(0x00);
|
||||||
|
|
||||||
match self.send_query(&mut query, false, false).await {
|
match self.send_query(&query, false, false).await {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(err) => Err(err),
|
Err(err) => Err(err),
|
||||||
}
|
}
|
||||||
|
@ -439,7 +452,7 @@ impl NetMDInterface {
|
||||||
/// Send a query to the NetMD player
|
/// Send a query to the NetMD player
|
||||||
async fn send_query(
|
async fn send_query(
|
||||||
&mut self,
|
&mut self,
|
||||||
query: &mut Vec<u8>,
|
query: &Vec<u8>,
|
||||||
test: bool,
|
test: bool,
|
||||||
accept_interim: bool,
|
accept_interim: bool,
|
||||||
) -> Result<Vec<u8>, InterfaceError> {
|
) -> Result<Vec<u8>, InterfaceError> {
|
||||||
|
@ -452,7 +465,7 @@ impl NetMDInterface {
|
||||||
|
|
||||||
async fn send_command(
|
async fn send_command(
|
||||||
&mut self,
|
&mut self,
|
||||||
query: &mut Vec<u8>,
|
query: &Vec<u8>,
|
||||||
test: bool,
|
test: bool,
|
||||||
) -> Result<(), InterfaceError> {
|
) -> Result<(), InterfaceError> {
|
||||||
let status_byte = match test {
|
let status_byte = match test {
|
||||||
|
@ -463,7 +476,7 @@ impl NetMDInterface {
|
||||||
let mut new_query = Vec::new();
|
let mut new_query = Vec::new();
|
||||||
|
|
||||||
new_query.push(status_byte as u8);
|
new_query.push(status_byte as u8);
|
||||||
new_query.append(query);
|
new_query.extend_from_slice(&query);
|
||||||
|
|
||||||
self.device.send_command(new_query).await?;
|
self.device.send_command(new_query).await?;
|
||||||
|
|
||||||
|
@ -478,6 +491,7 @@ impl NetMDInterface {
|
||||||
data = self.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])?;
|
||||||
|
debug!("Device status: {:?}", status);
|
||||||
|
|
||||||
match status {
|
match status {
|
||||||
NetmdStatus::NotImplemented => {
|
NetmdStatus::NotImplemented => {
|
||||||
|
@ -510,12 +524,12 @@ impl NetMDInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn playback_control(&mut self, action: Action) -> Result<(), InterfaceError> {
|
async fn playback_control(&mut self, action: Action) -> Result<(), InterfaceError> {
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"18c3 ff %b 000000".to_string(),
|
"18c3 ff %b 000000".to_string(),
|
||||||
vec![QueryValue::Number(action as i64)],
|
vec![QueryValue::Number(action as i64)],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
scan_query(reply, "18c3 00 %b 000000".to_string())?;
|
scan_query(reply, "18c3 00 %b 000000".to_string())?;
|
||||||
|
|
||||||
|
@ -545,9 +559,9 @@ impl NetMDInterface {
|
||||||
//TODO: Implement fix for LAM-1
|
//TODO: Implement fix for LAM-1
|
||||||
/// Stop playback
|
/// Stop playback
|
||||||
pub async fn stop(&mut self) -> Result<(), InterfaceError> {
|
pub async fn stop(&mut self) -> Result<(), InterfaceError> {
|
||||||
let mut query = format_query("18c5 ff 00000000".to_string(), vec![])?;
|
let query = format_query("18c5 ff 00000000".to_string(), vec![])?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
scan_query(reply, "18c5 00 00000000".to_string())?;
|
scan_query(reply, "18c5 00 00000000".to_string())?;
|
||||||
|
|
||||||
|
@ -555,8 +569,8 @@ impl NetMDInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn acquire(&mut self) -> Result<(), InterfaceError> {
|
pub async fn acquire(&mut self) -> Result<(), InterfaceError> {
|
||||||
let mut query = format_query("ff 010c ffff ffff ffff ffff ffff ffff".to_string(), vec![])?;
|
let query = format_query("ff 010c ffff ffff ffff ffff ffff ffff".to_string(), vec![])?;
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
scan_query(reply, "ff 010c ffff ffff ffff ffff ffff ffff".to_string())?;
|
scan_query(reply, "ff 010c ffff ffff ffff ffff ffff ffff".to_string())?;
|
||||||
|
|
||||||
|
@ -564,9 +578,9 @@ impl NetMDInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn release(&mut self) -> Result<(), InterfaceError> {
|
pub async fn release(&mut self) -> Result<(), InterfaceError> {
|
||||||
let mut query = format_query("ff 0100 ffff ffff ffff ffff ffff ffff".to_string(), vec![])?;
|
let query = format_query("ff 0100 ffff ffff ffff ffff ffff ffff".to_string(), vec![])?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
scan_query(reply, "ff 0100 ffff ffff ffff ffff ffff ffff".to_string())?;
|
scan_query(reply, "ff 0100 ffff ffff ffff ffff ffff ffff".to_string())?;
|
||||||
|
|
||||||
|
@ -580,12 +594,12 @@ impl NetMDInterface {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1809 8001 0230 8800 0030 8804 00 ff00 00000000".to_string(),
|
"1809 8001 0230 8800 0030 8804 00 ff00 00000000".to_string(),
|
||||||
vec![],
|
vec![],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
let res = scan_query(
|
let res = scan_query(
|
||||||
reply,
|
reply,
|
||||||
|
@ -617,12 +631,12 @@ impl NetMDInterface {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1809 8001 0330 8802 0030 8805 0030 8806 00 ff00 00000000".to_string(),
|
"1809 8001 0330 8802 0030 8805 0030 8806 00 ff00 00000000".to_string(),
|
||||||
vec![],
|
vec![],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
let result = scan_query(
|
let result = scan_query(
|
||||||
reply,
|
reply,
|
||||||
|
@ -636,7 +650,9 @@ impl NetMDInterface {
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if operating_status.len() < 2 {
|
if operating_status.len() < 2 {
|
||||||
return Err(InterfaceError::InvalidStatus(StatusError));
|
if !operating_status.is_empty() {
|
||||||
|
return Err(InterfaceError::InvalidStatus(StatusError(operating_status[0] as u16)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let operating_status_number =
|
let operating_status_number =
|
||||||
|
@ -658,20 +674,23 @@ impl NetMDInterface {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1809 8001 0330 %w 0030 8805 0030 %w 00 ff00 00000000".to_string(),
|
"1809 8001 0330 %w 0030 8805 0030 %w 00 ff00 00000000".to_string(),
|
||||||
vec![QueryValue::Number(p1 as i64), QueryValue::Number(p2 as i64)],
|
vec![QueryValue::Number(p1 as i64), QueryValue::Number(p2 as i64)],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
let res = scan_query(
|
let res = scan_query(
|
||||||
reply,
|
reply,
|
||||||
"1809 8001 0330 %?%? %?%? %?%? %?%? %?%? %? 1000 00%?0000 %x %?".to_string(),
|
"1809 8001 0330 %?%? %?%? %?%? %?%? %?%? %? 1000 00%?0000 %x %?".to_string(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.change_descriptor_state(&Descriptor::OperatingStatusBlock, &DescriptorAction::Close)
|
self.change_descriptor_state(
|
||||||
.await?;
|
&Descriptor::OperatingStatusBlock,
|
||||||
|
&DescriptorAction::Close
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(res[0].to_vec().unwrap())
|
Ok(res[0].to_vec().unwrap())
|
||||||
}
|
}
|
||||||
|
@ -689,21 +708,18 @@ impl NetMDInterface {
|
||||||
self.change_descriptor_state(
|
self.change_descriptor_state(
|
||||||
&Descriptor::OperatingStatusBlock,
|
&Descriptor::OperatingStatusBlock,
|
||||||
&DescriptorAction::OpenRead,
|
&DescriptorAction::OpenRead,
|
||||||
)
|
).await?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1809 8001 0430 8802 0030 8805 0030 0003 0030 0002 00 ff00 00000000".to_string(),
|
"1809 8001 0430 8802 0030 8805 0030 0003 0030 0002 00 ff00 00000000".to_string(),
|
||||||
vec![],
|
vec![],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let reply = match self.send_query(&mut query, false, false).await {
|
//TODO: Ensure this is ok, we might want to do proper error handling
|
||||||
Ok(result) => result,
|
let reply = match self.send_query(&query, false, false).await {
|
||||||
Err(e) => match e {
|
Ok(d) => d,
|
||||||
InterfaceError::Rejected(_) => Vec::new(),
|
Err(_) => return Ok([0u16; 5]),
|
||||||
_ => return Err(e),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = scan_query(reply, "1809 8001 0430 %?%? %?%? %?%? %?%? %?%? %?%? %?%? %? %?00 00%?0000 000b 0002 0007 00 %w %B %B %B %B".to_string())?;
|
let result = scan_query(reply, "1809 8001 0430 %?%? %?%? %?%? %?%? %?%? %?%? %?%? %? %?00 00%?0000 000b 0002 0007 00 %w %B %B %B %B".to_string())?;
|
||||||
|
@ -716,26 +732,28 @@ impl NetMDInterface {
|
||||||
result[4].to_i64().unwrap() as u16,
|
result[4].to_i64().unwrap() as u16,
|
||||||
];
|
];
|
||||||
|
|
||||||
self.change_descriptor_state(&Descriptor::OperatingStatusBlock, &DescriptorAction::Close)
|
self.change_descriptor_state(
|
||||||
.await?;
|
&Descriptor::OperatingStatusBlock,
|
||||||
|
&DescriptorAction::Close
|
||||||
|
).await?;
|
||||||
|
|
||||||
Ok(final_result)
|
Ok(final_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Eject the disc from the player if supported
|
/// Eject the disc from the player if supported
|
||||||
pub async fn eject_disc(&mut self) -> Result<(), InterfaceError> {
|
pub async fn eject_disc(&mut self) -> Result<(), InterfaceError> {
|
||||||
let mut query = format_query("18c1 ff 6000".to_string(), vec![]).unwrap();
|
let 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(&query, false, false).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the machine has the capability to eject a disc
|
/// Check if the machine has the capability to eject a disc
|
||||||
pub async fn can_eject_disc(&mut self) -> Result<bool, InterfaceError> {
|
pub async fn can_eject_disc(&mut self) -> Result<bool, InterfaceError> {
|
||||||
let mut query = format_query("18c1 ff 6000".to_string(), vec![]).unwrap();
|
let query = format_query("18c1 ff 6000".to_string(), vec![]).unwrap();
|
||||||
|
|
||||||
match self.send_query(&mut query, true, false).await {
|
match self.send_query(&query, true, false).await {
|
||||||
Ok(_) => Ok(true),
|
Ok(_) => Ok(true),
|
||||||
Err(error) => Err(error),
|
Err(error) => Err(error),
|
||||||
}
|
}
|
||||||
|
@ -743,13 +761,13 @@ impl NetMDInterface {
|
||||||
|
|
||||||
/// Move the playback to a specific track
|
/// Move the playback to a specific track
|
||||||
pub async fn go_to_track(&mut self, track_number: u16) -> Result<u16, InterfaceError> {
|
pub async fn go_to_track(&mut self, track_number: u16) -> Result<u16, InterfaceError> {
|
||||||
let mut query = format_query(
|
let 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)],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
let res = scan_query(reply, "1850 00010000 0000 %w".to_string())?;
|
let res = scan_query(reply, "1850 00010000 0000 %w".to_string())?;
|
||||||
|
|
||||||
|
@ -767,7 +785,7 @@ impl NetMDInterface {
|
||||||
second: u8,
|
second: u8,
|
||||||
frame: u8,
|
frame: u8,
|
||||||
) -> Result<u16, InterfaceError> {
|
) -> Result<u16, InterfaceError> {
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1850 ff000000 0000 %w %B%B%B%B".to_string(),
|
"1850 ff000000 0000 %w %B%B%B%B".to_string(),
|
||||||
vec![
|
vec![
|
||||||
QueryValue::Number(track_number as i64),
|
QueryValue::Number(track_number as i64),
|
||||||
|
@ -779,7 +797,7 @@ impl NetMDInterface {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
let res = scan_query(reply, "1850 00000000 %?%? %w %B%B%B%B".to_string())?;
|
let res = scan_query(reply, "1850 00000000 %?%? %w %B%B%B%B".to_string())?;
|
||||||
|
|
||||||
|
@ -788,14 +806,15 @@ impl NetMDInterface {
|
||||||
Ok(value as u16)
|
Ok(value as u16)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Change track in a [`Direction`]
|
||||||
pub async fn track_change(&mut self, direction: Direction) -> Result<(), InterfaceError> {
|
pub async fn track_change(&mut self, direction: Direction) -> Result<(), InterfaceError> {
|
||||||
let mut query = format_query(
|
let 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)],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
scan_query(reply, "1850 0010 00000000 %?%?".to_string())?;
|
scan_query(reply, "1850 0010 00000000 %?%?".to_string())?;
|
||||||
|
|
||||||
|
@ -804,21 +823,22 @@ impl NetMDInterface {
|
||||||
|
|
||||||
/// 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 query = format_query("1840 ff 0000".to_string(), vec![]).unwrap();
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
scan_query(reply, "1840 00 0000".to_string())?;
|
scan_query(reply, "1840 00 0000".to_string())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
/// Get the flags from a disc
|
||||||
pub async fn disc_flags(&mut self) -> Result<u8, InterfaceError> {
|
pub async fn disc_flags(&mut self) -> Result<u8, InterfaceError> {
|
||||||
self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead)
|
self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut query = format_query("1806 01101000 ff00 0001000b".to_string(), vec![]).unwrap();
|
let query = format_query("1806 01101000 ff00 0001000b".to_string(), vec![]).unwrap();
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
let res = scan_query(reply, "1806 01101000 1000 0001000b %b".to_string()).unwrap();
|
let res = scan_query(reply, "1806 01101000 1000 0001000b %b".to_string()).unwrap();
|
||||||
|
|
||||||
|
@ -828,15 +848,15 @@ impl NetMDInterface {
|
||||||
Ok(res[0].to_i64().unwrap() as u8)
|
Ok(res[0].to_i64().unwrap() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The number of tracks on the disc
|
/// Get the number of tracks on the disc
|
||||||
pub async fn track_count(&mut self) -> Result<u16, InterfaceError> {
|
pub async fn track_count(&mut self) -> Result<u16, InterfaceError> {
|
||||||
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead)
|
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut query =
|
let query =
|
||||||
format_query("1806 02101001 3000 1000 ff00 00000000".to_string(), vec![]).unwrap();
|
format_query("1806 02101001 3000 1000 ff00 00000000".to_string(), vec![]).unwrap();
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
let res = scan_query(
|
let res = scan_query(
|
||||||
reply,
|
reply,
|
||||||
|
@ -870,7 +890,7 @@ impl NetMDInterface {
|
||||||
false => 0,
|
false => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1806 02201801 00%b 3000 0a00 ff00 %w%w".to_string(),
|
"1806 02201801 00%b 3000 0a00 ff00 %w%w".to_string(),
|
||||||
vec![
|
vec![
|
||||||
QueryValue::Number(wchar_value),
|
QueryValue::Number(wchar_value),
|
||||||
|
@ -880,7 +900,7 @@ impl NetMDInterface {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
if remaining == 0 {
|
if remaining == 0 {
|
||||||
let res = scan_query(
|
let res = scan_query(
|
||||||
|
@ -917,7 +937,7 @@ impl NetMDInterface {
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the disc title
|
/// Gets the disc title without group information
|
||||||
pub async fn disc_title(&mut self, wchar: bool) -> Result<String, InterfaceError> {
|
pub async fn disc_title(&mut self, wchar: bool) -> Result<String, InterfaceError> {
|
||||||
let mut title = self.raw_disc_title(wchar).await?;
|
let mut title = self.raw_disc_title(wchar).await?;
|
||||||
|
|
||||||
|
@ -1051,7 +1071,7 @@ impl NetMDInterface {
|
||||||
|
|
||||||
let mut track_titles: Vec<String> = vec![];
|
let mut track_titles: Vec<String> = vec![];
|
||||||
for i in tracks {
|
for i in tracks {
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1806 022018%b %w 3000 0a00 ff00 00000000".to_string(),
|
"1806 022018%b %w 3000 0a00 ff00 00000000".to_string(),
|
||||||
vec![
|
vec![
|
||||||
QueryValue::Number(wchar_value),
|
QueryValue::Number(wchar_value),
|
||||||
|
@ -1060,7 +1080,7 @@ impl NetMDInterface {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
let res = scan_query(
|
let res = scan_query(
|
||||||
reply,
|
reply,
|
||||||
|
@ -1095,6 +1115,9 @@ impl NetMDInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the title of the disc
|
// Sets the title of the disc
|
||||||
|
//
|
||||||
|
// Caution: This does not respect groups. Use the functions available in
|
||||||
|
// NetMDContext to properly rename a disc.
|
||||||
pub async fn set_disc_title(&mut self, title: &str, wchar: bool) -> Result<(), InterfaceError> {
|
pub async fn set_disc_title(&mut self, title: &str, wchar: bool) -> Result<(), InterfaceError> {
|
||||||
let current_title = self.raw_disc_title(wchar).await?;
|
let current_title = self.raw_disc_title(wchar).await?;
|
||||||
if current_title == title {
|
if current_title == title {
|
||||||
|
@ -1127,7 +1150,7 @@ impl NetMDInterface {
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1807 02201801 00%b 3000 0a00 5000 %w 0000 %w %*".to_string(),
|
"1807 02201801 00%b 3000 0a00 5000 %w 0000 %w %*".to_string(),
|
||||||
vec![
|
vec![
|
||||||
QueryValue::Number(wchar_value),
|
QueryValue::Number(wchar_value),
|
||||||
|
@ -1137,7 +1160,7 @@ impl NetMDInterface {
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let _ = self.send_query(&mut query, false, false).await;
|
let _ = self.send_query(&query, false, false).await;
|
||||||
|
|
||||||
if self.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)
|
||||||
|
@ -1191,7 +1214,7 @@ impl NetMDInterface {
|
||||||
self.change_descriptor_state(&descriptor, &DescriptorAction::OpenWrite)
|
self.change_descriptor_state(&descriptor, &DescriptorAction::OpenWrite)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1807 022018%b %w 3000 0a00 5000 %w 0000 %w %*".to_string(),
|
"1807 022018%b %w 3000 0a00 5000 %w 0000 %w %*".to_string(),
|
||||||
vec![
|
vec![
|
||||||
QueryValue::Number(wchar_value),
|
QueryValue::Number(wchar_value),
|
||||||
|
@ -1201,7 +1224,7 @@ impl NetMDInterface {
|
||||||
QueryValue::Array(new_title),
|
QueryValue::Array(new_title),
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
let _ = scan_query(
|
let _ = scan_query(
|
||||||
reply,
|
reply,
|
||||||
|
@ -1215,19 +1238,19 @@ impl NetMDInterface {
|
||||||
|
|
||||||
/// Erases a track from the disc's UTOC
|
/// Erases a track from the disc's UTOC
|
||||||
pub async fn erase_track(&mut self, track: u16) -> Result<(), InterfaceError> {
|
pub async fn erase_track(&mut self, track: u16) -> Result<(), InterfaceError> {
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1840 ff01 00 201001 %w".to_string(),
|
"1840 ff01 00 201001 %w".to_string(),
|
||||||
vec![QueryValue::Number(track as i64)],
|
vec![QueryValue::Number(track as i64)],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let _result = self.send_query(&mut query, false, false).await;
|
let _result = self.send_query(&query, false, false).await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves a track to another index on the disc
|
/// Moves a track to another index on the disc
|
||||||
pub async fn move_track(&mut self, source: u16, dest: u16) -> Result<(), InterfaceError> {
|
pub async fn move_track(&mut self, source: u16, dest: u16) -> Result<(), InterfaceError> {
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1843 ff00 00 201001 %w 201001 %w".to_string(),
|
"1843 ff00 00 201001 %w 201001 %w".to_string(),
|
||||||
vec![
|
vec![
|
||||||
QueryValue::Number(source as i64),
|
QueryValue::Number(source as i64),
|
||||||
|
@ -1235,7 +1258,7 @@ impl NetMDInterface {
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let _result = self.send_query(&mut query, false, false).await;
|
let _result = self.send_query(&query, false, false).await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1250,7 +1273,7 @@ impl NetMDInterface {
|
||||||
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead)
|
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1806 02201001 %w %w %w ff00 00000000".to_string(),
|
"1806 02201001 %w %w %w ff00 00000000".to_string(),
|
||||||
vec![
|
vec![
|
||||||
QueryValue::Number(track as i64),
|
QueryValue::Number(track as i64),
|
||||||
|
@ -1259,7 +1282,7 @@ impl NetMDInterface {
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
let res = scan_query(
|
let res = scan_query(
|
||||||
reply,
|
reply,
|
||||||
"1806 02201001 %?%? %?%? %?%? 1000 00%?0000 %x".to_string(),
|
"1806 02201001 %?%? %?%? %?%? 1000 00%?0000 %x".to_string(),
|
||||||
|
@ -1282,7 +1305,7 @@ impl NetMDInterface {
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
for track in tracks {
|
for track in tracks {
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1806 02201001 %w %w %w ff00 00000000".to_string(),
|
"1806 02201001 %w %w %w ff00 00000000".to_string(),
|
||||||
vec![
|
vec![
|
||||||
QueryValue::Number(track as i64),
|
QueryValue::Number(track as i64),
|
||||||
|
@ -1291,7 +1314,7 @@ impl NetMDInterface {
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
let res = scan_query(
|
let res = scan_query(
|
||||||
reply,
|
reply,
|
||||||
|
@ -1358,11 +1381,11 @@ impl NetMDInterface {
|
||||||
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead)
|
self.change_descriptor_state(&Descriptor::AudioContentsTD, &DescriptorAction::OpenRead)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1806 01201001 %w ff00 00010008".to_string(),
|
"1806 01201001 %w ff00 00010008".to_string(),
|
||||||
vec![QueryValue::Number(track as i64)],
|
vec![QueryValue::Number(track as i64)],
|
||||||
)?;
|
)?;
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
let res = scan_query(reply, "1806 01201001 %?%? 10 00 00010008 %b".to_string())?;
|
let res = scan_query(reply, "1806 01201001 %?%? 10 00 00010008 %b".to_string())?;
|
||||||
|
|
||||||
|
@ -1377,8 +1400,8 @@ impl NetMDInterface {
|
||||||
self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead)
|
self.change_descriptor_state(&Descriptor::RootTD, &DescriptorAction::OpenRead)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut query = format_query("1806 02101000 3080 0300 ff00 00000000".to_string(), vec![])?;
|
let query = format_query("1806 02101000 3080 0300 ff00 00000000".to_string(), vec![])?;
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
// 8003 changed to %?03 - Panasonic returns 0803 instead. This byte's meaning is unknown
|
// 8003 changed to %?03 - Panasonic returns 0803 instead. This byte's meaning is unknown
|
||||||
let res = scan_query(
|
let res = scan_query(
|
||||||
|
@ -1410,12 +1433,12 @@ impl NetMDInterface {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut query = format_query(
|
let 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(),
|
||||||
vec![],
|
vec![],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
let res = scan_query(reply, "1809 8001 0330 8801 0030 8805 0030 8807 00 1000 000e0000 000c 8805 0008 80e0 0110 %b %b 4000".to_string())?;
|
let res = scan_query(reply, "1809 8001 0330 8801 0030 8805 0030 8807 00 1000 000e0000 000c 8805 0008 80e0 0110 %b %b 4000".to_string())?;
|
||||||
|
|
||||||
|
@ -1433,12 +1456,12 @@ impl NetMDInterface {
|
||||||
track: u16,
|
track: u16,
|
||||||
progress_callback: Option<F>,
|
progress_callback: Option<F>,
|
||||||
) -> Result<(DiscFormat, u16, Vec<u8>), InterfaceError> {
|
) -> Result<(DiscFormat, u16, Vec<u8>), InterfaceError> {
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1800 080046 f003010330 ff00 1001 %w".to_string(),
|
"1800 080046 f003010330 ff00 1001 %w".to_string(),
|
||||||
vec![QueryValue::Number((track + 1) as i64)],
|
vec![QueryValue::Number((track + 1) as i64)],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, true).await?;
|
let reply = self.send_query(&query, false, true).await?;
|
||||||
|
|
||||||
let res = scan_query(
|
let res = scan_query(
|
||||||
reply,
|
reply,
|
||||||
|
@ -1473,28 +1496,28 @@ impl NetMDInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn disable_new_track_protection(&mut self, val: u16) -> Result<(), InterfaceError> {
|
pub async fn disable_new_track_protection(&mut self, val: u16) -> Result<(), InterfaceError> {
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1800 080046 f0030103 2b ff %w".to_string(),
|
"1800 080046 f0030103 2b ff %w".to_string(),
|
||||||
vec![QueryValue::Number(val as i64)],
|
vec![QueryValue::Number(val as i64)],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
scan_query(reply, "1800 080046 f0030103 2b 00 %?%?".to_string())?;
|
scan_query(reply, "1800 080046 f0030103 2b 00 %?%?".to_string())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn enter_secure_session(&mut self) -> Result<(), InterfaceError> {
|
pub async fn enter_secure_session(&mut self) -> Result<(), InterfaceError> {
|
||||||
let mut query = format_query("1800 080046 f0030103 80 ff".to_string(), vec![])?;
|
let query = format_query("1800 080046 f0030103 80 ff".to_string(), vec![])?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
scan_query(reply, "1800 080046 f0030103 80 00".to_string())?;
|
scan_query(reply, "1800 080046 f0030103 80 00".to_string())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn leave_secure_session(&mut self) -> Result<(), InterfaceError> {
|
pub async fn leave_secure_session(&mut self) -> Result<(), InterfaceError> {
|
||||||
let mut query = format_query("1800 080046 f0030103 81 ff".to_string(), vec![])?;
|
let query = format_query("1800 080046 f0030103 81 ff".to_string(), vec![])?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
scan_query(reply, "1800 080046 f0030103 81 00".to_string())?;
|
scan_query(reply, "1800 080046 f0030103 81 00".to_string())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1506,9 +1529,9 @@ impl NetMDInterface {
|
||||||
///
|
///
|
||||||
/// The leaf ID is a 8-byte constant
|
/// The leaf ID is a 8-byte constant
|
||||||
pub async fn leaf_id(&mut self) -> Result<[u8; 8], InterfaceError> {
|
pub async fn leaf_id(&mut self) -> Result<[u8; 8], InterfaceError> {
|
||||||
let mut query = format_query("1800 080046 f0030103 11 ff".to_string(), vec![])?;
|
let query = format_query("1800 080046 f0030103 11 ff".to_string(), vec![])?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
let res = scan_query(reply, "1800 080046 f0030103 11 00 %*".to_string())?;
|
let res = scan_query(reply, "1800 080046 f0030103 11 00 %*".to_string())?;
|
||||||
|
|
||||||
Ok(res[0].to_vec().unwrap().try_into().unwrap())
|
Ok(res[0].to_vec().unwrap().try_into().unwrap())
|
||||||
|
@ -1530,7 +1553,7 @@ impl NetMDInterface {
|
||||||
|
|
||||||
let keychains = keychain.concat();
|
let keychains = keychain.concat();
|
||||||
|
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1800 080046 f0030103 12 ff %w 0000 %w %d %d %d 00000000 %* %*".to_string(),
|
"1800 080046 f0030103 12 ff %w 0000 %w %d %d %d 00000000 %* %*".to_string(),
|
||||||
vec![
|
vec![
|
||||||
QueryValue::Number(databytes as i64),
|
QueryValue::Number(databytes as i64),
|
||||||
|
@ -1543,7 +1566,7 @@ impl NetMDInterface {
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
scan_query(
|
scan_query(
|
||||||
reply,
|
reply,
|
||||||
|
@ -1564,12 +1587,12 @@ impl NetMDInterface {
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1800 080046 f0030103 20 ff 000000 %*".to_string(),
|
"1800 080046 f0030103 20 ff 000000 %*".to_string(),
|
||||||
vec![QueryValue::Array(hostnonce)],
|
vec![QueryValue::Array(hostnonce)],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
let res = scan_query(reply, "1800 080046 f0030103 20 %? 000000 %#".to_string())?;
|
let res = scan_query(reply, "1800 080046 f0030103 20 %? 000000 %#".to_string())?;
|
||||||
|
|
||||||
|
@ -1577,9 +1600,9 @@ impl NetMDInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn session_key_forget(&mut self) -> Result<(), InterfaceError> {
|
pub async fn session_key_forget(&mut self) -> Result<(), InterfaceError> {
|
||||||
let mut query = format_query("1800 080046 f0030103 21 ff 000000".to_string(), vec![])?;
|
let query = format_query("1800 080046 f0030103 21 ff 000000".to_string(), vec![])?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
let _ = scan_query(reply, "1800 080046 f0030103 21 00 000000".to_string())?;
|
let _ = scan_query(reply, "1800 080046 f0030103 21 00 000000".to_string())?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1615,12 +1638,12 @@ impl NetMDInterface {
|
||||||
.encrypt_padded_mut::<NoPadding>(message.as_mut_slice(), 32)
|
.encrypt_padded_mut::<NoPadding>(message.as_mut_slice(), 32)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1800 080046 f0030103 22 ff 0000 %*".to_string(),
|
"1800 080046 f0030103 22 ff 0000 %*".to_string(),
|
||||||
vec![QueryValue::Array(message)],
|
vec![QueryValue::Array(message)],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
scan_query(reply, "1800 080046 f0030103 22 00 0000".to_string())?;
|
scan_query(reply, "1800 080046 f0030103 22 00 0000".to_string())?;
|
||||||
|
|
||||||
|
@ -1644,7 +1667,7 @@ impl NetMDInterface {
|
||||||
.encrypt_padded_mut::<NoPadding>(&mut message, 8)
|
.encrypt_padded_mut::<NoPadding>(&mut message, 8)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1800 080046 f0030103 48 ff 00 1001 %w %*".to_string(),
|
"1800 080046 f0030103 48 ff 00 1001 %w %*".to_string(),
|
||||||
vec![
|
vec![
|
||||||
QueryValue::Number(track_number as i64),
|
QueryValue::Number(track_number as i64),
|
||||||
|
@ -1652,7 +1675,7 @@ impl NetMDInterface {
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
scan_query(reply, "1800 080046 f0030103 48 00 00 1001 %?%?".to_string())?;
|
scan_query(reply, "1800 080046 f0030103 48 00 00 1001 %?%?".to_string())?;
|
||||||
|
|
||||||
|
@ -1660,7 +1683,7 @@ impl NetMDInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub async fn send_track<F>(
|
pub async fn send_track<F: Fn(usize, usize)>(
|
||||||
&mut self,
|
&mut self,
|
||||||
wireformat: u8,
|
wireformat: u8,
|
||||||
discformat: u8,
|
discformat: u8,
|
||||||
|
@ -1671,8 +1694,6 @@ impl NetMDInterface {
|
||||||
hex_session_key: &[u8],
|
hex_session_key: &[u8],
|
||||||
progress_callback: F,
|
progress_callback: F,
|
||||||
) -> Result<(u16, Vec<u8>, Vec<u8>), InterfaceError>
|
) -> Result<(u16, Vec<u8>, Vec<u8>), InterfaceError>
|
||||||
where
|
|
||||||
F: Fn(usize, usize),
|
|
||||||
{
|
{
|
||||||
if hex_session_key.len() != 8 {
|
if hex_session_key.len() != 8 {
|
||||||
return Err(EncryptionError::InvalidLength(
|
return Err(EncryptionError::InvalidLength(
|
||||||
|
@ -1686,7 +1707,7 @@ impl NetMDInterface {
|
||||||
|
|
||||||
let total_bytes: usize = (pkt_size + 24) as usize; //framesizedict[wireformat] * frames + pktcount * 24;
|
let total_bytes: usize = (pkt_size + 24) as usize; //framesizedict[wireformat] * frames + pktcount * 24;
|
||||||
|
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1800 080046 f0030103 28 ff 000100 1001 ffff 00 %b %b %d %d".to_string(),
|
"1800 080046 f0030103 28 ff 000100 1001 ffff 00 %b %b %d %d".to_string(),
|
||||||
vec![
|
vec![
|
||||||
QueryValue::Number(wireformat as i64),
|
QueryValue::Number(wireformat as i64),
|
||||||
|
@ -1695,7 +1716,7 @@ impl NetMDInterface {
|
||||||
QueryValue::Number(total_bytes as i64),
|
QueryValue::Number(total_bytes as i64),
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
let mut reply = self.send_query(&mut query, false, true).await?;
|
let mut reply = self.send_query(&query, false, true).await?;
|
||||||
scan_query(
|
scan_query(
|
||||||
reply,
|
reply,
|
||||||
"1800 080046 f0030103 28 00 000100 1001 %?%? 00 %*".to_string(),
|
"1800 080046 f0030103 28 00 000100 1001 %?%? 00 %*".to_string(),
|
||||||
|
@ -1744,11 +1765,11 @@ impl NetMDInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn track_uuid(&mut self, track: u16) -> Result<String, InterfaceError> {
|
pub async fn track_uuid(&mut self, track: u16) -> Result<String, InterfaceError> {
|
||||||
let mut query = format_query(
|
let query = format_query(
|
||||||
"1800 080046 f0030103 23 ff 1001 %w".to_string(),
|
"1800 080046 f0030103 23 ff 1001 %w".to_string(),
|
||||||
vec![QueryValue::Number(track as i64)],
|
vec![QueryValue::Number(track as i64)],
|
||||||
)?;
|
)?;
|
||||||
let reply = self.send_query(&mut query, false, false).await?;
|
let reply = self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
let res = scan_query(reply, "1800 080046 f0030103 23 00 1001 %?%? %*".to_string())?;
|
let res = scan_query(reply, "1800 080046 f0030103 23 00 1001 %?%? %*".to_string())?;
|
||||||
|
|
||||||
|
@ -1756,8 +1777,8 @@ impl NetMDInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn terminate(&mut self) -> Result<(), InterfaceError> {
|
pub async fn terminate(&mut self) -> Result<(), InterfaceError> {
|
||||||
let mut query = format_query("1800 080046 f0030103 2a ff00".to_string(), vec![])?;
|
let query = format_query("1800 080046 f0030103 2a ff00".to_string(), vec![])?;
|
||||||
self.send_query(&mut query, false, false).await?;
|
self.send_query(&query, false, false).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1768,7 +1789,7 @@ type DesCbcEnc = cbc::Encryptor<des::Des>;
|
||||||
type DesCbcDec = cbc::Decryptor<des::Des>;
|
type DesCbcDec = cbc::Decryptor<des::Des>;
|
||||||
type TDesCbcEnc = cbc::Encryptor<des::TdesEde3>;
|
type TDesCbcEnc = cbc::Encryptor<des::TdesEde3>;
|
||||||
|
|
||||||
pub fn retailmac(key: &[u8], value: &[u8], iv: &[u8; 8]) -> Vec<u8> {
|
pub(super) 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.copy_from_slice(&key[0..8]);
|
subkey_a.copy_from_slice(&key[0..8]);
|
||||||
|
|
||||||
|
@ -1794,13 +1815,13 @@ pub fn retailmac(key: &[u8], value: &[u8], iv: &[u8; 8]) -> Vec<u8> {
|
||||||
end[..8].to_vec()
|
end[..8].to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EKBData {
|
pub(super) struct EKBData {
|
||||||
chains: [[u8; 16]; 2],
|
chains: [[u8; 16]; 2],
|
||||||
depth: i32,
|
depth: i32,
|
||||||
signature: [u8; 24],
|
signature: [u8; 24],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EKBOpenSource;
|
pub(super) struct EKBOpenSource;
|
||||||
|
|
||||||
impl EKBOpenSource {
|
impl EKBOpenSource {
|
||||||
pub fn root_key(&self) -> [u8; 16] {
|
pub fn root_key(&self) -> [u8; 16] {
|
||||||
|
@ -1909,7 +1930,7 @@ impl MDTrack {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MDSession<'a> {
|
pub(super) struct MDSession<'a> {
|
||||||
pub md: &'a mut NetMDInterface,
|
pub md: &'a mut NetMDInterface,
|
||||||
pub ekb_object: EKBOpenSource,
|
pub ekb_object: EKBOpenSource,
|
||||||
pub hex_session_key: Option<Vec<u8>>,
|
pub hex_session_key: Option<Vec<u8>>,
|
||||||
|
@ -1948,14 +1969,12 @@ impl<'a> MDSession<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn download_track<F>(
|
pub async fn download_track<F: Fn(usize, usize)>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut track: MDTrack,
|
mut track: MDTrack,
|
||||||
progress_callback: F,
|
progress_callback: F,
|
||||||
disc_format: Option<DiscFormat>,
|
disc_format: Option<DiscFormat>,
|
||||||
) -> Result<(u16, Vec<u8>, Vec<u8>), Box<dyn Error>>
|
) -> Result<(u16, Vec<u8>, Vec<u8>), Box<dyn Error>>
|
||||||
where
|
|
||||||
F: Fn(usize, usize),
|
|
||||||
{
|
{
|
||||||
if self.hex_session_key.is_none() {
|
if self.hex_session_key.is_none() {
|
||||||
return Err("Cannot download a track using a non-init()'ed session!".into());
|
return Err("Cannot download a track using a non-init()'ed session!".into());
|
||||||
|
|
|
@ -8,3 +8,15 @@ pub mod interface;
|
||||||
mod mappings;
|
mod mappings;
|
||||||
mod query_utils;
|
mod query_utils;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use base::DEVICE_IDS_CROSSUSB;
|
||||||
|
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use commands::NetMDContext;
|
||||||
|
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use interface::NetMDInterface;
|
||||||
|
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use base::NetMD;
|
||||||
|
|
|
@ -90,13 +90,16 @@ pub enum QueryError {
|
||||||
#[error("unrecognized format character: `{0}`")]
|
#[error("unrecognized format character: `{0}`")]
|
||||||
UnrecognizedChar(char),
|
UnrecognizedChar(char),
|
||||||
|
|
||||||
#[error("Format and input mismatch at {index}: expected {expected:#04x}, got {actual:#04x} (format {format_string})")]
|
#[error("format and input mismatch at {index}: expected {expected:#04x}, got {actual:#04x} (format {format_string})")]
|
||||||
InputMismatch {
|
InputMismatch {
|
||||||
index: usize,
|
index: usize,
|
||||||
expected: u8,
|
expected: u8,
|
||||||
actual: u8,
|
actual: u8,
|
||||||
format_string: String,
|
format_string: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#[error("input data is empty")]
|
||||||
|
EmptyData,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Formats a query using a standard input to send to the player
|
/// Formats a query using a standard input to send to the player
|
||||||
|
@ -196,6 +199,14 @@ pub fn format_query(format: String, args: Vec<QueryValue>) -> Result<Vec<u8>, Qu
|
||||||
|
|
||||||
/// Scans a result using a standard input to recieve from the player
|
/// Scans a result using a standard input to recieve from the player
|
||||||
pub fn scan_query(query_result: Vec<u8>, format: String) -> Result<Vec<QueryValue>, QueryError> {
|
pub fn scan_query(query_result: Vec<u8>, format: String) -> Result<Vec<QueryValue>, QueryError> {
|
||||||
|
if DEBUG {
|
||||||
|
println!("RECV<<< F: {}", format);
|
||||||
|
}
|
||||||
|
|
||||||
|
if query_result.is_empty() {
|
||||||
|
return Err(QueryError::EmptyData)
|
||||||
|
}
|
||||||
|
|
||||||
let mut result: Vec<QueryValue> = Vec::new();
|
let mut result: Vec<QueryValue> = Vec::new();
|
||||||
|
|
||||||
let initial_length = query_result.len();
|
let initial_length = query_result.len();
|
||||||
|
|
Loading…
Reference in a new issue