1use hal::digital::v2::{InputPin, OutputPin};
2use usb_device::{class_prelude::*, control::RequestType};
3
4use crate::class::{BlasterClass, FTDI_MODEM_STA_DUMMY};
5use crate::port::Port;
6
7const BLASTER_WRITE_SIZE: usize = 64;
10const BLASTER_READ_SIZE: usize = 32;
11
12pub struct Blaster<
14 'a,
15 B: UsbBus,
16 E,
17 TDI: OutputPin<Error = E>,
18 TCK: OutputPin<Error = E>,
19 TMS: OutputPin<Error = E>,
20 TDO: InputPin<Error = E>,
21> {
22 class: BlasterClass<'a, B>,
23 port: Port<E, TDI, TCK, TMS, TDO>,
24 send_buffer: [u8; BLASTER_WRITE_SIZE],
25 send_len: usize,
26 recv_buffer: [u8; BLASTER_READ_SIZE],
27 recv_len: usize,
28}
29
30impl<
31 'a,
32 B: UsbBus,
33 E,
34 TDI: OutputPin<Error = E>,
35 TCK: OutputPin<Error = E>,
36 TMS: OutputPin<Error = E>,
37 TDO: InputPin<Error = E>,
38 > Blaster<'a, B, E, TDI, TCK, TMS, TDO>
39{
40 pub fn new(
43 alloc: &'a UsbBusAllocator<B>,
44 tdi: TDI,
45 tck: TCK,
46 tms: TMS,
47 tdo: TDO,
48 ) -> Blaster<'a, B, E, TDI, TCK, TMS, TDO> {
49 let mut blaster = Blaster {
50 class: BlasterClass::new(alloc, BLASTER_WRITE_SIZE as u16, BLASTER_READ_SIZE as u16),
51 port: Port::new(tdi, tck, tms, tdo),
52 send_buffer: [0u8; BLASTER_WRITE_SIZE],
53 send_len: 0,
54 recv_buffer: [0u8; BLASTER_READ_SIZE],
55 recv_len: 0,
56 };
57 blaster.send_buffer[0] = FTDI_MODEM_STA_DUMMY[0];
58 blaster.send_buffer[1] = FTDI_MODEM_STA_DUMMY[1];
59 blaster
60 }
61
62 pub fn read(&mut self) -> usb_device::Result<usize> {
64 if self.recv_len == self.recv_buffer.len() {
65 return Err(UsbError::WouldBlock);
66 }
67 let amount = self.class.read(&mut self.recv_buffer[self.recv_len..])?;
68 self.recv_len += amount;
69 Ok(amount)
70 }
71
72 pub fn write(&mut self, heartbeat: bool) -> usb_device::Result<usize> {
77 if self.send_len == 0 && !heartbeat {
78 return Err(UsbError::WouldBlock);
79 }
80 let res = self.class.write(&self.send_buffer[..self.send_len + 2]);
81 if res.is_ok() {
82 let amount = *res.as_ref().unwrap();
83 if amount <= 2 {
84 if amount == 1 {
85 panic!("Cannot recover from half-sent status");
87 }
88 } else {
89 self.send_buffer
90 .copy_within((amount)..(self.send_len + 2), 2);
91 let actual_amount = amount - 2;
92 self.send_len -= actual_amount;
93 }
94 }
95 res
96 }
97
98 pub fn handle(&mut self) -> Result<(), E> {
101 self.port.handle(
102 &mut self.recv_buffer,
103 &mut self.recv_len,
104 &mut self.send_buffer[2..],
105 &mut self.send_len,
106 )
107 }
108}
109
110impl<
111 B,
112 E,
113 TDI: OutputPin<Error = E>,
114 TCK: OutputPin<Error = E>,
115 TMS: OutputPin<Error = E>,
116 TDO: InputPin<Error = E>,
117 > UsbClass<B> for Blaster<'_, B, E, TDI, TCK, TMS, TDO>
118where
119 B: UsbBus,
120 E: core::fmt::Debug,
121{
122 fn get_configuration_descriptors(
123 &self,
124 writer: &mut DescriptorWriter,
125 ) -> usb_device::Result<()> {
126 self.class.get_configuration_descriptors(writer)
127 }
128
129 fn reset(&mut self) {
130 self.class.reset();
131 self.port.reset().expect("unable to reset port");
133 self.send_len = 0;
134 self.recv_len = 0;
135 }
136
137 fn control_in(&mut self, xfer: ControlIn<B>) {
138 self.class.control_in(xfer);
139 }
140
141 fn control_out(&mut self, xfer: ControlOut<B>) {
142 const FTDI_VEN_REQ_RESET: u8 = 0x00;
144 const _FTDI_VEN_REQ_SET_BAUDRATE: u8 = 0x01;
146 const _FTDI_VEN_REQ_SET_DATA_CHAR: u8 = 0x02;
148 const _FTDI_VEN_REQ_SET_FLOW_CTRL: u8 = 0x03;
150 const _FTDI_VEN_REQ_SET_MODEM_CTRL: u8 = 0x04;
152 const _FTDI_VEN_REQ_SET_EVENT_CHAR: u8 = 0x06;
154 const _FTDI_VEN_REQ_SET_ERR_CHAR: u8 = 0x07;
156 const _FTDI_VEN_REQ_SET_LAT_TIMER: u8 = 0x09;
158 const _FTDI_VEN_REQ_SET_BITMODE: u8 = 0x0B;
160 const FTDI_VEN_REQ_WR_EEPROM: u8 = 0x91;
163 const FTDI_VEN_REQ_ES_EEPROM: u8 = 0x92;
165
166 let req = xfer.request();
167 if req.request_type == RequestType::Vendor {
168 match req.request {
169 FTDI_VEN_REQ_RESET => {
170 const RESET_SIO: u16 = 0x0000;
171 const RESET_PURGE_RX: u16 = 0x0001;
172 const RESET_PURGE_TX: u16 = 0x0002;
173 match req.value {
174 RESET_SIO => {
175 self.reset();
176 xfer.accept().unwrap();
177 }
178 RESET_PURGE_RX => {
179 self.recv_len = 0;
180 xfer.accept().unwrap();
181 }
182 RESET_PURGE_TX => {
183 self.send_len = 0;
184 xfer.accept().unwrap();
185 }
186 _ => {
187 xfer.reject().unwrap();
188 }
189 }
190 }
191 FTDI_VEN_REQ_WR_EEPROM => {
192 xfer.reject().unwrap();
193 }
194 FTDI_VEN_REQ_ES_EEPROM => {
195 xfer.reject().unwrap();
196 }
197 _ => {
198 xfer.accept().unwrap();
199 }
200 }
201 }
202 }
203}