vlfd_rs/
device.rs

1use crate::config::Config;
2use crate::constants;
3use crate::error::{Error, Result};
4use crate::usb::{Endpoint, UsbDevice};
5use std::time::{Duration, Instant};
6
7const SYNC_TIMEOUT: Duration = Duration::from_secs(1);
8
9/// High-level interface for talking to the SMIMS VLFD device.
10///
11/// The type owns the underlying USB session and keeps the remote configuration
12/// cached locally, providing ergonomic helpers around the device's
13/// configuration and command protocols.
14pub struct Device {
15    usb: UsbDevice,
16    config: Config,
17    encryption: EncryptionState,
18}
19
20impl Device {
21    pub fn new() -> Result<Self> {
22        Ok(Self {
23            usb: UsbDevice::new()?,
24            config: Config::new(),
25            encryption: EncryptionState::default(),
26        })
27    }
28
29    pub fn connect() -> Result<Self> {
30        let mut device = Self::new()?;
31        device.open()?;
32        device.initialize()?;
33        Ok(device)
34    }
35
36    pub fn usb(&self) -> &UsbDevice {
37        &self.usb
38    }
39
40    pub fn config(&self) -> &Config {
41        &self.config
42    }
43
44    pub fn config_mut(&mut self) -> &mut Config {
45        &mut self.config
46    }
47
48    pub fn is_open(&self) -> bool {
49        self.usb.is_open()
50    }
51
52    pub fn open(&mut self) -> Result<()> {
53        self.usb.open(constants::DW_VID, constants::DW_PID)
54    }
55
56    pub fn close(&mut self) -> Result<()> {
57        self.usb.close()
58    }
59
60    pub fn initialize(&mut self) -> Result<()> {
61        self.read_encrypt_table()?;
62        self.encryption.decode_table();
63        self.read_config()?;
64        Ok(())
65    }
66
67    pub fn reset_engine(&self) -> Result<()> {
68        self.usb.write_bytes(Endpoint::Command, &[0x02])
69    }
70
71    pub fn ensure_session(&mut self) -> Result<()> {
72        if !self.is_open() {
73            self.open()?;
74        }
75        self.initialize()
76    }
77
78    pub fn enter_io_mode(&mut self, settings: &IoSettings) -> Result<()> {
79        self.ensure_session()?;
80
81        let actual_version = self.config.smims_version_raw();
82        if actual_version < constants::SMIMS_VERSION {
83            return Err(Error::VersionMismatch {
84                expected: constants::SMIMS_VERSION,
85                actual: actual_version,
86            });
87        }
88
89        if !self.config.is_programmed() {
90            return Err(Error::NotProgrammed);
91        }
92
93        if !self.config.vericomm_ability() {
94            return Err(Error::FeatureUnavailable("vericomm"));
95        }
96
97        if let Some(licence_key) = settings.licence_key {
98            self.config.set_licence_key(licence_key);
99        }
100
101        self.config
102            .set_vericomm_clock_high_delay(settings.clock_high_delay);
103        self.config
104            .set_vericomm_clock_low_delay(settings.clock_low_delay);
105        self.config.set_vericomm_isv(settings.vericomm_isv);
106        self.config
107            .set_vericomm_clock_check_enabled(settings.clock_check_enabled);
108        self.config.set_mode_selector(settings.mode_selector);
109
110        self.write_config()?;
111        self.activate_vericomm()?;
112        Ok(())
113    }
114
115    pub fn transfer_io(&mut self, write_buffer: &mut [u16], read_buffer: &mut [u16]) -> Result<()> {
116        self.encrypt(write_buffer);
117        self.fifo_write(write_buffer)?;
118        self.fifo_read(read_buffer)?;
119        self.decrypt(read_buffer);
120        Ok(())
121    }
122
123    pub fn exit_io_mode(&mut self) -> Result<()> {
124        if !self.is_open() {
125            return Ok(());
126        }
127
128        self.command_active()?;
129        self.close()
130    }
131
132    pub fn fifo_write(&self, buffer: &[u16]) -> Result<()> {
133        self.usb.write_words(Endpoint::FifoWrite, buffer)
134    }
135
136    pub fn fifo_read(&self, buffer: &mut [u16]) -> Result<()> {
137        self.usb.read_words(Endpoint::FifoRead, buffer)
138    }
139
140    pub fn sync_delay(&self) -> Result<()> {
141        let start = Instant::now();
142        let mut buffer = [0u8; 1];
143
144        while start.elapsed() <= SYNC_TIMEOUT {
145            self.usb.write_bytes(Endpoint::Command, &buffer)?;
146            self.usb.read_bytes(Endpoint::Sync, &mut buffer)?;
147            if buffer[0] != 0 {
148                return Ok(());
149            }
150        }
151
152        Err(Error::Timeout("sync_delay"))
153    }
154
155    pub fn command_active(&self) -> Result<()> {
156        self.sync_delay()?;
157        self.usb.write_bytes(Endpoint::Command, &[0x01, 0x00])
158    }
159
160    pub fn read_config(&mut self) -> Result<()> {
161        self.sync_delay()?;
162        self.usb.write_bytes(Endpoint::Command, &[0x01, 0x01])?;
163
164        let mut words = [0u16; Config::WORD_COUNT];
165        self.usb.read_words(Endpoint::FifoRead, &mut words)?;
166        self.command_active()?;
167        self.decrypt(&mut words);
168        self.config = Config::from_words(words);
169        Ok(())
170    }
171
172    pub fn write_config(&mut self) -> Result<()> {
173        self.sync_delay()?;
174        let mut words = *self.config.words();
175        self.encrypt(&mut words);
176        self.usb.write_bytes(Endpoint::Command, &[0x01, 0x11])?;
177        self.usb.write_words(Endpoint::FifoWrite, &words)?;
178        self.command_active()
179    }
180
181    pub fn activate_fpga_programmer(&self) -> Result<()> {
182        self.sync_delay()?;
183        self.usb.write_bytes(Endpoint::Command, &[0x01, 0x02])
184    }
185
186    pub fn activate_vericomm(&self) -> Result<()> {
187        self.sync_delay()?;
188        self.usb.write_bytes(Endpoint::Command, &[0x01, 0x03])
189    }
190
191    pub fn activate_veri_instrument(&self) -> Result<()> {
192        self.sync_delay()?;
193        self.usb.write_bytes(Endpoint::Command, &[0x01, 0x08])
194    }
195
196    pub fn activate_verilink(&self) -> Result<()> {
197        self.sync_delay()?;
198        self.usb.write_bytes(Endpoint::Command, &[0x01, 0x09])
199    }
200
201    pub fn activate_veri_soc(&self) -> Result<()> {
202        self.sync_delay()?;
203        self.usb.write_bytes(Endpoint::Command, &[0x01, 0x0a])
204    }
205
206    pub fn activate_vericomm_pro(&self) -> Result<()> {
207        self.sync_delay()?;
208        self.usb.write_bytes(Endpoint::Command, &[0x01, 0x0b])
209    }
210
211    pub fn activate_veri_sdk(&self) -> Result<()> {
212        self.sync_delay()?;
213        self.usb.write_bytes(Endpoint::Command, &[0x01, 0x04])
214    }
215
216    pub fn activate_flash_read(&self) -> Result<()> {
217        self.sync_delay()?;
218        self.usb.write_bytes(Endpoint::Command, &[0x01, 0x05])
219    }
220
221    pub fn activate_flash_write(&self) -> Result<()> {
222        self.sync_delay()?;
223        self.usb.write_bytes(Endpoint::Command, &[0x01, 0x15])
224    }
225
226    pub fn encrypt(&mut self, buffer: &mut [u16]) {
227        self.encryption.encrypt_words(buffer);
228    }
229
230    pub fn decrypt(&mut self, buffer: &mut [u16]) {
231        self.encryption.decrypt_words(buffer);
232    }
233
234    pub fn licence_gen(&self, security_key: u16, customer_id: u16) -> u16 {
235        licence_gen(security_key, customer_id)
236    }
237
238    fn read_encrypt_table(&mut self) -> Result<()> {
239        self.sync_delay()?;
240        self.usb.write_bytes(Endpoint::Command, &[0x01, 0x0f])?;
241        self.usb
242            .read_words(Endpoint::FifoRead, self.encryption.table_mut())
243    }
244}
245
246#[derive(Debug, Clone, Default)]
247struct EncryptionState {
248    table: [u16; 32],
249    encode_index: usize,
250    decode_index: usize,
251}
252
253impl EncryptionState {
254    fn table_mut(&mut self) -> &mut [u16; 32] {
255        &mut self.table
256    }
257
258    fn decode_table(&mut self) {
259        if self.table.is_empty() {
260            return;
261        }
262        self.table[0] = !self.table[0];
263        for idx in 1..self.table.len() {
264            let prev = self.table[idx - 1];
265            self.table[idx] ^= prev;
266        }
267        self.reset_indices();
268    }
269
270    fn encrypt_words(&mut self, buffer: &mut [u16]) {
271        let key = &self.table[0..16];
272        let mut index = self.encode_index;
273        for word in buffer.iter_mut() {
274            *word ^= key[index];
275            index = (index + 1) & 0x0f;
276        }
277        self.encode_index = index;
278    }
279
280    fn decrypt_words(&mut self, buffer: &mut [u16]) {
281        let key = &self.table[16..32];
282        let mut index = self.decode_index;
283        for word in buffer.iter_mut() {
284            *word ^= key[index];
285            index = (index + 1) & 0x0f;
286        }
287        self.decode_index = index;
288    }
289
290    fn reset_indices(&mut self) {
291        self.encode_index = 0;
292        self.decode_index = 0;
293    }
294}
295
296/// Fine-grained tuning options when switching the device into VeriComm I/O
297/// mode.
298#[derive(Debug, Clone)]
299pub struct IoSettings {
300    pub clock_high_delay: u16,
301    pub clock_low_delay: u16,
302    pub vericomm_isv: u8,
303    pub clock_check_enabled: bool,
304    pub mode_selector: u8,
305    pub licence_key: Option<u16>,
306}
307
308impl Default for IoSettings {
309    fn default() -> Self {
310        Self {
311            clock_high_delay: 11,
312            clock_low_delay: 11,
313            vericomm_isv: 0,
314            clock_check_enabled: false,
315            mode_selector: 0,
316            licence_key: Some(0xff40),
317        }
318    }
319}
320
321fn licence_gen(security_key: u16, customer_id: u16) -> u16 {
322    let mut temp: u32 = 0;
323
324    let mut i: u16 = security_key & 0x0003;
325    let mut j: u16 = (customer_id & 0x000f) << 4;
326    j >>= i;
327    j = (j >> 4) | (j & 0x000f);
328    temp |= (j as u32) << 16;
329
330    i = (security_key & 0x0030) >> 4;
331    j = customer_id & 0x00f0;
332    j >>= i;
333    j = (j >> 4) | (j & 0x000f);
334    temp |= (j as u32) << 20;
335
336    i = (security_key & 0x0300) >> 8;
337    j = (customer_id & 0x0f00) >> 4;
338    j >>= i;
339    j = (j >> 4) | (j & 0x000f);
340    temp |= (j as u32) << 24;
341
342    i = (security_key & 0x3000) >> 12;
343    j = (customer_id & 0xf000) >> 8;
344    j >>= i;
345    j = (j >> 4) | (j & 0x000f);
346    temp |= (j as u32) << 28;
347
348    temp >>= 11;
349    !((temp >> 16) | (temp & 0x0000ffff)) as u16
350}