1use crate::ptp::{
7 pack_string, unpack_u32_array, DeviceInfo, EventContainer, ObjectFormatCode, ObjectHandle,
8 ObjectInfo, ObjectPropertyCode, OperationCode, StorageId, StorageInfo,
9};
10use crate::Error;
11
12use super::PtpSession;
13
14impl PtpSession {
15 pub async fn get_device_info(&self) -> Result<DeviceInfo, Error> {
18 let (response, data) = self
19 .execute_with_receive(OperationCode::GetDeviceInfo, &[])
20 .await?;
21 Self::check_response(&response, OperationCode::GetDeviceInfo)?;
22 DeviceInfo::from_bytes(&data)
23 }
24
25 pub async fn get_storage_ids(&self) -> Result<Vec<StorageId>, Error> {
27 let (response, data) = self
28 .execute_with_receive(OperationCode::GetStorageIds, &[])
29 .await?;
30 Self::check_response(&response, OperationCode::GetStorageIds)?;
31 let (ids, _) = unpack_u32_array(&data)?;
32 Ok(ids.into_iter().map(StorageId).collect())
33 }
34
35 pub async fn get_storage_info(&self, storage_id: StorageId) -> Result<StorageInfo, Error> {
38 let (response, data) = self
39 .execute_with_receive(OperationCode::GetStorageInfo, &[storage_id.0])
40 .await?;
41 Self::check_response(&response, OperationCode::GetStorageInfo)?;
42 StorageInfo::from_bytes(&data)
43 }
44
45 pub async fn get_object_handles(
56 &self,
57 storage_id: StorageId,
58 format: Option<ObjectFormatCode>,
59 parent: Option<ObjectHandle>,
60 ) -> Result<Vec<ObjectHandle>, Error> {
61 let format_code = format.map(|f| u16::from(f) as u32).unwrap_or(0);
62 let parent_handle = parent.map(|p| p.0).unwrap_or(0); let (response, data) = self
65 .execute_with_receive(
66 OperationCode::GetObjectHandles,
67 &[storage_id.0, format_code, parent_handle],
68 )
69 .await?;
70 Self::check_response(&response, OperationCode::GetObjectHandles)?;
71 let (handles, _) = unpack_u32_array(&data)?;
72 Ok(handles.into_iter().map(ObjectHandle).collect())
73 }
74
75 pub async fn get_object_info(&self, handle: ObjectHandle) -> Result<ObjectInfo, Error> {
77 let (response, data) = self
78 .execute_with_receive(OperationCode::GetObjectInfo, &[handle.0])
79 .await?;
80 Self::check_response(&response, OperationCode::GetObjectInfo)?;
81 ObjectInfo::from_bytes(&data)
82 }
83
84 pub async fn get_object(&self, handle: ObjectHandle) -> Result<Vec<u8>, Error> {
86 let (response, data) = self
87 .execute_with_receive(OperationCode::GetObject, &[handle.0])
88 .await?;
89 Self::check_response(&response, OperationCode::GetObject)?;
90 Ok(data)
91 }
92
93 pub async fn get_partial_object(
103 &self,
104 handle: ObjectHandle,
105 offset: u64,
106 max_bytes: u32,
107 ) -> Result<Vec<u8>, Error> {
108 let (response, data) = self
111 .execute_with_receive(
112 OperationCode::GetPartialObject,
113 &[handle.0, offset as u32, max_bytes],
114 )
115 .await?;
116 Self::check_response(&response, OperationCode::GetPartialObject)?;
117 Ok(data)
118 }
119
120 pub async fn get_thumb(&self, handle: ObjectHandle) -> Result<Vec<u8>, Error> {
122 let (response, data) = self
123 .execute_with_receive(OperationCode::GetThumb, &[handle.0])
124 .await?;
125 Self::check_response(&response, OperationCode::GetThumb)?;
126 Ok(data)
127 }
128
129 pub async fn send_object_info(
141 &self,
142 storage_id: StorageId,
143 parent: ObjectHandle,
144 info: &ObjectInfo,
145 ) -> Result<(StorageId, ObjectHandle, ObjectHandle), Error> {
146 let data = info.to_bytes()?;
147 let response = self
148 .execute_with_send(
149 OperationCode::SendObjectInfo,
150 &[storage_id.0, parent.0],
151 &data,
152 )
153 .await?;
154 Self::check_response(&response, OperationCode::SendObjectInfo)?;
155
156 if response.params.len() < 3 {
158 return Err(Error::invalid_data(
159 "SendObjectInfo response missing params",
160 ));
161 }
162 Ok((
163 StorageId(response.params[0]),
164 ObjectHandle(response.params[1]),
165 ObjectHandle(response.params[2]),
166 ))
167 }
168
169 pub async fn send_object(&self, data: &[u8]) -> Result<(), Error> {
174 let response = self
175 .execute_with_send(OperationCode::SendObject, &[], data)
176 .await?;
177 Self::check_response(&response, OperationCode::SendObject)?;
178 Ok(())
179 }
180
181 pub async fn delete_object(&self, handle: ObjectHandle) -> Result<(), Error> {
183 let response = self
185 .execute(OperationCode::DeleteObject, &[handle.0, 0])
186 .await?;
187 Self::check_response(&response, OperationCode::DeleteObject)?;
188 Ok(())
189 }
190
191 pub async fn move_object(
193 &self,
194 handle: ObjectHandle,
195 storage_id: StorageId,
196 parent: ObjectHandle,
197 ) -> Result<(), Error> {
198 let response = self
199 .execute(
200 OperationCode::MoveObject,
201 &[handle.0, storage_id.0, parent.0],
202 )
203 .await?;
204 Self::check_response(&response, OperationCode::MoveObject)?;
205 Ok(())
206 }
207
208 pub async fn copy_object(
211 &self,
212 handle: ObjectHandle,
213 storage_id: StorageId,
214 parent: ObjectHandle,
215 ) -> Result<ObjectHandle, Error> {
216 let response = self
217 .execute(
218 OperationCode::CopyObject,
219 &[handle.0, storage_id.0, parent.0],
220 )
221 .await?;
222 Self::check_response(&response, OperationCode::CopyObject)?;
223
224 if response.params.is_empty() {
225 return Err(Error::invalid_data("CopyObject response missing handle"));
226 }
227 Ok(ObjectHandle(response.params[0]))
228 }
229
230 pub async fn get_object_prop_value(
244 &self,
245 handle: ObjectHandle,
246 property: ObjectPropertyCode,
247 ) -> Result<Vec<u8>, Error> {
248 let (response, data) = self
249 .execute_with_receive(
250 OperationCode::GetObjectPropValue,
251 &[handle.0, u16::from(property) as u32],
252 )
253 .await?;
254 Self::check_response(&response, OperationCode::GetObjectPropValue)?;
255 Ok(data)
256 }
257
258 pub async fn set_object_prop_value(
269 &self,
270 handle: ObjectHandle,
271 property: ObjectPropertyCode,
272 value: &[u8],
273 ) -> Result<(), Error> {
274 let response = self
275 .execute_with_send(
276 OperationCode::SetObjectPropValue,
277 &[handle.0, u16::from(property) as u32],
278 value,
279 )
280 .await?;
281 Self::check_response(&response, OperationCode::SetObjectPropValue)?;
282 Ok(())
283 }
284
285 pub async fn rename_object(&self, handle: ObjectHandle, new_name: &str) -> Result<(), Error> {
299 let name_bytes = pack_string(new_name);
300 self.set_object_prop_value(handle, ObjectPropertyCode::ObjectFileName, &name_bytes)
301 .await
302 }
303
304 pub async fn initiate_capture(
344 &self,
345 storage_id: StorageId,
346 format: ObjectFormatCode,
347 ) -> Result<(), Error> {
348 let format_code = match format {
351 ObjectFormatCode::Undefined => 0,
352 other => u16::from(other) as u32,
353 };
354 let response = self
355 .execute(OperationCode::InitiateCapture, &[storage_id.0, format_code])
356 .await?;
357 Self::check_response(&response, OperationCode::InitiateCapture)?;
358 Ok(())
359 }
360
361 pub async fn poll_event(&self) -> Result<Option<EventContainer>, Error> {
378 match self.transport.receive_interrupt().await {
379 Ok(bytes) => {
380 let container = EventContainer::from_bytes(&bytes)?;
381 Ok(Some(container))
382 }
383 Err(Error::Timeout) => Ok(None),
384 Err(e) => Err(e),
385 }
386 }
387}
388
389#[cfg(test)]
390mod tests {
391 use super::*;
392 use crate::ptp::session::tests::{
393 data_container, mock_transport, ok_response, response_with_params,
394 };
395 use crate::ptp::{
396 pack_string, pack_u16, pack_u32, pack_u32_array, ContainerType, ResponseCode,
397 };
398
399 fn event_container(code: u16, params: [u32; 3]) -> Vec<u8> {
400 let mut buf = Vec::with_capacity(24);
401 buf.extend_from_slice(&pack_u32(24)); buf.extend_from_slice(&pack_u16(ContainerType::Event.to_code()));
403 buf.extend_from_slice(&pack_u16(code));
404 buf.extend_from_slice(&pack_u32(0)); buf.extend_from_slice(&pack_u32(params[0]));
406 buf.extend_from_slice(&pack_u32(params[1]));
407 buf.extend_from_slice(&pack_u32(params[2]));
408 buf
409 }
410
411 #[tokio::test]
412 async fn test_get_storage_ids() {
413 let (transport, mock) = mock_transport();
414 mock.queue_response(ok_response(1)); let storage_ids_data = pack_u32_array(&[0x00010001, 0x00010002]);
418 mock.queue_response(data_container(
419 2,
420 OperationCode::GetStorageIds,
421 &storage_ids_data,
422 ));
423 mock.queue_response(ok_response(2));
424
425 let session = PtpSession::open(transport, 1).await.unwrap();
426 let ids = session.get_storage_ids().await.unwrap();
427
428 assert_eq!(ids, vec![StorageId(0x00010001), StorageId(0x00010002)]);
429 }
430
431 #[tokio::test]
432 async fn test_get_object_handles() {
433 let (transport, mock) = mock_transport();
434 mock.queue_response(ok_response(1)); let handles_data = pack_u32_array(&[1, 2, 3]);
438 mock.queue_response(data_container(
439 2,
440 OperationCode::GetObjectHandles,
441 &handles_data,
442 ));
443 mock.queue_response(ok_response(2));
444
445 let session = PtpSession::open(transport, 1).await.unwrap();
446 let handles = session
447 .get_object_handles(StorageId::ALL, None, None)
448 .await
449 .unwrap();
450
451 assert_eq!(
452 handles,
453 vec![ObjectHandle(1), ObjectHandle(2), ObjectHandle(3)]
454 );
455 }
456
457 #[tokio::test]
458 async fn test_get_object() {
459 let (transport, mock) = mock_transport();
460 mock.queue_response(ok_response(1)); let object_data = vec![0x01, 0x02, 0x03, 0x04, 0x05];
464 mock.queue_response(data_container(2, OperationCode::GetObject, &object_data));
465 mock.queue_response(ok_response(2));
466
467 let session = PtpSession::open(transport, 1).await.unwrap();
468 let data = session.get_object(ObjectHandle(1)).await.unwrap();
469
470 assert_eq!(data, object_data);
471 }
472
473 #[tokio::test]
474 async fn test_delete_object() {
475 let (transport, mock) = mock_transport();
476 mock.queue_response(ok_response(1)); mock.queue_response(ok_response(2)); let session = PtpSession::open(transport, 1).await.unwrap();
480 session.delete_object(ObjectHandle(1)).await.unwrap();
481 }
482
483 #[tokio::test]
484 async fn test_copy_object() {
485 let (transport, mock) = mock_transport();
486 mock.queue_response(ok_response(1)); mock.queue_response(response_with_params(2, ResponseCode::Ok, &[100])); let session = PtpSession::open(transport, 1).await.unwrap();
490 let new_handle = session
491 .copy_object(ObjectHandle(1), StorageId(0x00010001), ObjectHandle::ROOT)
492 .await
493 .unwrap();
494
495 assert_eq!(new_handle, ObjectHandle(100));
496 }
497
498 #[tokio::test]
501 async fn test_poll_event_object_added() {
502 use crate::ptp::EventCode;
503
504 let (transport, mock) = mock_transport();
505 mock.queue_response(ok_response(1)); mock.queue_interrupt(event_container(0x4002, [42, 0, 0]));
509
510 let session = PtpSession::open(transport, 1).await.unwrap();
511 let event = session.poll_event().await.unwrap().unwrap();
512
513 assert_eq!(event.code, EventCode::ObjectAdded);
514 assert_eq!(event.params[0], 42);
515 }
516
517 #[tokio::test]
518 async fn test_poll_event_store_removed() {
519 use crate::ptp::EventCode;
520
521 let (transport, mock) = mock_transport();
522 mock.queue_response(ok_response(1)); mock.queue_interrupt(event_container(0x4005, [0x00010001, 0, 0]));
526
527 let session = PtpSession::open(transport, 1).await.unwrap();
528 let event = session.poll_event().await.unwrap().unwrap();
529
530 assert_eq!(event.code, EventCode::StoreRemoved);
531 assert_eq!(event.params[0], 0x00010001);
532 }
533
534 #[tokio::test]
535 async fn test_poll_event_multiple_events() {
536 use crate::ptp::EventCode;
537
538 let (transport, mock) = mock_transport();
539 mock.queue_response(ok_response(1)); mock.queue_interrupt(event_container(0x4002, [1, 0, 0])); mock.queue_interrupt(event_container(0x4002, [2, 0, 0])); mock.queue_interrupt(event_container(0x4003, [1, 0, 0])); let session = PtpSession::open(transport, 1).await.unwrap();
547
548 let event1 = session.poll_event().await.unwrap().unwrap();
549 assert_eq!(event1.code, EventCode::ObjectAdded);
550 assert_eq!(event1.params[0], 1);
551
552 let event2 = session.poll_event().await.unwrap().unwrap();
553 assert_eq!(event2.code, EventCode::ObjectAdded);
554 assert_eq!(event2.params[0], 2);
555
556 let event3 = session.poll_event().await.unwrap().unwrap();
557 assert_eq!(event3.code, EventCode::ObjectRemoved);
558 assert_eq!(event3.params[0], 1);
559 }
560
561 #[tokio::test]
564 async fn test_get_object_prop_value() {
565 let (transport, mock) = mock_transport();
566 mock.queue_response(ok_response(1)); let prop_value = vec![0x05, 0x48, 0x00, 0x69, 0x00, 0x00, 0x00]; mock.queue_response(data_container(
571 2,
572 OperationCode::GetObjectPropValue,
573 &prop_value,
574 ));
575 mock.queue_response(ok_response(2));
576
577 let session = PtpSession::open(transport, 1).await.unwrap();
578 let data = session
579 .get_object_prop_value(ObjectHandle(1), ObjectPropertyCode::ObjectFileName)
580 .await
581 .unwrap();
582
583 assert_eq!(data, prop_value);
584 }
585
586 #[tokio::test]
587 async fn test_set_object_prop_value() {
588 let (transport, mock) = mock_transport();
589 mock.queue_response(ok_response(1)); mock.queue_response(ok_response(2)); let session = PtpSession::open(transport, 1).await.unwrap();
593 let prop_value = pack_string("newfile.txt");
594 session
595 .set_object_prop_value(
596 ObjectHandle(1),
597 ObjectPropertyCode::ObjectFileName,
598 &prop_value,
599 )
600 .await
601 .unwrap();
602 }
603
604 #[tokio::test]
605 async fn test_set_object_prop_value_not_supported() {
606 let (transport, mock) = mock_transport();
607 mock.queue_response(ok_response(1)); mock.queue_response(response_with_params(
609 2,
610 ResponseCode::OperationNotSupported,
611 &[],
612 ));
613
614 let session = PtpSession::open(transport, 1).await.unwrap();
615 let prop_value = pack_string("newfile.txt");
616 let result = session
617 .set_object_prop_value(
618 ObjectHandle(1),
619 ObjectPropertyCode::ObjectFileName,
620 &prop_value,
621 )
622 .await;
623
624 assert!(matches!(
625 result,
626 Err(crate::Error::Protocol {
627 code: ResponseCode::OperationNotSupported,
628 ..
629 })
630 ));
631 }
632
633 #[tokio::test]
634 async fn test_rename_object() {
635 let (transport, mock) = mock_transport();
636 mock.queue_response(ok_response(1)); mock.queue_response(ok_response(2)); let session = PtpSession::open(transport, 1).await.unwrap();
640 session
641 .rename_object(ObjectHandle(1), "renamed.txt")
642 .await
643 .unwrap();
644 }
645
646 #[tokio::test]
647 async fn test_rename_object_not_supported() {
648 let (transport, mock) = mock_transport();
649 mock.queue_response(ok_response(1)); mock.queue_response(response_with_params(
651 2,
652 ResponseCode::OperationNotSupported,
653 &[],
654 ));
655
656 let session = PtpSession::open(transport, 1).await.unwrap();
657 let result = session.rename_object(ObjectHandle(1), "renamed.txt").await;
658
659 assert!(matches!(
660 result,
661 Err(crate::Error::Protocol {
662 code: ResponseCode::OperationNotSupported,
663 ..
664 })
665 ));
666 }
667
668 #[tokio::test]
671 async fn test_initiate_capture() {
672 let (transport, mock) = mock_transport();
673 mock.queue_response(ok_response(1)); mock.queue_response(ok_response(2)); let session = PtpSession::open(transport, 1).await.unwrap();
677 session
678 .initiate_capture(StorageId(0), ObjectFormatCode::Undefined)
679 .await
680 .unwrap();
681 }
682
683 #[tokio::test]
684 async fn test_initiate_capture_with_format() {
685 let (transport, mock) = mock_transport();
686 mock.queue_response(ok_response(1)); mock.queue_response(ok_response(2)); let session = PtpSession::open(transport, 1).await.unwrap();
690 session
691 .initiate_capture(StorageId(0x00010001), ObjectFormatCode::Jpeg)
692 .await
693 .unwrap();
694 }
695
696 #[tokio::test]
697 async fn test_initiate_capture_not_supported() {
698 let (transport, mock) = mock_transport();
699 mock.queue_response(ok_response(1)); mock.queue_response(response_with_params(
701 2,
702 ResponseCode::OperationNotSupported,
703 &[],
704 ));
705
706 let session = PtpSession::open(transport, 1).await.unwrap();
707 let result = session
708 .initiate_capture(StorageId(0), ObjectFormatCode::Undefined)
709 .await;
710
711 assert!(matches!(
712 result,
713 Err(crate::Error::Protocol {
714 code: ResponseCode::OperationNotSupported,
715 ..
716 })
717 ));
718 }
719}