chore: clean up containerinfo
Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
@@ -9,7 +9,7 @@ use byteorder::{LittleEndian, WriteBytesExt};
|
|||||||
use devices::SupportedCamera;
|
use devices::SupportedCamera;
|
||||||
use log::{debug, error, trace};
|
use log::{debug, error, trace};
|
||||||
use ptp::{
|
use ptp::{
|
||||||
enums::{CommandCode, ContainerType, PropCode, ResponseCode, UsbMode},
|
enums::{CommandCode, ContainerCode, ContainerType, PropCode, ResponseCode, UsbMode},
|
||||||
structs::{ContainerInfo, DeviceInfo},
|
structs::{ContainerInfo, DeviceInfo},
|
||||||
};
|
};
|
||||||
use rusb::{GlobalContext, constants::LIBUSB_CLASS_IMAGE};
|
use rusb::{GlobalContext, constants::LIBUSB_CLASS_IMAGE};
|
||||||
@@ -216,7 +216,9 @@ pub trait CameraImpl<P: rusb::UsbContext> {
|
|||||||
transaction: bool,
|
transaction: bool,
|
||||||
) -> anyhow::Result<Vec<u8>> {
|
) -> anyhow::Result<Vec<u8>> {
|
||||||
let transaction_id = if transaction {
|
let transaction_id = if transaction {
|
||||||
Some(ptp.transaction_id)
|
let transaction_id = Some(ptp.transaction_id);
|
||||||
|
ptp.transaction_id += 1;
|
||||||
|
transaction_id
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@@ -252,10 +254,13 @@ pub trait CameraImpl<P: rusb::UsbContext> {
|
|||||||
}
|
}
|
||||||
ContainerType::Response => {
|
ContainerType::Response => {
|
||||||
trace!("Response received: code {:?}", container.code);
|
trace!("Response received: code {:?}", container.code);
|
||||||
let code = ResponseCode::try_from(container.code)?;
|
match container.code {
|
||||||
if code != ResponseCode::Ok {
|
ContainerCode::Command(_) | ContainerCode::Response(ResponseCode::Ok) => {}
|
||||||
bail!(ptp::error::Error::Response(container.code));
|
ContainerCode::Response(code) => {
|
||||||
|
bail!(ptp::error::Error::Response(code as u16));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!(
|
trace!(
|
||||||
"Command {:?} completed successfully with data payload of {} bytes",
|
"Command {:?} completed successfully with data payload of {} bytes",
|
||||||
code,
|
code,
|
||||||
@@ -276,28 +281,12 @@ pub trait CameraImpl<P: rusb::UsbContext> {
|
|||||||
kind: ContainerType,
|
kind: ContainerType,
|
||||||
code: CommandCode,
|
code: CommandCode,
|
||||||
payload: &[u8],
|
payload: &[u8],
|
||||||
// Fuji, for the love of God don't ever write code again.
|
|
||||||
transaction_id: Option<u32>,
|
transaction_id: Option<u32>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
// Look at what you made me do. Fuck.
|
let container_info = ContainerInfo::new(kind, code, transaction_id, payload)?;
|
||||||
let header_len = ContainerInfo::SIZE
|
let first_chunk_len = min(payload.len(), self.chunk_size() - container_info.len());
|
||||||
- if transaction_id.is_none() {
|
|
||||||
size_of::<u32>()
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
let first_chunk_len = min(payload.len(), self.chunk_size() - header_len);
|
|
||||||
let total_len = u32::try_from(payload.len() + header_len)?;
|
|
||||||
|
|
||||||
let mut buffer = Vec::with_capacity(first_chunk_len + header_len);
|
|
||||||
buffer.write_u32::<LittleEndian>(total_len)?;
|
|
||||||
buffer.write_u16::<LittleEndian>(kind as u16)?;
|
|
||||||
buffer.write_u16::<LittleEndian>(code as u16)?;
|
|
||||||
if let Some(transaction_id) = transaction_id {
|
|
||||||
buffer.write_u32::<LittleEndian>(transaction_id)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
let mut buffer: Vec<u8> = container_info.try_into()?;
|
||||||
buffer.extend_from_slice(&payload[..first_chunk_len]);
|
buffer.extend_from_slice(&payload[..first_chunk_len]);
|
||||||
|
|
||||||
trace!(
|
trace!(
|
||||||
@@ -329,13 +318,14 @@ pub trait CameraImpl<P: rusb::UsbContext> {
|
|||||||
|
|
||||||
trace!("Read {n} bytes from bulk_in");
|
trace!("Read {n} bytes from bulk_in");
|
||||||
|
|
||||||
let container_info = ContainerInfo::parse(buf)?;
|
let container_info = ContainerInfo::try_from(buf)?;
|
||||||
if container_info.payload_len == 0 {
|
|
||||||
|
let payload_len = container_info.payload_len();
|
||||||
|
if payload_len == 0 {
|
||||||
trace!("No payload in container");
|
trace!("No payload in container");
|
||||||
return Ok((container_info, Vec::new()));
|
return Ok((container_info, Vec::new()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let payload_len = container_info.payload_len as usize;
|
|
||||||
let mut payload = Vec::with_capacity(payload_len);
|
let mut payload = Vec::with_capacity(payload_len);
|
||||||
if buf.len() > ContainerInfo::SIZE {
|
if buf.len() > ContainerInfo::SIZE {
|
||||||
payload.extend_from_slice(&buf[ContainerInfo::SIZE..]);
|
payload.extend_from_slice(&buf[ContainerInfo::SIZE..]);
|
||||||
@@ -415,7 +405,7 @@ pub trait CameraImpl<P: rusb::UsbContext> {
|
|||||||
|
|
||||||
fn import_backup(&self, ptp: &mut Ptp, buffer: &[u8]) -> anyhow::Result<()> {
|
fn import_backup(&self, ptp: &mut Ptp, buffer: &[u8]) -> anyhow::Result<()> {
|
||||||
debug!("Preparing ObjectInfo header for backup");
|
debug!("Preparing ObjectInfo header for backup");
|
||||||
let mut obj_info = vec![0u8; 1088];
|
let mut obj_info = vec![0u8; 1012];
|
||||||
let mut cursor = Cursor::new(&mut obj_info[..]);
|
let mut cursor = Cursor::new(&mut obj_info[..]);
|
||||||
cursor.write_u32::<LittleEndian>(0x0)?;
|
cursor.write_u32::<LittleEndian>(0x0)?;
|
||||||
cursor.write_u16::<LittleEndian>(0x5000)?;
|
cursor.write_u16::<LittleEndian>(0x5000)?;
|
||||||
@@ -433,13 +423,7 @@ pub trait CameraImpl<P: rusb::UsbContext> {
|
|||||||
debug!("Received response with {} bytes", response.len());
|
debug!("Received response with {} bytes", response.len());
|
||||||
|
|
||||||
debug!("Sending SendObject command for backup");
|
debug!("Sending SendObject command for backup");
|
||||||
let response = self.send(
|
let response = self.send(ptp, CommandCode::SendObject, None, Some(buffer), true)?;
|
||||||
ptp,
|
|
||||||
CommandCode::SendObject,
|
|
||||||
Some(&[0x0]),
|
|
||||||
Some(buffer),
|
|
||||||
false,
|
|
||||||
)?;
|
|
||||||
debug!("Received response with {} bytes", response.len());
|
debug!("Received response with {} bytes", response.len());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@@ -31,7 +31,7 @@ impl TryFrom<u16> for CommandCode {
|
|||||||
0x100D => Ok(Self::SendObject),
|
0x100D => Ok(Self::SendObject),
|
||||||
0x1015 => Ok(Self::GetDevicePropValue),
|
0x1015 => Ok(Self::GetDevicePropValue),
|
||||||
0x1016 => Ok(Self::SetDevicePropValue),
|
0x1016 => Ok(Self::SetDevicePropValue),
|
||||||
v => bail!("Unknown command code '{v}'"),
|
v => bail!("Unknown command code '{v:x?}'"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,11 +112,43 @@ impl std::convert::TryFrom<u16> for ResponseCode {
|
|||||||
0x201E => Ok(Self::SessionAlreadyOpen),
|
0x201E => Ok(Self::SessionAlreadyOpen),
|
||||||
0x201F => Ok(Self::TransactionCancelled),
|
0x201F => Ok(Self::TransactionCancelled),
|
||||||
0x2020 => Ok(Self::SpecificationOfDestinationUnsupported),
|
0x2020 => Ok(Self::SpecificationOfDestinationUnsupported),
|
||||||
v => bail!("Unknown response code '{v}'"),
|
v => bail!("Unknown response code '{v:x?}'"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(u16)]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum ContainerCode {
|
||||||
|
Command(CommandCode),
|
||||||
|
Response(ResponseCode),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ContainerCode> for u16 {
|
||||||
|
fn from(code: ContainerCode) -> Self {
|
||||||
|
match code {
|
||||||
|
ContainerCode::Command(cmd) => cmd as Self,
|
||||||
|
ContainerCode::Response(resp) => resp as Self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u16> for ContainerCode {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn try_from(value: u16) -> Result<Self, Self::Error> {
|
||||||
|
if let Ok(cmd) = CommandCode::try_from(value) {
|
||||||
|
return Ok(Self::Command(cmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(resp) = ResponseCode::try_from(value) {
|
||||||
|
return Ok(Self::Response(resp));
|
||||||
|
}
|
||||||
|
|
||||||
|
bail!("Unknown container code '{value:x?}'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum PropCode {
|
pub enum PropCode {
|
||||||
|
@@ -1,8 +1,11 @@
|
|||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
|
||||||
use super::{enums::ContainerType, read::Read};
|
use super::{
|
||||||
|
enums::{CommandCode, ContainerCode, ContainerType},
|
||||||
|
read::Read,
|
||||||
|
};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -50,28 +53,81 @@ impl TryFrom<&[u8]> for DeviceInfo {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct ContainerInfo {
|
pub struct ContainerInfo {
|
||||||
|
pub total_len: u32,
|
||||||
pub kind: ContainerType,
|
pub kind: ContainerType,
|
||||||
pub payload_len: u32,
|
pub code: ContainerCode,
|
||||||
pub code: u16,
|
pub transaction_id: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContainerInfo {
|
impl ContainerInfo {
|
||||||
pub const SIZE: usize =
|
const BASE_SIZE: usize = size_of::<u32>() + size_of::<u16>() + size_of::<u16>();
|
||||||
size_of::<ContainerType>() + size_of::<u32>() + size_of::<u16>() + size_of::<u32>();
|
pub const SIZE: usize = Self::BASE_SIZE + size_of::<u32>();
|
||||||
}
|
|
||||||
|
|
||||||
impl ContainerInfo {
|
pub fn new(
|
||||||
pub fn parse<R: ReadBytesExt>(mut r: R) -> anyhow::Result<Self> {
|
kind: ContainerType,
|
||||||
let payload_len = r.read_u32::<LittleEndian>()? - Self::SIZE as u32;
|
code: CommandCode,
|
||||||
let kind = r.read_u16::<LittleEndian>()?;
|
transaction_id: Option<u32>,
|
||||||
let kind = ContainerType::try_from(kind)?;
|
payload: &[u8],
|
||||||
let code = r.read_u16::<LittleEndian>()?;
|
) -> anyhow::Result<Self> {
|
||||||
let _transaction_id = r.read_u32::<LittleEndian>()?;
|
let mut total_len = if transaction_id.is_some() {
|
||||||
|
Self::SIZE
|
||||||
|
} else {
|
||||||
|
Self::BASE_SIZE
|
||||||
|
};
|
||||||
|
total_len += payload.len();
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
total_len: u32::try_from(total_len)?,
|
||||||
|
kind,
|
||||||
|
code: ContainerCode::Command(code),
|
||||||
|
transaction_id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn len(&self) -> usize {
|
||||||
|
if self.transaction_id.is_some() {
|
||||||
|
Self::SIZE
|
||||||
|
} else {
|
||||||
|
Self::BASE_SIZE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn payload_len(&self) -> usize {
|
||||||
|
self.total_len as usize - self.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&[u8]> for ContainerInfo {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||||
|
let mut r = Cursor::new(bytes);
|
||||||
|
|
||||||
|
let total_len = r.read_u32::<LittleEndian>()?;
|
||||||
|
let kind = ContainerType::try_from(r.read_u16::<LittleEndian>()?)?;
|
||||||
|
let code = ContainerCode::try_from(r.read_u16::<LittleEndian>()?)?;
|
||||||
|
let transaction_id = Some(r.read_u32::<LittleEndian>()?);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
total_len,
|
||||||
kind,
|
kind,
|
||||||
payload_len,
|
|
||||||
code,
|
code,
|
||||||
|
transaction_id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<ContainerInfo> for Vec<u8> {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn try_from(val: ContainerInfo) -> Result<Self, Self::Error> {
|
||||||
|
let mut buf = Self::with_capacity(val.len());
|
||||||
|
buf.write_u32::<LittleEndian>(val.total_len)?;
|
||||||
|
buf.write_u16::<LittleEndian>(val.kind as u16)?;
|
||||||
|
buf.write_u16::<LittleEndian>(val.code.into())?;
|
||||||
|
if let Some(transaction_id) = val.transaction_id {
|
||||||
|
buf.write_u32::<LittleEndian>(transaction_id)?;
|
||||||
|
}
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user