chore: clean up containerinfo

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2025-10-16 12:15:09 +01:00
parent 1f26a91dcd
commit 4825b699a6
3 changed files with 124 additions and 52 deletions

View File

@@ -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(())

View File

@@ -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 {

View File

@@ -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)
}
}