1use crate::ptp::{
7 DevicePropDesc, DevicePropertyCode, OperationCode, PropertyDataType, PropertyValue,
8};
9use crate::Error;
10
11use super::PtpSession;
12
13impl PtpSession {
14 pub async fn get_device_prop_desc(
38 &self,
39 property: DevicePropertyCode,
40 ) -> Result<DevicePropDesc, Error> {
41 let (response, data) = self
42 .execute_with_receive(
43 OperationCode::GetDevicePropDesc,
44 &[u16::from(property) as u32],
45 )
46 .await?;
47 Self::check_response(&response, OperationCode::GetDevicePropDesc)?;
48 DevicePropDesc::from_bytes(&data)
49 }
50
51 pub async fn get_device_prop_value(
61 &self,
62 property: DevicePropertyCode,
63 ) -> Result<Vec<u8>, Error> {
64 let (response, data) = self
65 .execute_with_receive(
66 OperationCode::GetDevicePropValue,
67 &[u16::from(property) as u32],
68 )
69 .await?;
70 Self::check_response(&response, OperationCode::GetDevicePropValue)?;
71 Ok(data)
72 }
73
74 pub async fn get_device_prop_value_typed(
84 &self,
85 property: DevicePropertyCode,
86 data_type: PropertyDataType,
87 ) -> Result<PropertyValue, Error> {
88 let data = self.get_device_prop_value(property).await?;
89 let (value, _) = PropertyValue::from_bytes(&data, data_type)?;
90 Ok(value)
91 }
92
93 pub async fn set_device_prop_value(
103 &self,
104 property: DevicePropertyCode,
105 value: &[u8],
106 ) -> Result<(), Error> {
107 let response = self
108 .execute_with_send(
109 OperationCode::SetDevicePropValue,
110 &[u16::from(property) as u32],
111 value,
112 )
113 .await?;
114 Self::check_response(&response, OperationCode::SetDevicePropValue)?;
115 Ok(())
116 }
117
118 pub async fn set_device_prop_value_typed(
127 &self,
128 property: DevicePropertyCode,
129 value: &PropertyValue,
130 ) -> Result<(), Error> {
131 let data = value.to_bytes();
132 self.set_device_prop_value(property, &data).await
133 }
134
135 pub async fn reset_device_prop_value(&self, property: DevicePropertyCode) -> Result<(), Error> {
141 let response = self
142 .execute(
143 OperationCode::ResetDevicePropValue,
144 &[u16::from(property) as u32],
145 )
146 .await?;
147 Self::check_response(&response, OperationCode::ResetDevicePropValue)?;
148 Ok(())
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155 use crate::ptp::session::tests::{
156 data_container, mock_transport, ok_response, response_with_params,
157 };
158 use crate::ptp::{pack_u16, ResponseCode};
159
160 fn build_battery_prop_desc(current: u8) -> Vec<u8> {
162 let mut buf = Vec::new();
163 buf.extend_from_slice(&pack_u16(0x5001));
165 buf.extend_from_slice(&pack_u16(0x0002));
167 buf.push(0x00);
169 buf.push(100);
171 buf.push(current);
173 buf.push(0x01);
175 buf.push(0); buf.push(100); buf.push(1); buf
180 }
181
182 #[tokio::test]
183 async fn test_get_device_prop_desc() {
184 let (transport, mock) = mock_transport();
185 mock.queue_response(ok_response(1)); let prop_desc_data = build_battery_prop_desc(75);
189 mock.queue_response(data_container(
190 2,
191 OperationCode::GetDevicePropDesc,
192 &prop_desc_data,
193 ));
194 mock.queue_response(ok_response(2));
195
196 let session = PtpSession::open(transport, 1).await.unwrap();
197 let desc = session
198 .get_device_prop_desc(DevicePropertyCode::BatteryLevel)
199 .await
200 .unwrap();
201
202 assert_eq!(desc.property_code, DevicePropertyCode::BatteryLevel);
203 assert_eq!(desc.data_type, PropertyDataType::Uint8);
204 assert!(!desc.writable);
205 assert_eq!(desc.current_value, PropertyValue::Uint8(75));
206 }
207
208 #[tokio::test]
209 async fn test_get_device_prop_desc_not_supported() {
210 let (transport, mock) = mock_transport();
211 mock.queue_response(ok_response(1)); mock.queue_response(response_with_params(
213 2,
214 ResponseCode::DevicePropNotSupported,
215 &[],
216 ));
217
218 let session = PtpSession::open(transport, 1).await.unwrap();
219 let result = session
220 .get_device_prop_desc(DevicePropertyCode::BatteryLevel)
221 .await;
222
223 assert!(matches!(
224 result,
225 Err(crate::Error::Protocol {
226 code: ResponseCode::DevicePropNotSupported,
227 ..
228 })
229 ));
230 }
231
232 #[tokio::test]
233 async fn test_get_device_prop_value() {
234 let (transport, mock) = mock_transport();
235 mock.queue_response(ok_response(1)); let value_data = vec![75u8];
239 mock.queue_response(data_container(
240 2,
241 OperationCode::GetDevicePropValue,
242 &value_data,
243 ));
244 mock.queue_response(ok_response(2));
245
246 let session = PtpSession::open(transport, 1).await.unwrap();
247 let data = session
248 .get_device_prop_value(DevicePropertyCode::BatteryLevel)
249 .await
250 .unwrap();
251
252 assert_eq!(data, vec![75u8]);
253 }
254
255 #[tokio::test]
256 async fn test_get_device_prop_value_typed() {
257 let (transport, mock) = mock_transport();
258 mock.queue_response(ok_response(1)); let value_data = vec![0x90, 0x01]; mock.queue_response(data_container(
263 2,
264 OperationCode::GetDevicePropValue,
265 &value_data,
266 ));
267 mock.queue_response(ok_response(2));
268
269 let session = PtpSession::open(transport, 1).await.unwrap();
270 let value = session
271 .get_device_prop_value_typed(
272 DevicePropertyCode::ExposureIndex,
273 PropertyDataType::Uint16,
274 )
275 .await
276 .unwrap();
277
278 assert_eq!(value, PropertyValue::Uint16(400));
279 }
280
281 #[tokio::test]
282 async fn test_set_device_prop_value() {
283 let (transport, mock) = mock_transport();
284 mock.queue_response(ok_response(1)); mock.queue_response(ok_response(2)); let session = PtpSession::open(transport, 1).await.unwrap();
288 let value = vec![0x90, 0x01]; session
290 .set_device_prop_value(DevicePropertyCode::ExposureIndex, &value)
291 .await
292 .unwrap();
293 }
294
295 #[tokio::test]
296 async fn test_set_device_prop_value_typed() {
297 let (transport, mock) = mock_transport();
298 mock.queue_response(ok_response(1)); mock.queue_response(ok_response(2)); let session = PtpSession::open(transport, 1).await.unwrap();
302 session
303 .set_device_prop_value_typed(
304 DevicePropertyCode::ExposureIndex,
305 &PropertyValue::Uint16(400),
306 )
307 .await
308 .unwrap();
309 }
310
311 #[tokio::test]
312 async fn test_set_device_prop_value_invalid() {
313 let (transport, mock) = mock_transport();
314 mock.queue_response(ok_response(1)); mock.queue_response(response_with_params(
316 2,
317 ResponseCode::InvalidDevicePropValue,
318 &[],
319 ));
320
321 let session = PtpSession::open(transport, 1).await.unwrap();
322 let result = session
323 .set_device_prop_value(DevicePropertyCode::ExposureIndex, &[0x00, 0x00])
324 .await;
325
326 assert!(matches!(
327 result,
328 Err(crate::Error::Protocol {
329 code: ResponseCode::InvalidDevicePropValue,
330 ..
331 })
332 ));
333 }
334
335 #[tokio::test]
336 async fn test_reset_device_prop_value() {
337 let (transport, mock) = mock_transport();
338 mock.queue_response(ok_response(1)); mock.queue_response(ok_response(2)); let session = PtpSession::open(transport, 1).await.unwrap();
342 session
343 .reset_device_prop_value(DevicePropertyCode::ExposureIndex)
344 .await
345 .unwrap();
346 }
347}