Skip to main content

mtp_rs/mtp/
event.rs

1//! Device events.
2
3use crate::mtp::{ObjectHandle, StorageId};
4use crate::ptp::{EventCode, EventContainer};
5
6/// Events from an MTP device.
7#[derive(Debug, Clone)]
8pub enum DeviceEvent {
9    /// A new object was added.
10    ObjectAdded {
11        /// Handle of the new object.
12        handle: ObjectHandle,
13    },
14
15    /// An object was removed.
16    ObjectRemoved {
17        /// Handle of the removed object.
18        handle: ObjectHandle,
19    },
20
21    /// A storage was added (e.g., SD card inserted).
22    StoreAdded {
23        /// ID of the new storage.
24        storage_id: StorageId,
25    },
26
27    /// A storage was removed.
28    StoreRemoved {
29        /// ID of the removed storage.
30        storage_id: StorageId,
31    },
32
33    /// Storage info changed (e.g., free space).
34    StorageInfoChanged {
35        /// ID of the storage that changed.
36        storage_id: StorageId,
37    },
38
39    /// Object info changed.
40    ObjectInfoChanged {
41        /// Handle of the object that changed.
42        handle: ObjectHandle,
43    },
44
45    /// Device info changed.
46    DeviceInfoChanged,
47
48    /// Device is being reset.
49    DeviceReset,
50
51    /// Unknown event.
52    Unknown {
53        /// Raw event code.
54        code: u16,
55        /// Event parameters.
56        params: [u32; 3],
57    },
58}
59
60impl DeviceEvent {
61    /// Parse from an event container.
62    #[must_use]
63    pub fn from_container(container: &EventContainer) -> Self {
64        match container.code {
65            EventCode::ObjectAdded => DeviceEvent::ObjectAdded {
66                handle: ObjectHandle(u64::from(container.params[0])),
67            },
68            EventCode::ObjectRemoved => DeviceEvent::ObjectRemoved {
69                handle: ObjectHandle(u64::from(container.params[0])),
70            },
71            EventCode::StoreAdded => DeviceEvent::StoreAdded {
72                storage_id: StorageId(u64::from(container.params[0])),
73            },
74            EventCode::StoreRemoved => DeviceEvent::StoreRemoved {
75                storage_id: StorageId(u64::from(container.params[0])),
76            },
77            EventCode::StorageInfoChanged => DeviceEvent::StorageInfoChanged {
78                storage_id: StorageId(u64::from(container.params[0])),
79            },
80            EventCode::ObjectInfoChanged => DeviceEvent::ObjectInfoChanged {
81                handle: ObjectHandle(u64::from(container.params[0])),
82            },
83            EventCode::DeviceInfoChanged => DeviceEvent::DeviceInfoChanged,
84            // All other codes (including Unknown and unhandled known codes like DevicePropChanged)
85            other => DeviceEvent::Unknown {
86                code: other.into(),
87                params: container.params,
88            },
89        }
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn event_parsing() {
99        // Events with object handle param
100        for (code, expected_handle) in [
101            (EventCode::ObjectAdded, 42),
102            (EventCode::ObjectRemoved, 123),
103            (EventCode::ObjectInfoChanged, 99),
104        ] {
105            let container = EventContainer {
106                code,
107                transaction_id: 0,
108                params: [expected_handle, 0, 0],
109            };
110            let event = DeviceEvent::from_container(&container);
111            let handle = match event {
112                DeviceEvent::ObjectAdded { handle } => handle,
113                DeviceEvent::ObjectRemoved { handle } => handle,
114                DeviceEvent::ObjectInfoChanged { handle } => handle,
115                _ => panic!("Unexpected event type"),
116            };
117            assert_eq!(handle, ObjectHandle(u64::from(expected_handle)));
118        }
119
120        // Events with storage ID param
121        for (code, expected_id) in [
122            (EventCode::StoreAdded, 0x00010001),
123            (EventCode::StoreRemoved, 0x00010002),
124            (EventCode::StorageInfoChanged, 0x00010001),
125        ] {
126            let container = EventContainer {
127                code,
128                transaction_id: 0,
129                params: [expected_id, 0, 0],
130            };
131            let event = DeviceEvent::from_container(&container);
132            let storage_id = match event {
133                DeviceEvent::StoreAdded { storage_id } => storage_id,
134                DeviceEvent::StoreRemoved { storage_id } => storage_id,
135                DeviceEvent::StorageInfoChanged { storage_id } => storage_id,
136                _ => panic!("Unexpected event type"),
137            };
138            assert_eq!(storage_id, StorageId(u64::from(expected_id)));
139        }
140
141        // DeviceInfoChanged (no params)
142        let container = EventContainer {
143            code: EventCode::DeviceInfoChanged,
144            transaction_id: 0,
145            params: [0, 0, 0],
146        };
147        assert!(matches!(
148            DeviceEvent::from_container(&container),
149            DeviceEvent::DeviceInfoChanged
150        ));
151    }
152
153    #[test]
154    fn unknown_events() {
155        // Explicit Unknown code
156        let container = EventContainer {
157            code: EventCode::Unknown(0x9999),
158            transaction_id: 0,
159            params: [1, 2, 3],
160        };
161        match DeviceEvent::from_container(&container) {
162            DeviceEvent::Unknown { code, params } => {
163                assert_eq!(code, 0x9999);
164                assert_eq!(params, [1, 2, 3]);
165            }
166            _ => panic!("Expected Unknown event"),
167        }
168
169        // Known EventCode without DeviceEvent variant (DevicePropChanged)
170        let container = EventContainer {
171            code: EventCode::DevicePropChanged,
172            transaction_id: 0,
173            params: [100, 0, 0],
174        };
175        match DeviceEvent::from_container(&container) {
176            DeviceEvent::Unknown { code, params } => {
177                assert_eq!(code, 0x4006);
178                assert_eq!(params[0], 100);
179            }
180            _ => panic!("Expected Unknown event"),
181        }
182    }
183}