1use std::io::Read;
7use std::sync::Arc;
8
9use crate::U3vError;
10use crate::bootstrap::{Abrm, ManifestEntry, Sbrm, Sirm};
11use crate::control::ControlChannel;
12use crate::usb::UsbTransfer;
13
14const ZIP_MAGIC: &[u8; 4] = b"PK\x03\x04";
16
17fn decompress_if_zip(data: Vec<u8>) -> Result<Vec<u8>, U3vError> {
20 if data.len() < 4 || &data[..4] != ZIP_MAGIC {
21 return Ok(data);
22 }
23 let cursor = std::io::Cursor::new(&data);
24 let mut archive =
25 zip::ZipArchive::new(cursor).map_err(|e| U3vError::Protocol(format!("bad ZIP: {e}")))?;
26 if archive.is_empty() {
27 return Err(U3vError::Protocol("ZIP archive is empty".into()));
28 }
29 let mut file = archive
30 .by_index(0)
31 .map_err(|e| U3vError::Protocol(format!("cannot read ZIP entry: {e}")))?;
32 let mut xml = Vec::with_capacity(file.size() as usize);
33 file.read_to_end(&mut xml)
34 .map_err(|e| U3vError::Protocol(format!("ZIP decompression failed: {e}")))?;
35 Ok(xml)
36}
37
38const INITIAL_MAX_TRANSFER: u32 = 1024;
43
44pub struct U3vDevice<T: UsbTransfer> {
50 control: ControlChannel<T>,
51 abrm: Abrm,
52 sbrm: Sbrm,
53 stream_ep: Option<u8>,
54 event_ep: Option<u8>,
55}
56
57impl<T: UsbTransfer> U3vDevice<T> {
58 pub fn open(
63 transport: Arc<T>,
64 ep_in: u8,
65 ep_out: u8,
66 stream_ep: Option<u8>,
67 event_ep: Option<u8>,
68 ) -> Result<Self, U3vError> {
69 let mut control = ControlChannel::new(
71 Arc::clone(&transport),
72 ep_in,
73 ep_out,
74 INITIAL_MAX_TRANSFER,
75 INITIAL_MAX_TRANSFER,
76 );
77
78 let abrm = Abrm::read_from(&mut control)?;
79 let sbrm = Sbrm::read_from(&mut control, abrm.sbrm_address)?;
80
81 let control = ControlChannel::new(
83 transport,
84 ep_in,
85 ep_out,
86 sbrm.max_cmd_transfer,
87 sbrm.max_ack_transfer,
88 );
89
90 Ok(Self {
91 control,
92 abrm,
93 sbrm,
94 stream_ep,
95 event_ep,
96 })
97 }
98
99 pub fn transport(&self) -> Arc<T> {
101 self.control.transport().clone()
102 }
103
104 pub fn abrm(&self) -> &Abrm {
106 &self.abrm
107 }
108
109 pub fn sbrm(&self) -> &Sbrm {
111 &self.sbrm
112 }
113
114 pub fn read_mem(&mut self, addr: u64, len: usize) -> Result<Vec<u8>, U3vError> {
116 self.control.read_mem(addr, len)
117 }
118
119 pub fn write_mem(&mut self, addr: u64, data: &[u8]) -> Result<(), U3vError> {
121 self.control.write_mem(addr, data)
122 }
123
124 pub fn read_sirm(&mut self) -> Result<Sirm, U3vError> {
126 Sirm::read_from(&mut self.control, self.sbrm.sirm_address)
127 }
128
129 pub fn fetch_xml(&mut self) -> Result<String, U3vError> {
134 let entry = ManifestEntry::read_first(&mut self.control, self.abrm.manifest_table_address)?;
135 let raw = self
136 .control
137 .read_mem(entry.file_address, entry.file_size as usize)?;
138 let xml_bytes = decompress_if_zip(raw)?;
139 String::from_utf8(xml_bytes)
140 .map_err(|e| U3vError::Protocol(format!("XML is not valid UTF-8: {e}")))
141 }
142
143 pub fn stream_ep(&self) -> Option<u8> {
145 self.stream_ep
146 }
147
148 pub fn event_ep(&self) -> Option<u8> {
150 self.event_ep
151 }
152
153 pub fn open_stream(
160 &mut self,
161 payload_size: u64,
162 ) -> Result<crate::stream::U3vStream<T>, U3vError> {
163 let ep = self
164 .stream_ep
165 .ok_or_else(|| U3vError::Protocol("device has no streaming endpoint".into()))?;
166
167 let sirm = self.read_sirm()?;
168 sirm.configure(
169 &mut self.control,
170 payload_size,
171 sirm.max_leader_size,
172 sirm.max_trailer_size,
173 )?;
174 sirm.enable(&mut self.control)?;
175
176 Ok(crate::stream::U3vStream::new(
177 self.control.transport().clone(),
178 ep,
179 sirm.max_leader_size as usize,
180 sirm.max_trailer_size as usize,
181 payload_size as usize,
182 ))
183 }
184
185 pub fn stop_stream(&mut self) -> Result<(), U3vError> {
187 let sirm = self.read_sirm()?;
188 sirm.disable(&mut self.control)
189 }
190}
191
192#[cfg(feature = "usb")]
197impl U3vDevice<crate::usb::RusbTransfer> {
198 pub fn open_device(info: &crate::discovery::U3vDeviceInfo) -> Result<Self, U3vError> {
201 use rusb::UsbContext;
202 let context = rusb::Context::new().map_err(|e| U3vError::Usb(e.to_string()))?;
203 let devices = context
204 .devices()
205 .map_err(|e| U3vError::Usb(e.to_string()))?;
206
207 let device = devices
208 .iter()
209 .find(|d| d.bus_number() == info.bus && d.address() == info.address)
210 .ok_or_else(|| {
211 U3vError::Usb(format!(
212 "device not found at bus={} addr={}",
213 info.bus, info.address
214 ))
215 })?;
216
217 let handle = device.open().map_err(|e| U3vError::Usb(e.to_string()))?;
218
219 let iface = &info.interface_info;
221 handle
222 .claim_interface(iface.control_iface)
223 .map_err(|e| U3vError::Usb(format!("claim control interface: {e}")))?;
224 if let Some(si) = iface.stream_iface {
225 let _ = handle.claim_interface(si);
226 }
227 if let Some(ei) = iface.event_iface {
228 let _ = handle.claim_interface(ei);
229 }
230
231 let transport = Arc::new(crate::usb::RusbTransfer::new(Arc::new(handle)));
232 Self::open(
233 transport,
234 iface.control_ep_in,
235 iface.control_ep_out,
236 iface.stream_ep_in,
237 iface.event_ep_in,
238 )
239 }
240}
241
242#[cfg(test)]
247mod tests {
248 use super::*;
249 use crate::usb::MockUsbTransfer;
250 use bytes::{BufMut, BytesMut};
251
252 const EP_OUT: u8 = 0x01;
253 const EP_IN: u8 = 0x81;
254 const ACK_PREFIX_LE: u32 = 0x4356_3341;
255 const PREFIX_SIZE: usize = 12;
256
257 fn success_ack(request_id: u16, payload: &[u8]) -> Vec<u8> {
258 let mut buf = BytesMut::with_capacity(PREFIX_SIZE + payload.len());
259 buf.put_u32_le(ACK_PREFIX_LE);
260 buf.put_u16_le(0x0000); buf.put_u16_le(0x0085); buf.put_u16_le(payload.len() as u16);
263 buf.put_u16_le(request_id);
264 buf.extend_from_slice(payload);
265 buf.to_vec()
266 }
267
268 fn enqueue_bootstrap_responses(mock: &MockUsbTransfer, sbrm_addr: u64) -> u16 {
271 let mut req: u16 = 0;
272
273 mock.enqueue_read(EP_IN, success_ack(req, &0x0001_0000u32.to_be_bytes()));
276 req += 1;
277 let mut s = vec![0u8; 64];
279 s[..4].copy_from_slice(b"Test");
280 mock.enqueue_read(EP_IN, success_ack(req, &s));
281 req += 1;
282 s = vec![0u8; 64];
284 s[..7].copy_from_slice(b"MockCam");
285 mock.enqueue_read(EP_IN, success_ack(req, &s));
286 req += 1;
287 mock.enqueue_read(EP_IN, success_ack(req, &[0u8; 64]));
289 req += 1;
290 mock.enqueue_read(EP_IN, success_ack(req, &[0u8; 64]));
292 req += 1;
293 mock.enqueue_read(EP_IN, success_ack(req, &[0u8; 64]));
295 req += 1;
296 mock.enqueue_read(EP_IN, success_ack(req, &[0u8; 64]));
298 req += 1;
299 mock.enqueue_read(EP_IN, success_ack(req, &0x0005_0000u64.to_be_bytes()));
301 req += 1;
302 mock.enqueue_read(EP_IN, success_ack(req, &sbrm_addr.to_be_bytes()));
304 req += 1;
305 mock.enqueue_read(EP_IN, success_ack(req, &0u64.to_be_bytes()));
307 req += 1;
308
309 mock.enqueue_read(EP_IN, success_ack(req, &0x0001_0000u32.to_be_bytes()));
312 req += 1;
313 mock.enqueue_read(EP_IN, success_ack(req, &2048u32.to_be_bytes()));
315 req += 1;
316 mock.enqueue_read(EP_IN, success_ack(req, &2048u32.to_be_bytes()));
318 req += 1;
319 mock.enqueue_read(EP_IN, success_ack(req, &1u32.to_be_bytes()));
321 req += 1;
322 mock.enqueue_read(EP_IN, success_ack(req, &0x0002_0000u64.to_be_bytes()));
324 req += 1;
325 mock.enqueue_read(EP_IN, success_ack(req, &256u32.to_be_bytes()));
327 req += 1;
328 mock.enqueue_read(EP_IN, success_ack(req, &0x0003_0000u64.to_be_bytes()));
330 req += 1;
331 mock.enqueue_read(EP_IN, success_ack(req, &64u32.to_be_bytes()));
333 req += 1;
334
335 req
336 }
337
338 #[test]
339 fn open_device_reads_bootstrap() {
340 let mock = Arc::new(MockUsbTransfer::new());
341 let sbrm_addr: u64 = 0x0001_0000;
342 enqueue_bootstrap_responses(&mock, sbrm_addr);
343
344 let dev = U3vDevice::open(Arc::clone(&mock), EP_IN, EP_OUT, Some(0x82), None).unwrap();
345
346 assert_eq!(dev.abrm().manufacturer_name, "Test");
347 assert_eq!(dev.sbrm().max_cmd_transfer, 2048);
348 assert_eq!(dev.sbrm().max_ack_transfer, 2048);
349 assert_eq!(dev.sbrm().num_stream_channels, 1);
350 assert_eq!(dev.stream_ep(), Some(0x82));
351 assert_eq!(dev.event_ep(), None);
352 }
353
354 #[test]
355 fn fetch_xml_from_manifest() {
356 let mock = Arc::new(MockUsbTransfer::new());
357 let sbrm_addr: u64 = 0x0001_0000;
358 enqueue_bootstrap_responses(&mock, sbrm_addr);
359
360 let mut dev = U3vDevice::open(Arc::clone(&mock), EP_IN, EP_OUT, None, None).unwrap();
361
362 let mut req: u16 = 0;
364
365 mock.enqueue_read(EP_IN, success_ack(req, &1u32.to_be_bytes()));
367 req += 1;
368
369 let xml_addr: u64 = 0x0010_0000;
371 let xml_content = b"<RegisterDescription />";
372 let xml_size = xml_content.len() as u64;
373 let mut entry_data = BytesMut::with_capacity(24);
374 entry_data.put_u64(0); entry_data.put_u64(xml_addr);
376 entry_data.put_u64(xml_size);
377 mock.enqueue_read(EP_IN, success_ack(req, &entry_data));
378 req += 1;
379
380 mock.enqueue_read(EP_IN, success_ack(req, xml_content));
382
383 let xml = dev.fetch_xml().unwrap();
384 assert_eq!(xml, "<RegisterDescription />");
385 }
386}