1use std::str::FromStr;
7use std::time::{Duration, SystemTime};
8
9use bitflags::bitflags;
10use byteorder::{ByteOrder, BE, LE};
11use log::{debug, error, trace};
12
13use rusb::{
14 Context as UsbContext, Device as UsbDevice, DeviceDescriptor, DeviceHandle, Direction,
15 TransferType,
16};
17
18use embedded_hal::spi::{Mode as SpiMode, Phase, Polarity, MODE_0};
19
20use crate::Error;
21
22#[derive(Debug, Clone, PartialEq)]
23pub struct Info {
24 manufacturer: String,
25 product: String,
26 serial: String,
27}
28
29#[derive(Debug, PartialEq, Clone, Copy)]
31pub enum Commands {
32 GetClockDivider = 0x46,
33 GetEventCounter = 0x44,
34 GetFullThreshold = 0x34,
35 GetGpioChipSelect = 0x24,
36 GetGpioModeAndLevel = 0x22,
37 GetGpioValues = 0x20,
38 GetRtrState = 0x36,
39 GetSpiWord = 0x30,
40 GetSpiDelay = 0x32,
41 GetReadOnlyVersion = 0x11,
42 ResetDevice = 0x10,
43 SetClockDivider = 0x47,
44 SetEventCOunter = 0x45,
45 SetFullThreshold = 0x35,
46 SetGpioChipSelect = 0x25,
47 SetGpioModeAndLevel = 0x23,
48 SetGpioValues = 0x21,
49 SetRtrStop = 0x37,
50 SetSpiWord = 0x31,
51 SetSpiDelay = 0x33,
52}
53
54pub const VID: u16 = 0x10c4;
56
57pub const PID: u16 = 0x87a0;
59
60bitflags!(
61 pub struct RequestType: u8 {
63 const HOST_TO_DEVICE = 0b0000_0000;
64 const DEVICE_TO_HOST = 0b1000_0000;
65
66 const TYPE_STANDARD = 0b0000_0000;
67 const TYPE_CLASS = 0b0010_0000;
68 const TYPE_VENDOR = 0b0100_0000;
69
70 const RECIPIENT_DEVICE = 0b0000_0000;
71 const RECIPIENT_INTERFACE = 0b0000_0001;
72 const RECIPIENT_ENDPOINT = 0b0000_0010;
73 const RECIPIENT_OTHER = 0b0000_0011;
74 }
75);
76
77bitflags!(
78 pub struct GpioLevels: u16 {
81 const GPIO_10 = (1 << 14);
82 const GPIO_9 = (1 << 13);
83 const GPIO_8 = (1 << 12);
84 const GPIO_7 = (1 << 11);
85 const GPIO_6 = (1 << 10);
86 const GPIO_5 = (1 << 8);
87
88 const GPIO_4 = (1 << 7);
89 const GPIO_3 = (1 << 6);
90 const GPIO_2 = (1 << 5);
91 const GPIO_1 = (1 << 4);
92 const GPIO_0 = (1 << 3);
93 }
94);
95
96#[derive(Debug, PartialEq, Clone, Copy)]
98pub enum GpioMode {
99 Input = 0x00,
100 OpenDrain = 0x01,
101 PushPull = 0x02,
102}
103
104impl FromStr for GpioMode {
105 type Err = String;
106
107 fn from_str(s: &str) -> Result<Self, Self::Err> {
108 match s {
109 "input" => Ok(Self::Input),
110 "open-drain" => Ok(Self::OpenDrain),
111 "push-pull" => Ok(Self::PushPull),
112 _ => Err(format!(
113 "Unrecognised GPIO mode, try 'input', 'open-drain', or 'push-pull'"
114 )),
115 }
116 }
117}
118
119#[derive(Debug, PartialEq, Clone, Copy)]
121pub enum GpioLevel {
122 Low = 0x00,
123 High = 0x01,
124}
125
126impl FromStr for GpioLevel {
127 type Err = String;
128
129 fn from_str(s: &str) -> Result<Self, Self::Err> {
130 match s {
131 "1" | "true" | "high" => Ok(Self::High),
132 "0" | "false" | "low" => Ok(Self::Low),
133 _ => Err(format!("Unrecognised GPIO level, try 'high' or 'low'")),
134 }
135 }
136}
137
138#[derive(Debug, PartialEq, Clone)]
140pub enum TransferCommand {
141 Read = 0x00,
142 Write = 0x01,
143 WriteRead = 0x02,
144 ReadWithRTR = 0x04,
145}
146
147pub(crate) struct Inner {
150 _device: UsbDevice<UsbContext>,
151 handle: DeviceHandle<UsbContext>,
152 endpoints: Endpoints,
153
154 pub(crate) gpio_allocated: [bool; 11],
155 spi_clock: SpiClock,
156}
157
158#[derive(Debug)]
161struct Endpoints {
162 _control: Endpoint,
163 read: Endpoint,
164 write: Endpoint,
165}
166
167#[derive(Debug, PartialEq, Clone)]
169struct Endpoint {
170 config: u8,
171 iface: u8,
172 setting: u8,
173 address: u8,
174}
175
176#[derive(Debug, PartialEq, Clone)]
178#[cfg_attr(feature = "clap", derive(clap::Parser))]
179pub struct UsbOptions {
180 #[cfg_attr(feature = "clap", clap(long))]
181 pub detach_kernel_driver: bool,
183
184 #[cfg_attr(feature = "clap", clap(long))]
185 pub claim_interface: bool,
187}
188
189impl Default for UsbOptions {
190 fn default() -> Self {
192 Self {
193 #[cfg(target_os = "linux")]
194 detach_kernel_driver: true,
195 #[cfg(target_os = "windows")]
196 detach_kernel_driver: false,
197 #[cfg(target_os = "macos")]
198 detach_kernel_driver: true,
199
200 #[cfg(target_os = "linux")]
201 claim_interface: false,
202 #[cfg(target_os = "windows")]
203 claim_interface: true,
204 #[cfg(target_os = "macos")]
205 claim_interface: true,
206 }
207 }
208}
209
210impl Inner {
211 pub fn new(
213 device: UsbDevice<UsbContext>,
214 descriptor: DeviceDescriptor,
215 opts: UsbOptions,
216 ) -> Result<(Self, Info), Error> {
217 let timeout = Duration::from_millis(200);
218
219 let mut handle = match device.open() {
221 Ok(v) => v,
222 Err(e) => {
223 error!("Opening device: {}", e);
224 return Err(Error::Usb(e));
225 }
226 };
227
228 handle.reset()?;
230
231 let languages = handle.read_languages(timeout)?;
233 let active_config = handle.active_configuration()?;
234
235 trace!("Active configuration: {}", active_config);
236 trace!("Languages: {:?}", languages);
237
238 if languages.len() == 0 {
240 return Err(Error::NoLanguages);
241 }
242
243 let language = languages[0];
245 let manufacturer = handle.read_manufacturer_string(language, &descriptor, timeout)?;
246 let product = handle.read_product_string(language, &descriptor, timeout)?;
247 let serial = handle.read_serial_number_string(language, &descriptor, timeout)?;
248 let info = Info {
249 manufacturer,
250 product,
251 serial,
252 };
253
254 if descriptor.num_configurations() != 1 {
256 error!("Unexpected number of configurations");
257 return Err(Error::Configurations);
258 }
259
260 let config_desc = device.config_descriptor(0)?;
262
263 let (mut write, mut read) = (None, None);
264
265 for interface in config_desc.interfaces() {
266 for interface_desc in interface.descriptors() {
267 for endpoint_desc in interface_desc.endpoint_descriptors() {
268 let e = Endpoint {
270 config: config_desc.number(),
271 iface: interface_desc.interface_number(),
272 setting: interface_desc.setting_number(),
273 address: endpoint_desc.address(),
274 };
275
276 trace!("Endpoint: {:?}", e);
277
278 match (endpoint_desc.transfer_type(), endpoint_desc.direction()) {
280 (TransferType::Bulk, Direction::In) => read = Some(e),
281 (TransferType::Bulk, Direction::Out) => write = Some(e),
282 (_, _) => continue,
283 }
284 }
285 }
286 }
287
288 let control = Endpoint {
290 config: 1,
291 iface: 0,
292 setting: 0,
293 address: 0,
294 };
295 if opts.detach_kernel_driver {
300 debug!("Checking for active kernel driver");
301 match handle.kernel_driver_active(control.iface)? {
302 true => {
303 debug!("Detaching kernel driver");
304 handle.detach_kernel_driver(control.iface)?;
305 }
306 false => {
307 debug!("Kernel driver inactive");
308 }
309 }
310 } else {
311 debug!("Skipping kernel driver attach check");
312 }
313
314 if opts.claim_interface {
316 debug!("Claiming device interface");
317 handle.claim_interface(control.iface)?;
318 } else {
319 debug!("Skipping claim device interface");
320 }
321
322 let write = match write {
324 Some(c) => c,
325 None => {
326 error!("No write endpoint found");
327 return Err(Error::Endpoint);
328 }
329 };
330 handle.set_active_configuration(write.config)?;
331
332 let read = match read {
333 Some(c) => c,
334 None => {
335 error!("No read endpoint found");
336 return Err(Error::Endpoint);
337 }
338 };
339 handle.set_active_configuration(read.config)?;
340
341 let endpoints = Endpoints {
343 _control: control,
344 write,
345 read,
346 };
347 Ok((
348 Inner {
349 _device: device,
350 handle,
351 endpoints,
352 gpio_allocated: [false; 11],
353 spi_clock: SpiClock::Clock12Mhz,
354 },
355 info,
356 ))
357 }
358}
359
360#[derive(Debug, PartialEq, Copy, Clone)]
362pub enum SpiClock {
363 Clock12Mhz,
364 Clock6MHz,
365 Clock3MHz,
366 Clock1_5MHz,
367 Clock750KHz,
368 Clock375MHz,
369}
370
371pub const SPI_OP_DELAY_US: u64 = 100;
373
374impl SpiClock {
375 pub fn freq(&self) -> u64 {
376 match self {
377 SpiClock::Clock12Mhz => 12_000_000,
378 SpiClock::Clock6MHz => 6_000_000,
379 SpiClock::Clock3MHz => 3_000_000,
380 SpiClock::Clock1_5MHz => 1_500_000,
381 SpiClock::Clock750KHz => 750_000,
382 SpiClock::Clock375MHz => 375_000,
383 }
384 }
385
386 pub fn transfer_time(&self, len_bytes: u64) -> std::time::Duration {
387 let micros = len_bytes * 8 * 1_000_000 / self.freq();
388 Duration::from_micros(micros + SPI_OP_DELAY_US)
389 }
390}
391
392impl std::convert::TryFrom<usize> for SpiClock {
393 type Error = Error;
394
395 fn try_from(v: usize) -> Result<Self, Self::Error> {
396 match v {
397 12_000_000 => Ok(SpiClock::Clock12Mhz),
398 6_000_000 => Ok(SpiClock::Clock6MHz),
399 3_000_000 => Ok(SpiClock::Clock3MHz),
400 1_500_000 => Ok(SpiClock::Clock1_5MHz),
401 750_000 => Ok(SpiClock::Clock750KHz),
402 375_000 => Ok(SpiClock::Clock375MHz),
403 _ => Err(Error::InvalidBaud),
404 }
405 }
406}
407
408#[derive(Debug, PartialEq, Clone)]
410pub enum CsMode {
411 Disabled = 0x00,
413 Enabled = 0x01,
415 Exclusive = 0x02,
418}
419
420pub const CPOL_TRAILING: u8 = 0 << 5;
421
422bitflags!(
423 pub struct DelayMask: u8 {
425 const CS_TOGGLE = 1 << 3;
426 const PRE_DEASSERT = 1 << 2;
427 const POST_ASSERT = 1 << 1;
428 const INTER_BYE = 1 << 0;
429 }
430);
431
432#[derive(Debug, PartialEq, Clone)]
433pub struct SpiDelays {
434 mask: DelayMask,
435 pre_deassert: u8,
436 post_assert: u8,
437 inter_byte: u8,
438}
439
440#[derive(PartialEq, Clone)]
441pub struct SpiConfig {
442 pub clock: SpiClock,
443 pub spi_mode: SpiMode,
444 pub cs_mode: CsMode,
445 pub cs_pin_mode: GpioMode,
446 pub delays: SpiDelays,
447}
448
449impl Default for SpiConfig {
450 fn default() -> Self {
451 Self {
452 clock: SpiClock::Clock3MHz,
453 spi_mode: MODE_0,
454 cs_mode: CsMode::Disabled,
455 cs_pin_mode: GpioMode::PushPull,
456 delays: SpiDelays {
457 mask: DelayMask::empty(),
458 pre_deassert: 0,
459 post_assert: 0,
460 inter_byte: 0,
461 },
462 }
463 }
464}
465
466impl Inner {
467 pub(crate) fn spi_configure(&mut self, channel: u8, config: SpiConfig) -> Result<(), Error> {
468 debug!(
469 "Setting SPI channel: {:?} clock: {:?} cs mode: {:?}",
470 channel, config.clock, config.cs_mode
471 );
472
473 self.set_spi_word(channel, config.clock, config.spi_mode, config.cs_pin_mode)?;
475
476 self.set_gpio_chip_select(channel, config.cs_mode)?;
478
479 self.set_spi_delay(channel, config.delays)?;
481
482 Ok(())
483 }
484
485 pub(crate) fn set_spi_word(
486 &mut self,
487 channel: u8,
488 clock: SpiClock,
489 spi_mode: SpiMode,
490 cs_pin_mode: GpioMode,
491 ) -> Result<(), Error> {
492 let mut flags = 0;
493
494 if let Phase::CaptureOnSecondTransition = spi_mode.phase {
495 flags |= 1 << 5;
496 }
497
498 if let Polarity::IdleHigh = spi_mode.polarity {
499 flags |= 1 << 4;
500 };
501
502 if let GpioMode::PushPull = cs_pin_mode {
503 flags |= 1 << 3
504 }
505
506 flags |= (clock as u8) & 0b0111;
507
508 debug!("Set SPI word: 0x{:02x?}", flags);
509
510 let cmd = [channel, flags];
511
512 self.handle.write_control(
513 (RequestType::HOST_TO_DEVICE | RequestType::TYPE_VENDOR).bits(),
514 Commands::SetSpiWord as u8,
515 0,
516 0,
517 &cmd,
518 Duration::from_millis(200),
519 )?;
520
521 self.spi_clock = clock;
522
523 Ok(())
524 }
525
526 pub(crate) fn reset(&mut self) -> Result<(), Error> {
527 self.handle.write_control(
528 (RequestType::HOST_TO_DEVICE | RequestType::TYPE_VENDOR).bits(),
529 Commands::ResetDevice as u8,
530 0,
531 0,
532 &[],
533 Duration::from_millis(200),
534 )?;
535
536 Ok(())
537 }
538
539 pub(crate) fn set_spi_delay(&mut self, channel: u8, delays: SpiDelays) -> Result<(), Error> {
540 let cmd = [
541 channel,
542 delays.mask.bits(),
543 delays.inter_byte,
544 delays.post_assert,
545 delays.pre_deassert,
546 ];
547
548 self.handle.write_control(
549 (RequestType::HOST_TO_DEVICE | RequestType::TYPE_VENDOR).bits(),
550 Commands::SetSpiDelay as u8,
551 0,
552 0,
553 &cmd,
554 Duration::from_millis(200),
555 )?;
556
557 Ok(())
558 }
559
560 pub(crate) fn set_gpio_chip_select(
561 &mut self,
562 channel: u8,
563 cs_mode: CsMode,
564 ) -> Result<(), Error> {
565 let cmd = [channel, cs_mode as u8];
566
567 self.handle.write_control(
568 (RequestType::HOST_TO_DEVICE | RequestType::TYPE_VENDOR).bits(),
569 Commands::SetGpioChipSelect as u8,
570 0,
571 0,
572 &cmd,
573 Duration::from_millis(200),
574 )?;
575
576 Ok(())
577 }
578
579 pub(crate) fn spi_read(&mut self, buff: &mut [u8]) -> Result<usize, Error> {
581 let mut cmd = [0u8; 8];
582 cmd[2] = TransferCommand::Read as u8;
583 LE::write_u32(&mut cmd[4..], buff.len() as u32);
584
585 trace!("SPI read (cmd: {:?})", cmd);
586
587 self.handle.write_bulk(
588 self.endpoints.write.address,
589 &cmd,
590 Duration::from_millis(200),
591 )?;
592
593 let mut index = 0;
595
596 while index < buff.len() {
597 let remainder = if buff.len() > index + 64 {
598 64
599 } else {
600 buff.len() - index
601 };
602
603 debug!("SPI read (i: {}, rem: {})", index, remainder);
604
605 let n = self.handle.read_bulk(
606 self.endpoints.read.address,
607 &mut buff[index..index + remainder],
608 Duration::from_millis(200),
609 )?;
610
611 index += n;
612 }
613
614 trace!("SPI read done");
615
616 Ok(index)
617 }
618
619 pub(crate) fn spi_write(&mut self, buff: &[u8]) -> Result<(), Error> {
621 let mut cmd = vec![0u8; buff.len() + 8];
622
623 cmd[2] = TransferCommand::Write as u8;
624 LE::write_u32(&mut cmd[4..], buff.len() as u32);
625 (&mut cmd[8..]).copy_from_slice(buff);
626
627 let t = self.spi_clock.transfer_time(buff.len() as u64);
628 trace!("SPI write (cmd: {:?} time: {} us)", cmd, t.as_micros());
629
630 self.handle.write_bulk(
631 self.endpoints.write.address,
632 &cmd,
633 Duration::from_millis(200),
634 )?;
635
636 self.delay(t);
639
640 trace!("SPI write done");
643
644 Ok(())
645 }
646
647 fn delay(&mut self, d: Duration) {
648 let n = SystemTime::now();
649 while n.elapsed().unwrap() < d {}
650 }
651
652 pub(crate) fn spi_write_read(
654 &mut self,
655 buff_out: &[u8],
656 buff_in: &mut [u8],
657 ) -> Result<usize, Error> {
658 let mut cmd = vec![0u8; buff_out.len() + 8];
659
660 cmd[2] = TransferCommand::WriteRead as u8;
663 LE::write_u32(&mut cmd[4..], buff_out.len() as u32);
664 (&mut cmd[8..]).copy_from_slice(buff_out);
665
666 let total_time = self.spi_clock.transfer_time(buff_out.len() as u64);
667 trace!(
668 "SPI transfer (cmd: {:?} time: {} us)",
669 cmd,
670 total_time.as_micros()
671 );
672
673 self.handle.write_bulk(
674 self.endpoints.write.address,
675 &cmd,
676 Duration::from_millis(200),
677 )?;
678
679 trace!("SPI transfer await resp");
680
681 let mut index = 0;
682
683 while index < buff_in.len() {
684 let remainder = if buff_in.len() > index + 64 {
685 64
686 } else {
687 buff_in.len() - index
688 };
689
690 let t = self.spi_clock.transfer_time(buff_out.len() as u64);
691
692 trace!(
693 "SPI read (len: {}, index: {}, rem: {}, time: {} us)",
694 buff_in.len(),
695 index,
696 remainder,
697 t.as_micros()
698 );
699
700 let n = self.handle.read_bulk(
701 self.endpoints.read.address,
702 &mut buff_in[index..index + remainder],
703 Duration::from_millis(200),
704 )?;
705
706 index += n;
707
708 self.delay(t);
710 }
711
712 trace!("SPI transfer done");
713
714 Ok(index)
715 }
716
717 pub(crate) fn version(&mut self) -> Result<u16, Error> {
719 let mut buff = [0u8; 2];
720
721 self.handle.read_control(
722 (RequestType::DEVICE_TO_HOST | RequestType::TYPE_VENDOR).bits(),
723 Commands::GetReadOnlyVersion as u8,
724 0,
725 0,
726 &mut buff,
727 Duration::from_millis(200),
728 )?;
729
730 let version = LE::read_u16(&buff);
731
732 Ok(version)
733 }
734
735 pub(crate) fn set_gpio_mode_level(
737 &mut self,
738 pin: u8,
739 mode: GpioMode,
740 level: GpioLevel,
741 ) -> Result<(), Error> {
742 assert!(pin <= 10);
743
744 let cmd = [pin, mode as u8, level as u8];
745
746 trace!(
747 "GPIO set pin: {} mode: {:?} level: {:?} (cmd: {:?})",
748 pin,
749 mode,
750 level,
751 cmd
752 );
753
754 self.handle.write_control(
755 (RequestType::HOST_TO_DEVICE | RequestType::TYPE_VENDOR).bits(),
756 Commands::SetGpioModeAndLevel as u8,
757 0,
758 0,
759 &cmd,
760 Duration::from_millis(200),
761 )?;
762
763 Ok(())
764 }
765
766 pub(crate) fn get_gpio_values(&mut self) -> Result<GpioLevels, Error> {
768 let mut buff = [0u8; 2];
769
770 self.handle.read_control(
771 (RequestType::DEVICE_TO_HOST | RequestType::TYPE_VENDOR).bits(),
772 Commands::GetGpioValues as u8,
773 0,
774 0,
775 &mut buff,
776 Duration::from_millis(200),
777 )?;
778
779 let values = GpioLevels::from_bits_truncate(BE::read_u16(&buff));
781
782 trace!("GPIO get pins (values: {:?})", values);
783
784 Ok(values)
785 }
786
787 pub(crate) fn get_gpio_level(&mut self, pin: u8) -> Result<bool, Error> {
789 assert!(pin <= 10);
790
791 let levels = self.get_gpio_values()?;
792
793 let v = match pin {
794 0 => levels.contains(GpioLevels::GPIO_0),
795 1 => levels.contains(GpioLevels::GPIO_1),
796 2 => levels.contains(GpioLevels::GPIO_2),
797 3 => levels.contains(GpioLevels::GPIO_3),
798 4 => levels.contains(GpioLevels::GPIO_4),
799 5 => levels.contains(GpioLevels::GPIO_5),
800 6 => levels.contains(GpioLevels::GPIO_6),
801 7 => levels.contains(GpioLevels::GPIO_7),
802 8 => levels.contains(GpioLevels::GPIO_8),
803 9 => levels.contains(GpioLevels::GPIO_9),
804 10 => levels.contains(GpioLevels::GPIO_10),
805 _ => panic!("invalid pin {}", pin),
806 };
807
808 Ok(v)
809 }
810}