1mod ffi;
7
8use ffi::fw_error_t;
9use ffi::fw_freewili_device_t;
10use std::cell::RefCell;
11use std::collections::HashMap;
12use std::ffi::{CStr, c_char};
13use std::fmt;
14use std::rc::Rc;
15use thiserror::Error;
16
17use ffi::_fw_devicetype_t::*;
18use ffi::_fw_inttype_t::*;
19use ffi::_fw_stringtype_t::*;
20
21use crate::ffi::fw_stringtype_t;
22
23thread_local! {
24 static DEVICE_REGISTRY: RefCell<HashMap<*mut fw_freewili_device_t, Rc<FreeWiliDeviceHandle>>> = RefCell::new(HashMap::new());
25}
26
27#[derive(Error, Debug)]
28pub enum FreeWiliError {
29 #[error("Invalid Parameter")]
31 InvalidParameter,
32 #[error("Invalid device handle")]
34 InvalidDevice,
35 #[error("Internal error{}", .0.as_ref().map(|s| format!(": {s}")).unwrap_or_default())]
37 InternalError(Option<String>),
38 #[error("Memory error")]
40 MemoryError,
41 #[error("No more devices found")]
43 NoMoreDevices,
44 #[error("None")]
46 None,
47}
48
49pub type Result<T> = std::result::Result<T, FreeWiliError>;
50
51impl From<ffi::_fw_error_t> for FreeWiliError {
52 fn from(error: ffi::_fw_error_t) -> Self {
53 match error {
54 ffi::_fw_error_t::fw_error_success => FreeWiliError::None,
55 ffi::_fw_error_t::fw_error_invalid_parameter => FreeWiliError::InvalidParameter,
56 ffi::_fw_error_t::fw_error_invalid_device => FreeWiliError::InvalidDevice,
57 ffi::_fw_error_t::fw_error_internal_error => FreeWiliError::InternalError(None),
58 ffi::_fw_error_t::fw_error_memory => FreeWiliError::MemoryError,
59 ffi::_fw_error_t::fw_error_no_more_devices => FreeWiliError::NoMoreDevices,
60 ffi::_fw_error_t::fw_error_none => FreeWiliError::None,
61 ffi::_fw_error_t::fw_error__maxvalue => FreeWiliError::InternalError(None),
62 }
63 }
64}
65
66impl From<fw_error_t> for FreeWiliError {
67 fn from(error_code: fw_error_t) -> Self {
68 match error_code {
69 x if x == ffi::_fw_error_t::fw_error_success as u32 => FreeWiliError::None,
70 x if x == ffi::_fw_error_t::fw_error_invalid_parameter as u32 => {
71 FreeWiliError::InvalidParameter
72 }
73 x if x == ffi::_fw_error_t::fw_error_invalid_device as u32 => {
74 FreeWiliError::InvalidDevice
75 }
76 x if x == ffi::_fw_error_t::fw_error_internal_error as u32 => {
77 FreeWiliError::InternalError(None)
78 }
79 x if x == ffi::_fw_error_t::fw_error_memory as u32 => FreeWiliError::MemoryError,
80 x if x == ffi::_fw_error_t::fw_error_no_more_devices as u32 => {
81 FreeWiliError::NoMoreDevices
82 }
83 x if x == ffi::_fw_error_t::fw_error_none as u32 => FreeWiliError::None,
84 x if x == ffi::_fw_error_t::fw_error__maxvalue as u32 => {
85 FreeWiliError::InternalError(None)
86 }
87 _ => FreeWiliError::InternalError(Some(format!("Unknown error code: {error_code}"))),
88 }
89 }
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93pub enum UsbDeviceType {
94 Hub,
96 Serial,
98 SerialMain,
100 SerialDisplay,
102 MassStorage,
104 Esp32,
106 Ftdi,
108 Other,
110 _MaxValue,
112}
113
114impl From<ffi::_fw_usbdevicetype_t> for UsbDeviceType {
115 fn from(device_type: ffi::_fw_usbdevicetype_t) -> Self {
116 match device_type {
117 ffi::_fw_usbdevicetype_t::fw_usbdevicetype_hub => UsbDeviceType::Hub,
118 ffi::_fw_usbdevicetype_t::fw_usbdevicetype_serial => UsbDeviceType::Serial,
119 ffi::_fw_usbdevicetype_t::fw_usbdevicetype_serialmain => UsbDeviceType::SerialMain,
120 ffi::_fw_usbdevicetype_t::fw_usbdevicetype_serialdisplay => {
121 UsbDeviceType::SerialDisplay
122 }
123 ffi::_fw_usbdevicetype_t::fw_usbdevicetype_massstorage => UsbDeviceType::MassStorage,
124 ffi::_fw_usbdevicetype_t::fw_usbdevicetype_esp32 => UsbDeviceType::Esp32,
125 ffi::_fw_usbdevicetype_t::fw_usbdevicetype_ftdi => UsbDeviceType::Ftdi,
126 ffi::_fw_usbdevicetype_t::fw_usbdevicetype_other => UsbDeviceType::Other,
127 ffi::_fw_usbdevicetype_t::fw_usbdevicetype__maxvalue => UsbDeviceType::_MaxValue,
128 }
129 }
130}
131
132impl From<ffi::fw_usbdevicetype_t> for UsbDeviceType {
133 fn from(device_type: ffi::fw_usbdevicetype_t) -> Self {
134 match device_type {
135 x if x == ffi::_fw_usbdevicetype_t::fw_usbdevicetype_hub as u32 => UsbDeviceType::Hub,
136 x if x == ffi::_fw_usbdevicetype_t::fw_usbdevicetype_serial as u32 => {
137 UsbDeviceType::Serial
138 }
139 x if x == ffi::_fw_usbdevicetype_t::fw_usbdevicetype_serialmain as u32 => {
140 UsbDeviceType::SerialMain
141 }
142 x if x == ffi::_fw_usbdevicetype_t::fw_usbdevicetype_serialdisplay as u32 => {
143 UsbDeviceType::SerialDisplay
144 }
145 x if x == ffi::_fw_usbdevicetype_t::fw_usbdevicetype_massstorage as u32 => {
146 UsbDeviceType::MassStorage
147 }
148 x if x == ffi::_fw_usbdevicetype_t::fw_usbdevicetype_esp32 as u32 => {
149 UsbDeviceType::Esp32
150 }
151 x if x == ffi::_fw_usbdevicetype_t::fw_usbdevicetype_ftdi as u32 => UsbDeviceType::Ftdi,
152 x if x == ffi::_fw_usbdevicetype_t::fw_usbdevicetype_other as u32 => {
153 UsbDeviceType::Other
154 }
155 x if x == ffi::_fw_usbdevicetype_t::fw_usbdevicetype__maxvalue as u32 => {
156 UsbDeviceType::_MaxValue
157 }
158 _ => UsbDeviceType::Other, }
160 }
161}
162
163#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164pub enum DeviceType {
165 Unknown,
167 Freewili,
169 Defcon2024Badge,
171 Defcon2025FwBadge,
173 Uf2,
175 Winky,
177}
178
179impl From<ffi::_fw_devicetype_t> for DeviceType {
180 fn from(device_type: ffi::_fw_devicetype_t) -> Self {
181 match device_type {
182 ffi::_fw_devicetype_t::fw_devicetype_unknown => DeviceType::Unknown,
183 ffi::_fw_devicetype_t::fw_devicetype_freewili => DeviceType::Freewili,
184 ffi::_fw_devicetype_t::fw_devicetype_defcon2024badge => DeviceType::Defcon2024Badge,
185 ffi::_fw_devicetype_t::fw_devicetype_defcon2025fwbadge => DeviceType::Defcon2025FwBadge,
186 ffi::_fw_devicetype_t::fw_devicetype_uf2 => DeviceType::Uf2,
187 ffi::_fw_devicetype_t::fw_devicetype_winky => DeviceType::Winky,
188 }
189 }
190}
191
192impl From<ffi::fw_devicetype_t> for DeviceType {
193 fn from(device_type: ffi::fw_devicetype_t) -> Self {
194 match device_type {
195 x if x == ffi::_fw_devicetype_t::fw_devicetype_unknown as u32 => DeviceType::Unknown,
196 x if x == ffi::_fw_devicetype_t::fw_devicetype_freewili as u32 => DeviceType::Freewili,
197 x if x == ffi::_fw_devicetype_t::fw_devicetype_defcon2024badge as u32 => {
198 DeviceType::Defcon2024Badge
199 }
200 x if x == ffi::_fw_devicetype_t::fw_devicetype_defcon2025fwbadge as u32 => {
201 DeviceType::Defcon2025FwBadge
202 }
203 x if x == ffi::_fw_devicetype_t::fw_devicetype_uf2 as u32 => DeviceType::Uf2,
204 x if x == ffi::_fw_devicetype_t::fw_devicetype_winky as u32 => DeviceType::Winky,
205 _ => DeviceType::Unknown, }
207 }
208}
209
210#[derive(Debug, Clone)]
211pub struct USBDevice {
212 pub kind: UsbDeviceType,
214 pub kind_name: String,
215
216 pub vid: u16,
218 pub pid: u16,
220 pub name: String,
222 pub serial: String,
224 pub location: u32,
226 pub port_chain: Vec<u32>,
228 pub port: Option<String>,
230 pub path: Option<String>,
232}
233
234impl USBDevice {
235 pub unsafe fn from_device(device: *mut ffi::fw_freewili_device_t) -> Result<Self> {
240 let mut usb_device_type: ffi::fw_usbdevicetype_t =
241 fw_devicetype_unknown as ffi::fw_usbdevicetype_t;
242 let res = unsafe { ffi::fw_usb_device_get_type(device, &mut usb_device_type) };
243 if res != ffi::_fw_error_t::fw_error_success as ffi::fw_error_t {
244 return Err(res.into());
245 }
246
247 let mut usb_device_type_name = vec![0i8; 1024];
248 let mut usb_device_type_name_size: u32 = usb_device_type_name.len() as u32;
249 let res = unsafe {
250 ffi::fw_usb_device_get_type_name(
251 usb_device_type as ffi::fw_usbdevicetype_t,
252 usb_device_type_name.as_mut_ptr(),
253 &mut usb_device_type_name_size,
254 )
255 };
256 if res != ffi::_fw_error_t::fw_error_success as ffi::fw_error_t {
257 return Err(res.into());
258 }
259 let usb_device_type_name =
260 unsafe { CStr::from_ptr(usb_device_type_name.as_ptr() as *const c_char) }
261 .to_string_lossy()
262 .into_owned();
263
264 let mut vid: u32 = 0;
265 let res = unsafe {
266 ffi::fw_usb_device_get_int(device, fw_inttype_vid as u32, &mut vid as *mut u32)
267 };
268 if res != ffi::_fw_error_t::fw_error_success as ffi::fw_error_t {
269 return Err(res.into());
270 }
271
272 let mut pid: u32 = 0;
273 let res = unsafe {
274 ffi::fw_usb_device_get_int(device, fw_inttype_pid as u32, &mut pid as *mut u32)
275 };
276 if res != ffi::_fw_error_t::fw_error_success as ffi::fw_error_t {
277 return Err(res.into());
278 }
279
280 let mut location: u32 = 0;
281 let res = unsafe {
282 ffi::fw_usb_device_get_int(
283 device,
284 fw_inttype_location as u32,
285 &mut location as *mut u32,
286 )
287 };
288 if res != ffi::_fw_error_t::fw_error_success as ffi::fw_error_t {
289 return Err(res.into());
290 }
291
292 let mut name = vec![0i8; 1024];
293 let mut name_size: u32 = name.len() as u32;
294 let res = unsafe {
295 ffi::fw_usb_device_get_str(
296 device,
297 fw_stringtype_name as fw_stringtype_t,
298 name.as_mut_ptr(),
299 &mut name_size,
300 )
301 };
302 if res != ffi::_fw_error_t::fw_error_success as ffi::fw_error_t {
303 return Err(res.into());
304 }
305 let name = unsafe { CStr::from_ptr(name.as_ptr() as *const c_char) }
306 .to_string_lossy()
307 .into_owned();
308
309 let mut serial = vec![0i8; 1024];
310 let mut serial_size: u32 = serial.len() as u32;
311 let res = unsafe {
312 ffi::fw_usb_device_get_str(
313 device,
314 fw_stringtype_serial as fw_stringtype_t,
315 serial.as_mut_ptr(),
316 &mut serial_size,
317 )
318 };
319 if res != ffi::_fw_error_t::fw_error_success as ffi::fw_error_t {
320 return Err(res.into());
321 }
322 let serial = unsafe { CStr::from_ptr(serial.as_ptr() as *const c_char) }
323 .to_string_lossy()
324 .into_owned();
325
326 let mut port = vec![0i8; 1024];
327 let mut port_size: u32 = port.len() as u32;
328 let res = unsafe {
329 ffi::fw_usb_device_get_str(
330 device,
331 fw_stringtype_port as fw_stringtype_t,
332 port.as_mut_ptr(),
333 &mut port_size,
334 )
335 };
336 if res != ffi::_fw_error_t::fw_error_success as ffi::fw_error_t
337 && res != ffi::_fw_error_t::fw_error_none as ffi::fw_error_t
338 {
339 return Err(res.into());
340 }
341 let port = unsafe { CStr::from_ptr(port.as_ptr() as *const c_char) }
342 .to_string_lossy()
343 .into_owned();
344
345 let mut path = vec![0i8; 1024];
346 let mut path_size: u32 = path.len() as u32;
347 let res = unsafe {
348 ffi::fw_usb_device_get_str(
349 device,
350 fw_stringtype_path as fw_stringtype_t,
351 path.as_mut_ptr(),
352 &mut path_size,
353 )
354 };
355 if res != ffi::_fw_error_t::fw_error_success as ffi::fw_error_t
356 && res != ffi::_fw_error_t::fw_error_none as ffi::fw_error_t
357 {
358 return Err(res.into());
359 }
360 let path = unsafe { CStr::from_ptr(path.as_ptr() as *const c_char) }
361 .to_string_lossy()
362 .into_owned();
363
364 let mut port_chain: Vec<u32> = vec![0u32; 10];
365 let mut port_chain_size: u32 = port_chain.len() as u32;
366 let res = unsafe {
367 ffi::fw_usb_device_get_port_chain(device, port_chain.as_mut_ptr(), &mut port_chain_size)
368 };
369 if res != ffi::_fw_error_t::fw_error_success as ffi::fw_error_t {
370 return Err(res.into());
371 }
372 port_chain.resize(port_chain_size as usize, 0);
373
374 let usb_device = USBDevice {
375 kind: usb_device_type.into(),
376 kind_name: usb_device_type_name,
377 vid: vid as u16,
378 pid: pid as u16,
379 name,
380 serial,
381 location,
382 port_chain,
383 port: if port.is_empty() { None } else { Some(port) },
384 path: if path.is_empty() { None } else { Some(path) },
385 };
386
387 Ok(usb_device)
388 }
389}
390
391impl fmt::Display for USBDevice {
392 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393 let type_name = match usb_device_get_type_name(self.kind) {
395 Ok(name) => name,
396 Err(_) => "Unknown".to_string(),
397 };
398
399 write!(f, "{}: {}", type_name, self.name)?;
401
402 if let Some(port) = &self.port {
403 write!(f, ": {port}")?;
404 } else if let Some(path) = &self.path {
405 write!(f, ": {path}")?;
406 }
407
408 Ok(())
409 }
410}
411
412#[derive(Debug, Clone)]
413pub struct FreeWiliDevice {
414 handle: Rc<FreeWiliDeviceHandle>,
416}
417
418#[derive(Debug)]
419struct FreeWiliDeviceHandle {
420 ptr: *mut fw_freewili_device_t,
421}
422
423impl Drop for FreeWiliDeviceHandle {
424 fn drop(&mut self) {
425 let _res: ffi::fw_error_t = unsafe { ffi::fw_device_free(&mut self.ptr, 1) };
426 if _res != ffi::_fw_error_t::fw_error_success as u32 {
427 eprintln!("Failed to free FreeWili device handle: {_res:?}");
428 }
429 }
430}
431
432impl Default for FreeWiliDevice {
433 fn default() -> Self {
434 FreeWiliDevice {
435 handle: Rc::new(FreeWiliDeviceHandle {
436 ptr: std::ptr::null_mut(),
437 }),
438 }
439 }
440}
441
442impl FreeWiliDevice {
443 fn get_or_create_handle(ptr: *mut fw_freewili_device_t) -> Rc<FreeWiliDeviceHandle> {
446 DEVICE_REGISTRY.with(|registry| {
447 let mut registry = registry.borrow_mut();
448
449 if let Some(existing_handle) = registry.get(&ptr) {
451 return existing_handle.clone();
452 }
453
454 let new_handle = Rc::new(FreeWiliDeviceHandle { ptr });
456 registry.insert(ptr, new_handle.clone());
457 new_handle
458 })
459 }
460
461 pub fn find_all() -> Result<Vec<FreeWiliDevice>> {
463 const MAX_DEVICE_COUNT: u32 = 255;
464 let mut device_count: u32 = MAX_DEVICE_COUNT;
465 let mut devices: [*mut fw_freewili_device_t; MAX_DEVICE_COUNT as usize] =
466 [std::ptr::null_mut(); MAX_DEVICE_COUNT as usize];
467 let mut error_msg = vec![0u8; 1024];
468 let mut error_size: u32 = error_msg.len() as u32;
469
470 let res: fw_error_t = unsafe {
471 ffi::fw_device_find_all(
472 devices.as_mut_ptr(),
473 &mut device_count,
474 error_msg.as_mut_ptr() as *mut i8,
475 &mut error_size,
476 )
477 };
478 match res {
479 x if x == ffi::_fw_error_t::fw_error_success as ffi::fw_error_t => {}
480 x if x == ffi::_fw_error_t::fw_error_internal_error as ffi::fw_error_t => {
481 let error_str = unsafe { CStr::from_ptr(error_msg.as_ptr() as *const c_char) }
482 .to_string_lossy()
483 .into_owned();
484 return Err(FreeWiliError::InternalError(Some(error_str)));
485 }
486 _ => return Err(res.into()),
487 }
488
489 let mut device_handles = Vec::with_capacity(device_count as usize);
490 for i in 0..device_count {
491 let device_ptr = devices[i as usize];
492
493 let handle = Self::get_or_create_handle(device_ptr);
495
496 device_handles.push(FreeWiliDevice { handle });
497 }
498 Ok(device_handles)
499 }
500
501 pub fn device_type(&self) -> Result<DeviceType> {
502 let mut device_type: ffi::fw_devicetype_t = 0;
503 let res = unsafe { ffi::fw_device_get_type(self.handle.ptr, &mut device_type) };
504 if res != ffi::_fw_error_t::fw_error_success as u32 {
505 return Err(res.into());
506 }
507
508 Ok(device_type.into())
509 }
510
511 pub fn device_type_name(&self) -> Result<String> {
512 let device_type = self.device_type()? as ffi::fw_devicetype_t;
513
514 device_type_name(device_type)
515 }
516
517 fn get_device_string(&self, string_type: ffi::_fw_stringtype_t) -> Result<String> {
518 let mut buffer = vec![0u8; 1024];
519 let mut buffer_size = buffer.len() as u32;
520
521 let res: fw_error_t = unsafe {
522 ffi::fw_device_get_str(
523 self.handle.ptr,
524 string_type as u32,
525 buffer.as_mut_ptr() as *mut c_char,
526 &mut buffer_size,
527 )
528 };
529 if res != ffi::_fw_error_t::fw_error_success as u32 {
530 return Err(res.into());
531 }
532
533 let cstr = unsafe { CStr::from_ptr(buffer.as_ptr() as *const c_char) };
534 Ok(cstr.to_string_lossy().into_owned())
535 }
536
537 pub fn name(&self) -> Result<String> {
538 self.get_device_string(ffi::_fw_stringtype_t::fw_stringtype_name)
539 }
540
541 pub fn serial(&self) -> Result<String> {
542 self.get_device_string(ffi::_fw_stringtype_t::fw_stringtype_serial)
543 }
544
545 pub fn unique_id(&self) -> Result<u64> {
546 let mut unique_id: u64 = 0;
547 let res = unsafe { ffi::fw_device_unique_id(self.handle.ptr, &mut unique_id as *mut u64) };
548 if res != ffi::_fw_error_t::fw_error_success as u32 {
549 return Err(res.into());
550 }
551 Ok(unique_id)
552 }
553
554 pub fn standalone(&self) -> Result<bool> {
555 let mut is_standalone: bool = false;
556 let res = unsafe {
557 ffi::fw_device_is_standalone(self.handle.ptr, &mut is_standalone as *mut bool)
558 };
559 if res != ffi::_fw_error_t::fw_error_success as u32 {
560 return Err(res.into());
561 }
562 Ok(is_standalone)
563 }
564
565 pub fn usb_device_get_string(&self, string_type: ffi::_fw_stringtype_t) -> Result<String> {
566 let mut buffer = vec![0u8; 1024];
567 let mut buffer_size = buffer.len() as u32;
568
569 let res: fw_error_t = unsafe {
570 ffi::fw_usb_device_get_str(
571 self.handle.ptr,
572 string_type as u32,
573 buffer.as_mut_ptr() as *mut c_char,
574 &mut buffer_size,
575 )
576 };
577 if res != ffi::_fw_error_t::fw_error_success as u32 {
578 return Err(res.into());
579 }
580
581 let cstr = unsafe { CStr::from_ptr(buffer.as_ptr() as *const c_char) };
582 Ok(cstr.to_string_lossy().into_owned())
583 }
584
585 pub fn get_usb_devices(&self) -> Result<Vec<USBDevice>> {
586 let res = unsafe { ffi::fw_usb_device_begin(self.handle.ptr) };
587 if res != ffi::_fw_error_t::fw_error_success as u32 {
588 return Err(res.into());
589 }
590
591 let mut devices = Vec::new();
592 loop {
593 let usb_device = unsafe { USBDevice::from_device(self.handle.ptr)? };
594 devices.push(usb_device);
595
596 let res = unsafe { ffi::fw_usb_device_next(self.handle.ptr) };
597 if res != ffi::_fw_error_t::fw_error_success as u32 {
598 break;
599 }
600 }
601 Ok(devices)
602 }
603
604 pub fn get_main_usb_device(&self) -> Result<USBDevice> {
605 let mut error_msg = vec![0u8; 1024];
606 let mut error_size: u32 = error_msg.len() as u32;
607 let res = unsafe {
608 ffi::fw_usb_device_set(
609 self.handle.ptr,
610 ffi::_fw_usbdevice_iter_set_t::fw_usbdevice_iter_main
611 as ffi::fw_usbdevice_iter_set_t,
612 error_msg.as_mut_ptr() as *mut i8,
613 &mut error_size,
614 )
615 };
616 if res == ffi::_fw_error_t::fw_error_internal_error as fw_error_t {
617 let error_str = unsafe { CStr::from_ptr(error_msg.as_ptr() as *const c_char) }
618 .to_string_lossy()
619 .into_owned();
620 return Err(FreeWiliError::InternalError(Some(error_str)));
621 }
622 if res != ffi::_fw_error_t::fw_error_success as fw_error_t {
623 return Err(res.into());
624 }
625 unsafe { USBDevice::from_device(self.handle.ptr) }
626 }
627
628 pub fn get_display_usb_device(&self) -> Result<USBDevice> {
629 let mut error_msg = vec![0u8; 1024];
630 let mut error_size: u32 = error_msg.len() as u32;
631 let res = unsafe {
632 ffi::fw_usb_device_set(
633 self.handle.ptr,
634 ffi::_fw_usbdevice_iter_set_t::fw_usbdevice_iter_display
635 as ffi::fw_usbdevice_iter_set_t,
636 error_msg.as_mut_ptr() as *mut i8,
637 &mut error_size,
638 )
639 };
640 if res == ffi::_fw_error_t::fw_error_internal_error as fw_error_t {
641 let error_str = unsafe { CStr::from_ptr(error_msg.as_ptr() as *const c_char) }
642 .to_string_lossy()
643 .into_owned();
644 return Err(FreeWiliError::InternalError(Some(error_str)));
645 }
646 if res != ffi::_fw_error_t::fw_error_success as fw_error_t {
647 return Err(res.into());
648 }
649 unsafe { USBDevice::from_device(self.handle.ptr) }
650 }
651
652 pub fn get_fpga_usb_device(&self) -> Result<USBDevice> {
653 let mut error_msg = vec![0u8; 1024];
654 let mut error_size: u32 = error_msg.len() as u32;
655 let res = unsafe {
656 ffi::fw_usb_device_set(
657 self.handle.ptr,
658 ffi::_fw_usbdevice_iter_set_t::fw_usbdevice_iter_fpga
659 as ffi::fw_usbdevice_iter_set_t,
660 error_msg.as_mut_ptr() as *mut i8,
661 &mut error_size,
662 )
663 };
664 if res == ffi::_fw_error_t::fw_error_internal_error as fw_error_t {
665 let error_str = unsafe { CStr::from_ptr(error_msg.as_ptr() as *const c_char) }
666 .to_string_lossy()
667 .into_owned();
668 return Err(FreeWiliError::InternalError(Some(error_str)));
669 }
670 if res != ffi::_fw_error_t::fw_error_success as fw_error_t {
671 return Err(res.into());
672 }
673 unsafe { USBDevice::from_device(self.handle.ptr) }
674 }
675
676 pub fn get_hub_usb_device(&self) -> Result<USBDevice> {
677 let mut error_msg = vec![0u8; 1024];
678 let mut error_size: u32 = error_msg.len() as u32;
679 let res = unsafe {
680 ffi::fw_usb_device_set(
681 self.handle.ptr,
682 ffi::_fw_usbdevice_iter_set_t::fw_usbdevice_iter_hub
683 as ffi::fw_usbdevice_iter_set_t,
684 error_msg.as_mut_ptr() as *mut i8,
685 &mut error_size,
686 )
687 };
688 if res == ffi::_fw_error_t::fw_error_internal_error as fw_error_t {
689 let error_str = unsafe { CStr::from_ptr(error_msg.as_ptr() as *const c_char) }
690 .to_string_lossy()
691 .into_owned();
692 return Err(FreeWiliError::InternalError(Some(error_str)));
693 }
694 if res != ffi::_fw_error_t::fw_error_success as fw_error_t {
695 return Err(res.into());
696 }
697 unsafe { USBDevice::from_device(self.handle.ptr) }
698 }
699}
700
701pub fn device_type_name(device_type: impl Into<DeviceType>) -> Result<String> {
702 let device_type = device_type.into() as ffi::fw_devicetype_t;
703
704 let mut device_type_name = vec![0i8; 1024];
705 let mut device_type_name_size: u32 = device_type_name.len() as u32;
706 let res = unsafe {
707 ffi::fw_device_get_type_name(
708 device_type,
709 device_type_name.as_mut_ptr(),
710 &mut device_type_name_size,
711 )
712 };
713 if res != ffi::_fw_error_t::fw_error_success as ffi::fw_error_t {
714 return Err(res.into());
715 }
716
717 let cstr = unsafe { CStr::from_ptr(device_type_name.as_ptr() as *const c_char) };
718 Ok(cstr.to_string_lossy().into_owned())
719}
720
721pub fn usb_device_get_type_name(usb_device_type: impl Into<UsbDeviceType>) -> Result<String> {
722 let device_type = usb_device_type.into() as ffi::fw_devicetype_t;
723
724 let mut usb_device_type_name = vec![0i8; 1024];
725 let mut usb_device_type_name_size: u32 = usb_device_type_name.len() as u32;
726 let res = unsafe {
727 ffi::fw_usb_device_get_type_name(
728 device_type,
729 usb_device_type_name.as_mut_ptr(),
730 &mut usb_device_type_name_size,
731 )
732 };
733 if res != ffi::_fw_error_t::fw_error_success as ffi::fw_error_t {
734 return Err(res.into());
735 }
736
737 let cstr = unsafe { CStr::from_ptr(usb_device_type_name.as_ptr() as *const c_char) };
738 Ok(cstr.to_string_lossy().into_owned())
739}
740
741impl fmt::Display for FreeWiliDevice {
742 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
743 write!(
744 f,
745 "{} {}",
746 self.name().unwrap_or("Unknown".to_string()),
747 self.serial().unwrap_or("Unknown".to_string())
748 )
749 }
750}
751
752#[cfg(test)]
753mod tests {
754 use super::*;
755
756 #[test]
757 fn test_basic_functionality() -> Result<()> {
758 let devices = FreeWiliDevice::find_all()?;
759
760 for (i, device) in devices.iter().enumerate() {
761 let dev_type = device.device_type()?;
762 let type_name = device.device_type_name()?;
763 let name = device.name()?;
764 let serial = device.serial()?;
765 let unique_id = device.unique_id()?;
766 let standalone = device.standalone()?;
767 let usb_devices = device.get_usb_devices()?;
768
769 println!("{}. Found device: {}", i + 1, device);
770 println!("\ttype: {:?}", dev_type);
771 println!("\ttype name: {}", type_name);
772 println!("\tname: {}", name);
773 println!("\tserial: {}", serial);
774 println!("\tunique ID: {}", unique_id);
775 println!("\tstandalone: {}", standalone);
776 println!("\tUSB devices ({}):", usb_devices.len());
777
778 for (count, usb_device) in usb_devices.iter().enumerate() {
779 println!("\t\t{}: {}", count + 1, usb_device.kind_name);
780 println!("\t\t\tname: {}", usb_device.name);
781 println!("\t\t\tserial: {}", usb_device.serial);
782 println!("\t\t\tVID: {} PID: {}", usb_device.vid, usb_device.pid);
783 println!("\t\t\tlocation: {}", usb_device.location);
784 println!("\t\t\tport chain: {:?}", usb_device.port_chain);
785 if let Some(path) = &usb_device.path {
786 println!("\t\t\tpath: {}", path);
787 }
788 if let Some(port) = &usb_device.port {
789 println!("\t\t\tport: {}", port);
790 }
791 }
792
793 if let Ok(main_usb_device) = device.get_main_usb_device() {
795 println!("\tMain USB device: {}", main_usb_device.kind_name);
796 } else {
797 println!("\tNo main USB device found");
798 }
799
800 if let Ok(display_usb_device) = device.get_display_usb_device() {
801 println!("\tDisplay USB device: {}", display_usb_device.kind_name);
802 } else {
803 println!("\tNo display USB device found");
804 }
805
806 if let Ok(fpga_usb_device) = device.get_fpga_usb_device() {
807 println!("\tFPGA USB device: {}", fpga_usb_device.kind_name);
808 } else {
809 println!("\tNo FPGA USB device found");
810 }
811
812 if let Ok(hub_usb_device) = device.get_hub_usb_device() {
813 println!("\tHUB USB device: {}", hub_usb_device.kind_name);
814 } else {
815 println!("\tNo HUB USB device found");
816 }
817 }
818
819 Ok(())
820 }
821
822 #[test]
823 fn test_handle_copy() -> Result<()> {
824 let devices = FreeWiliDevice::find_all()?;
825
826 if devices.is_empty() {
827 println!("No devices found, skipping handle copy test.");
828 return Ok(());
829 }
830
831 let first_device = devices[0].clone();
832 let devices = FreeWiliDevice::find_all()?;
833
834 first_device.device_type()?;
835 let first_device = first_device;
836 for device in devices.clone() {
837 if device.unique_id()? == first_device.unique_id()? {
838 let _ = device;
839 }
840 }
841 for device in devices.clone() {
842 device.device_type()?;
843 }
844
845 let mut device = &devices[0];
846
847 device.device_type()?;
848
849 let devices = FreeWiliDevice::find_all()?;
850
851 device = &devices[0];
852
853 device.device_type()?;
854
855 Ok(())
856 }
857}