1use dmx_rdm::consts::{DMX_BAUD, INTER_SLOT_TIME_MILLIS};
9use dmx_rdm::dmx_uart_driver::{
10 DmxRecvUartDriver, DmxRespUartDriver, DmxUartDriver, DmxUartDriverError,
11};
12use libftd2xx::{BitsPerWord, FtStatus, Ftdi, FtdiCommon, Parity, StopBits};
13use std::time::{Duration, SystemTime};
14
15pub struct FtdiDriverConfig {
16 pub latency_timer: Duration,
19}
20
21impl Default for FtdiDriverConfig {
22 fn default() -> Self {
23 Self {
24 latency_timer: Duration::from_millis(2),
26 }
27 }
28}
29
30pub struct FtdiDriver {
31 serial_port: Ftdi,
32 latency_timer_us: u32,
33}
34
35impl FtdiDriver {
36 pub fn new(mut serial_port: Ftdi, config: FtdiDriverConfig) -> Result<Self, FtStatus> {
37 serial_port.set_baud_rate(DMX_BAUD)?;
38 serial_port.set_data_characteristics(BitsPerWord::Bits8, StopBits::Bits2, Parity::No)?;
39 serial_port.set_flow_control_none()?;
40 serial_port.set_timeouts(
41 Duration::from_millis(INTER_SLOT_TIME_MILLIS as u64),
42 Duration::from_secs(1),
43 )?;
44 serial_port.set_latency_timer(config.latency_timer)?;
45
46 Ok(Self {
47 serial_port,
48 latency_timer_us: config.latency_timer.as_micros() as u32,
49 })
50 }
51
52 fn begin_package(&mut self) -> Result<(), FtStatus> {
53 while self.serial_port.status()?.ammount_in_tx_queue != 0 {}
54
55 spin_sleep::sleep(Duration::from_millis(50));
56
57 self.serial_port.set_break_on()?;
58 self.serial_port.set_break_off()?;
59 Ok(())
62 }
63
64 fn check_timeout(&self, requested_timeout_us: u32) -> u32 {
65 if requested_timeout_us == 0 {
67 return 0;
68 }
69
70 if requested_timeout_us < self.latency_timer_us {
71 #[cfg(feature = "log")]
72 log::warn!("Requested timeout ({}µs) is shorter then latency timer ({}µs). This will cause timing issues. Using latency timer to prevent errors.", requested_timeout_us, self.latency_timer_us);
73
74 return self.latency_timer_us;
75 }
76
77 requested_timeout_us
78 }
79}
80
81impl DmxUartDriver for FtdiDriver {
82 type DriverError = FtStatus;
83}
84
85impl DmxRespUartDriver for FtdiDriver {
86 fn write_frames(
87 &mut self,
88 buffer: &[u8],
89 ) -> Result<usize, DmxUartDriverError<Self::DriverError>> {
90 self.begin_package()?;
91 self.write_frames_no_break(buffer)
92 }
93
94 fn write_frames_no_break(
95 &mut self,
96 buffer: &[u8],
97 ) -> Result<usize, DmxUartDriverError<Self::DriverError>> {
98 Ok(self.serial_port.write(buffer)?)
99 }
100}
101
102impl DmxRecvUartDriver for FtdiDriver {
103 fn read_frames(
104 &mut self,
105 buffer: &mut [u8],
106 timeout_us: u32,
107 ) -> Result<usize, DmxUartDriverError<Self::DriverError>> {
108 let start_time = SystemTime::now();
110 let mut break_byte = [0xFFu8; 1];
111
112 let actual_timeout = self.check_timeout(timeout_us);
113
114 while start_time.elapsed().unwrap().as_micros() < actual_timeout as u128 {
115 let bytes_read = self.serial_port.read(&mut break_byte)?;
116 if bytes_read != 0 && break_byte[0] == 0 {
117 return self.read_frames_no_break(buffer, 1);
118 }
119 }
120
121 Err(DmxUartDriverError::TimeoutError)
122 }
123
124 fn read_frames_no_break(
125 &mut self,
126 buffer: &mut [u8],
127 timeout_us: u32,
128 ) -> Result<usize, DmxUartDriverError<Self::DriverError>> {
129 let buffer_size = buffer.len();
130 let mut head = 0;
131
132 let actual_timeout_us = self.check_timeout(timeout_us);
133
134 let mut slot_start = SystemTime::now();
135 while head < buffer_size {
136 let bytes_read = self.serial_port.read(&mut buffer[head..])?;
137 head += bytes_read;
138
139 if head == 0 {
140 if slot_start.elapsed().unwrap().as_micros() < actual_timeout_us as u128 {
141 continue;
142 }
143
144 return Err(DmxUartDriverError::TimeoutError);
145 }
146
147 if bytes_read > 0 {
148 slot_start = SystemTime::now();
149 } else if slot_start.elapsed().unwrap().as_millis() >= INTER_SLOT_TIME_MILLIS as u128 {
150 break;
151 }
152 }
153
154 Ok(head)
155 }
156}