Skip to main content

mtp_rs/mtp/
event.rs

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