neuromorphic_drivers/devices/
prophesee_evk4.rs

1use crate::adapters;
2use crate::configuration;
3use crate::device;
4use crate::flag;
5use crate::properties;
6use crate::usb;
7
8use device::Usb;
9
10#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
11pub struct Biases {
12    pub pr: u8,
13    pub fo: u8,
14    pub hpf: u8,
15    pub diff_on: u8,
16    pub diff: u8,
17    pub diff_off: u8,
18    pub inv: u8,
19    pub refr: u8,
20    pub reqpuy: u8,
21    pub reqpux: u8,
22    pub sendreqpdy: u8,
23    pub unknown_1: u8,
24    pub unknown_2: u8,
25}
26
27#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
28pub enum Clock {
29    Internal = 0,
30    InternalWithOutputEnabled = 1,
31    External = 2,
32}
33
34#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
35pub struct RateLimiter {
36    pub reference_period_us: u16,
37    pub maximum_events_per_period: u32,
38}
39
40#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
41pub struct Configuration {
42    pub biases: Biases,
43    pub x_mask: [u64; 20],
44    pub y_mask: [u64; 12],
45    pub pixel_mask: [u64; 21],
46    pub mask_intersection_only: bool,
47    pub enable_external_trigger: bool,
48    pub clock: Clock,
49    pub rate_limiter: Option<RateLimiter>,
50    pub enable_output: bool,
51}
52
53pub struct Device {
54    handle: std::sync::Arc<rusb::DeviceHandle<rusb::Context>>,
55    ring: usb::Ring,
56    configuration_updater: configuration::Updater<Configuration>,
57    vendor_and_product_id: (u16, u16),
58    serial: String,
59    chip_firmware_configuration: Configuration,
60    register_mutex: std::sync::Arc<std::sync::Mutex<()>>,
61}
62
63#[derive(thiserror::Error, Debug, Clone)]
64pub enum Error {
65    #[error(transparent)]
66    Usb(#[from] usb::Error),
67
68    #[error("short write ({requested} bytes requested, {written} bytes written)")]
69    ShortWrite { requested: usize, written: usize },
70
71    #[error("short response while reading register {0}")]
72    RegisterReadShortResponse(u32),
73
74    #[error("bytes mismatch while reading register {0}")]
75    RegisterReadMismatch(u32),
76
77    #[error("unsupported mask code ({code}) for pixel mask {offset}")]
78    PixelMask { code: u32, offset: u32 },
79
80    #[error("the temperature measurement failed")]
81    Temperature,
82
83    #[error("the illuminance measurement failed")]
84    Illuminance,
85}
86
87impl From<rusb::Error> for Error {
88    fn from(error: rusb::Error) -> Self {
89        usb::Error::from(error).into()
90    }
91}
92
93pub const PROPERTIES: properties::Camera<Configuration> = Device::PROPERTIES;
94pub const DEFAULT_CONFIGURATION: Configuration = Device::PROPERTIES.default_configuration;
95pub const DEFAULT_USB_CONFIGURATION: usb::Configuration = Device::DEFAULT_USB_CONFIGURATION;
96pub fn open<IntoError, IntoWarning>(
97    serial_or_bus_number_and_address: device::SerialOrBusNumberAndAddress,
98    configuration: Configuration,
99    usb_configuration: &usb::Configuration,
100    event_loop: std::sync::Arc<usb::EventLoop>,
101    flag: flag::Flag<IntoError, IntoWarning>,
102) -> Result<Device, Error>
103where
104    IntoError: From<Error> + Clone + Send + 'static,
105    IntoWarning: From<usb::Overflow> + Clone + Send + 'static,
106{
107    Device::open(
108        serial_or_bus_number_and_address,
109        configuration,
110        usb_configuration,
111        event_loop,
112        flag,
113    )
114}
115
116impl device::Usb for Device {
117    type Adapter = adapters::evt3::Adapter;
118
119    type Configuration = Configuration;
120
121    type Error = Error;
122
123    type Properties = properties::Camera<Self::Configuration>;
124
125    const VENDOR_AND_PRODUCT_IDS: &'static [(u16, u16)] = &[
126        (0x04B4, 0x00F4),
127        (0x04B4, 0x00F5),
128        (0x31F7, 0x0003),
129        (0x31F7, 0x0004),
130        (0x1409, 0x8E00),
131    ];
132
133    const PROPERTIES: Self::Properties = Self::Properties {
134        name: "Prophesee EVK4",
135        width: 1280,
136        height: 720,
137        default_configuration: Self::Configuration {
138            biases: Biases {
139                pr: 0x7C,
140                fo: 0x53,
141                hpf: 0x00,
142                diff_on: 0x66,
143                diff: 0x4D,
144                diff_off: 0x49,
145                inv: 0x5B,
146                refr: 0x14,
147                reqpuy: 0x8C,
148                reqpux: 0x7C,
149                sendreqpdy: 0x94,
150                unknown_1: 0x74,
151                unknown_2: 0x51,
152            },
153            x_mask: [0; 20],
154            y_mask: [0; 12],
155            pixel_mask: [0; 21],
156            mask_intersection_only: false,
157            enable_external_trigger: true,
158            clock: Clock::Internal,
159            rate_limiter: None,
160            enable_output: true,
161        },
162    };
163
164    const DEFAULT_USB_CONFIGURATION: usb::Configuration = usb::Configuration {
165        buffer_length: 1 << 17,
166        ring_length: 1 << 12,
167        transfer_queue_length: 1 << 5,
168        allow_dma: false,
169    };
170
171    fn read_serial(handle: &mut rusb::DeviceHandle<rusb::Context>) -> rusb::Result<Option<String>> {
172        handle.claim_interface(0)?;
173        let mut type_buffer = [0u8; 2];
174        if handle.read_control(
175            0xC0,
176            0x72,
177            0x00,
178            0x00,
179            &mut type_buffer,
180            std::time::Duration::from_secs(1),
181        )? != 2
182        {
183            return Ok(None);
184        }
185        if type_buffer[0] != EVK3_IMX636_TYPE && type_buffer[0] != EVK3_IMX646_TYPE {
186            return Ok(None);
187        }
188        handle.write_bulk(
189            0x02,
190            &[0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
191            std::time::Duration::from_secs(1),
192        )?;
193        let mut buffer = vec![0u8; 16];
194        handle.read_bulk(0x82, &mut buffer, std::time::Duration::from_secs(1))?;
195        Ok(Some(format!(
196            "{:02X}{:02X}{:02X}{:02X}",
197            buffer[11], buffer[10], buffer[9], buffer[8]
198        )))
199    }
200
201    fn default_configuration(&self) -> Self::Configuration {
202        PROPERTIES.default_configuration
203    }
204
205    fn current_configuration(&self) -> Self::Configuration {
206        self.configuration_updater.current_configuration()
207    }
208
209    fn update_configuration(&self, configuration: Self::Configuration) {
210        self.configuration_updater.update(configuration);
211    }
212
213    fn open<IntoError, IntoWarning>(
214        serial_or_bus_number_and_address: device::SerialOrBusNumberAndAddress,
215        configuration: Self::Configuration,
216        usb_configuration: &usb::Configuration,
217        event_loop: std::sync::Arc<usb::EventLoop>,
218        flag: flag::Flag<IntoError, IntoWarning>,
219    ) -> Result<Self, Self::Error>
220    where
221        IntoError: From<Self::Error> + Clone + Send + 'static,
222        IntoWarning: From<usb::Overflow> + Clone + Send + 'static,
223    {
224        let (handle, vendor_and_product_id, serial) = match serial_or_bus_number_and_address {
225            device::SerialOrBusNumberAndAddress::Serial(serial) => {
226                Self::open_serial(event_loop.context(), serial)?
227            }
228            device::SerialOrBusNumberAndAddress::BusNumberAndAddress((bus_number, address)) => {
229                Self::open_bus_number_and_address(event_loop.context(), bus_number, address)?
230            }
231            device::SerialOrBusNumberAndAddress::None => Self::open_any(event_loop.context())?,
232        };
233        usb::assert_control_transfer(
234            &handle,
235            0x80,
236            0x06,
237            0x0300,
238            0x0000,
239            &[0x04, 0x03, 0x09, 0x04],
240            TIMEOUT,
241        )?;
242        usb::assert_string_descriptor_any(
243            &handle,
244            0x80,
245            0x06,
246            0x0301,
247            0x0409,
248            &[
249                // "Prophesee" (UTF-16)
250                &[
251                    b'P', 0x00, b'r', 0x00, b'o', 0x00, b'p', 0x00, b'h', 0x00, b'e', 0x00, b's',
252                    0x00, b'e', 0x00, b'e', 0x00,
253                ],
254                // "CenturyArks" (UTF-16)
255                &[
256                    b'C', 0x00, b'e', 0x00, b'n', 0x00, b't', 0x00, b'u', 0x00, b'r', 0x00, b'y',
257                    0x00, b'A', 0x00, b'r', 0x00, b'k', 0x00, b's', 0x00,
258                ],
259                // "IDS Imaging Development Systems GmbH" (UTF-16)
260                &[
261                    b'I', 0x00, b'D', 0x00, b'S', 0x00, b' ', 0x00, b'I', 0x00, b'm', 0x00, b'a',
262                    0x00, b'g', 0x00, b'i', 0x00, b'n', 0x00, b'g', 0x00, b' ', 0x00, b'D', 0x00,
263                    b'e', 0x00, b'v', 0x00, b'e', 0x00, b'l', 0x00, b'o', 0x00, b'p', 0x00, b'm',
264                    0x00, b'e', 0x00, b'n', 0x00, b't', 0x00, b' ', 0x00, b'S', 0x00, b'y', 0x00,
265                    b's', 0x00, b't', 0x00, b'e', 0x00, b'm', 0x00, b's', 0x00, b' ', 0x00, b'G',
266                    0x00, b'm', 0x00, b'b', 0x00, b'H', 0x00,
267                ],
268            ],
269            TIMEOUT,
270        )?;
271        usb::assert_string_descriptor_any(
272            &handle,
273            0x80,
274            0x06,
275            0x0302,
276            0x0409,
277            &[
278                // "EVK4" (UTF-16)
279                &[b'E', 0x00, b'V', 0x00, b'K', 0x00, b'4', 0x00],
280                // "SilkyEvCam HD v03.09.00C" (UTF-16)
281                &[
282                    b'S', 0x00, b'i', 0x00, b'l', 0x00, b'k', 0x00, b'y', 0x00, b'E', 0x00, b'v',
283                    0x00, b'C', 0x00, b'a', 0x00, b'm', 0x00, b' ', 0x00, b'H', 0x00, b'D', 0x00,
284                    b' ', 0x00, b'v', 0x00, b'0', 0x00, b'3', 0x00, b'.', 0x00, b'0', 0x00, b'9',
285                    0x00, b'.', 0x00, b'0', 0x00, b'0', 0x00, b'C', 0x00,
286                ],
287                // "SilkyEvCam HD Lite v03.09.01C" (UTF-16)
288                &[
289                    b'S', 0x00, b'i', 0x00, b'l', 0x00, b'k', 0x00, b'y', 0x00, b'E', 0x00, b'v',
290                    0x00, b'C', 0x00, b'a', 0x00, b'm', 0x00, b' ', 0x00, b'H', 0x00, b'D', 0x00,
291                    b' ', 0x00, b'L', 0x00, b'i', 0x00, b't', 0x00, b'e', 0x00, b' ', 0x00, b'v',
292                    0x00, b'0', 0x00, b'3', 0x00, b'.', 0x00, b'0', 0x00, b'9', 0x00, b'.', 0x00,
293                    b'0', 0x00, b'1', 0x00, b'C', 0x00,
294                ],
295                // "UE-39B0XCP" (UTF-16)
296                &[
297                    b'U', 0x00, b'E', 0x00, b'-', 0x00, b'3', 0x00, b'9', 0x00, b'B', 0x00, b'0',
298                    0x00, b'X', 0x00, b'C', 0x00, b'P',
299                ],
300            ],
301            TIMEOUT,
302        )?;
303        request(
304            &handle,
305            &[0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
306            TIMEOUT,
307        )?; // read release version
308        request(
309            &handle,
310            &[0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
311            TIMEOUT,
312        )?; // read build date
313        request(
314            &handle,
315            &[0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00],
316            TIMEOUT,
317        )?; // ?
318        request(
319            &handle,
320            &[
321                0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322            ],
323            TIMEOUT,
324        )?; // psee,ccam5_imx636 psee,ccam5_gen42
325        request(
326            &handle,
327            &[0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
328            TIMEOUT,
329        )?; // serial request
330        request(
331            &handle,
332            &[0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00],
333            TIMEOUT,
334        )?; // ?
335        request(
336            &handle,
337            &[
338                0x01, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339            ],
340            TIMEOUT,
341        )?; // CCam5 Imx636 Event-Based Camera
342        request(
343            &handle,
344            &[
345                0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346            ],
347            TIMEOUT,
348        )?; // psee,ccam5_imx636 psee,ccam5_gen42
349
350        // Read default biases
351        let mut chip_firmware_configuration = Self::PROPERTIES.default_configuration.clone();
352        chip_firmware_configuration.biases = Biases {
353            pr: BiasPr::read(&handle)?.idac_ctl as u8,
354            fo: BiasFo::read(&handle)?.idac_ctl as u8,
355            hpf: BiasHpf::read(&handle)?.idac_ctl as u8,
356            diff_on: BiasDiffOn::read(&handle)?.idac_ctl as u8,
357            diff: BiasDiff::read(&handle)?.idac_ctl as u8,
358            diff_off: BiasDiffOff::read(&handle)?.idac_ctl as u8,
359            inv: BiasInv::read(&handle)?.idac_ctl as u8,
360            refr: BiasRefr::read(&handle)?.idac_ctl as u8,
361            reqpuy: BiasReqpuy::read(&handle)?.idac_ctl as u8,
362            reqpux: BiasReqpux::read(&handle)?.idac_ctl as u8,
363            sendreqpdy: BiasSendreqpdy::read(&handle)?.idac_ctl as u8,
364            unknown_1: BiasUnknown1::read(&handle)?.idac_ctl as u8,
365            unknown_2: BiasUnknown2::read(&handle)?.idac_ctl as u8,
366        };
367
368        // issd_evk3_imx636_stop in hal_psee_plugins/include/devices/imx636/imx636_evk3_issd.h {
369        RoiCtrl {
370            reserved_0_1: 0,
371            td_enable: 1,
372            reserved_2_5: 0,
373            td_shadow_trigger: 0,
374            td_roni_n_en: 1,
375            reserved_7_10: 0,
376            td_rstn: 0,
377            reserved_11_32: 0x1e000a,
378        }
379        .write(&handle)?;
380        Unknown002C { value: 0x0022c324 }.write(&handle)?;
381        RoCtrl {
382            area_count_enable: 0,
383            output_disable: 1,
384            keep_timer_high: 0,
385        }
386        .write(&handle)?;
387        std::thread::sleep(std::time::Duration::from_millis(1));
388        TimeBaseCtrl {
389            enable: 0,
390            external: 0,
391            primary: 1,
392            external_enable: 0,
393            reserved_4_32: 0x64,
394        }
395        .write(&handle)?;
396        MipiControl { value: 0x000002f8 }.write(&handle)?;
397        std::thread::sleep(std::time::Duration::from_micros(300));
398        // }
399
400        // issd_evk3_imx636_destroy in hal_psee_plugins/include/devices/imx636/imx636_evk3_issd.h {
401        Unknown0070 { value: 0x00400008 }.write(&handle)?;
402        Unknown006C { value: 0x0ee47114 }.write(&handle)?;
403        std::thread::sleep(std::time::Duration::from_micros(500));
404        UnknownA00C { value: 0x00020400 }.write(&handle)?;
405        std::thread::sleep(std::time::Duration::from_micros(500));
406        UnknownA010 { value: 0x00008068 }.write(&handle)?;
407        std::thread::sleep(std::time::Duration::from_micros(200));
408        Unknown1104 { value: 0x00000000 }.write(&handle)?;
409        std::thread::sleep(std::time::Duration::from_micros(200));
410        UnknownA020 { value: 0x00000050 }.write(&handle)?;
411        std::thread::sleep(std::time::Duration::from_micros(200));
412        UnknownA004 { value: 0x000b0500 }.write(&handle)?;
413        std::thread::sleep(std::time::Duration::from_micros(200));
414        UnknownA008 { value: 0x00002404 }.write(&handle)?;
415        std::thread::sleep(std::time::Duration::from_micros(200));
416        UnknownA000 { value: 0x000b0500 }.write(&handle)?;
417        UnknownB044 { value: 0x00000000 }.write(&handle)?;
418        UnknownB004 { value: 0x0000000a }.write(&handle)?;
419        UnknownB040 { value: 0x0000000e }.write(&handle)?;
420        UnknownB0C8 { value: 0x00000000 }.write(&handle)?;
421        UnknownB040 { value: 0x00000006 }.write(&handle)?;
422        UnknownB040 { value: 0x00000004 }.write(&handle)?;
423        Unknown0000 { value: 0x4f006442 }.write(&handle)?;
424        Unknown0000 { value: 0x0f006442 }.write(&handle)?;
425        Unknown00B8 { value: 0x00000401 }.write(&handle)?;
426        Unknown00B8 { value: 0x00000400 }.write(&handle)?;
427        UnknownB07C { value: 0x00000000 }.write(&handle)?;
428        // }
429
430        // issd_evk3_imx636_init in hal_psee_plugins/include/devices/imx636/imx636_evk3_issd.h {
431        Unknown001C { value: 0x00000001 }.write(&handle)?;
432        Reset { value: 0x00000001 }.write(&handle)?;
433        std::thread::sleep(std::time::Duration::from_secs(1));
434        Reset { value: 0x00000000 }.write(&handle)?;
435        std::thread::sleep(std::time::Duration::from_millis(500));
436        MipiControl { value: 0x00000158 }.write(&handle)?;
437        std::thread::sleep(std::time::Duration::from_secs(1));
438        UnknownB044 { value: 0x00000000 }.write(&handle)?;
439        std::thread::sleep(std::time::Duration::from_micros(300));
440        UnknownB004 { value: 0x0000000a }.write(&handle)?;
441        UnknownB040 { value: 0x00000000 }.write(&handle)?;
442        UnknownB0C8 { value: 0x00000000 }.write(&handle)?;
443        UnknownB040 { value: 0x00000000 }.write(&handle)?;
444        UnknownB040 { value: 0x00000000 }.write(&handle)?;
445        Unknown0000 { value: 0x4f006442 }.write(&handle)?;
446        Unknown0000 { value: 0x0f006442 }.write(&handle)?;
447        Unknown00B8 { value: 0x00000400 }.write(&handle)?;
448        Unknown00B8 { value: 0x00000400 }.write(&handle)?;
449        UnknownB07C { value: 0x00000000 }.write(&handle)?;
450        UnknownB074 { value: 0x00000002 }.write(&handle)?;
451        UnknownB078 { value: 0x000000a0 }.write(&handle)?;
452        Unknown00C0 { value: 0x00000110 }.write(&handle)?;
453        Unknown00C0 { value: 0x00000210 }.write(&handle)?;
454        UnknownB120 { value: 0x00000001 }.write(&handle)?;
455        UnknownE120 { value: 0x00000000 }.write(&handle)?;
456        UnknownB068 { value: 0x00000004 }.write(&handle)?;
457        UnknownB07C { value: 0x00000001 }.write(&handle)?;
458        std::thread::sleep(std::time::Duration::from_micros(10));
459        UnknownB07C { value: 0x00000003 }.write(&handle)?;
460        std::thread::sleep(std::time::Duration::from_millis(1));
461        Unknown00B8 { value: 0x00000401 }.write(&handle)?;
462        Unknown00B8 { value: 0x00000409 }.write(&handle)?;
463        Unknown0000 { value: 0x4f006442 }.write(&handle)?;
464        Unknown0000 { value: 0x4f00644a }.write(&handle)?;
465        UnknownB080 { value: 0x00000077 }.write(&handle)?;
466        UnknownB084 { value: 0x0000000f }.write(&handle)?;
467        UnknownB088 { value: 0x00000037 }.write(&handle)?;
468        UnknownB08C { value: 0x00000037 }.write(&handle)?;
469        UnknownB090 { value: 0x000000df }.write(&handle)?;
470        UnknownB094 { value: 0x00000057 }.write(&handle)?;
471        UnknownB098 { value: 0x00000037 }.write(&handle)?;
472        UnknownB09C { value: 0x00000067 }.write(&handle)?;
473        UnknownB0A0 { value: 0x00000037 }.write(&handle)?;
474        UnknownB0A4 { value: 0x0000002f }.write(&handle)?;
475        UnknownB0AC { value: 0x00000028 }.write(&handle)?;
476        UnknownB0CC { value: 0x00000001 }.write(&handle)?;
477        MipiControl { value: 0x000002f8 }.write(&handle)?;
478        UnknownB004 { value: 0x0000008a }.write(&handle)?;
479        UnknownB01C { value: 0x00000030 }.write(&handle)?;
480        MipiPacketSize { value: 0x00002000 }.write(&handle)?;
481        UnknownB02C { value: 0x000000ff }.write(&handle)?;
482        MipiFrameBlanking { value: 0x00003e80 }.write(&handle)?;
483        MipiFramePeriod { value: 0x00000fa0 }.write(&handle)?;
484        UnknownA000 { value: 0x000b0501 }.write(&handle)?;
485        std::thread::sleep(std::time::Duration::from_micros(200));
486        UnknownA008 { value: 0x00002405 }.write(&handle)?;
487        std::thread::sleep(std::time::Duration::from_micros(200));
488        UnknownA004 { value: 0x000b0501 }.write(&handle)?;
489        std::thread::sleep(std::time::Duration::from_micros(200));
490        UnknownA020 { value: 0x00000150 }.write(&handle)?;
491        std::thread::sleep(std::time::Duration::from_micros(200));
492        UnknownB040 { value: 0x00000007 }.write(&handle)?;
493        UnknownB064 { value: 0x00000006 }.write(&handle)?;
494        UnknownB040 { value: 0x0000000f }.write(&handle)?;
495        std::thread::sleep(std::time::Duration::from_micros(100));
496        UnknownB004 { value: 0x0000008a }.write(&handle)?;
497        std::thread::sleep(std::time::Duration::from_micros(200));
498        UnknownB0C8 { value: 0x00000003 }.write(&handle)?;
499        std::thread::sleep(std::time::Duration::from_micros(200));
500        UnknownB044 { value: 0x00000001 }.write(&handle)?;
501        MipiControl { value: 0x000002f9 }.write(&handle)?;
502        Unknown7008 { value: 0x00000001 }.write(&handle)?;
503        EdfPipelineControl { value: 0x00070001 }.write(&handle)?;
504        Unknown8000 { value: 0x0001e085 }.write(&handle)?;
505        TimeBaseCtrl {
506            enable: 0,
507            external: 0,
508            primary: 1,
509            external_enable: 0,
510            reserved_4_32: 0x64,
511        }
512        .write(&handle)?;
513        RoiCtrl {
514            reserved_0_1: 0,
515            td_enable: 1,
516            reserved_2_5: 0,
517            td_shadow_trigger: 0,
518            td_roni_n_en: 1,
519            reserved_7_10: 0,
520            td_rstn: 0,
521            reserved_11_32: 0x1e000a,
522        }
523        .write(&handle)?;
524        Spare0 { value: 0x00000200 }.write(&handle)?;
525        BiasDiff {
526            idac_ctl: 0x4d,
527            vdac_ctl: 0x50,
528            buf_stg: 1,
529            ibtype_sel: 0,
530            mux_sel: 0,
531            mux_en: 1,
532            vdac_en: 0,
533            buf_en: 1,
534            idac_en: 1,
535            reserved: 0,
536            single: 1,
537        }
538        .write(&handle)?;
539        RoFsmCtrl {
540            readout_wait: 0,
541            reserved_16_31: 0,
542        }
543        .write(&handle)?;
544        std::thread::sleep(std::time::Duration::from_millis(1));
545        ReadoutCtrl { value: 0x00000200 }.write(&handle)?;
546        // }
547
548        // Thermometer ADC initalization
549        AdcControl {
550            adc_en: 1,
551            adc_clk_en: 0,
552            adc_start: 0,
553            reserved_3_32: 0xEC8,
554        }
555        .write(&handle)?;
556        AdcControl {
557            adc_en: 1,
558            adc_clk_en: 1,
559            adc_start: 0,
560            reserved_3_32: 0xEC8,
561        }
562        .write(&handle)?;
563        AdcMiscCtrl {
564            reserved_0_1: 0,
565            adc_buf_cal_en: 1,
566            reserved_2_10: 0x210,
567            adc_rng: 0,
568            adc_temp: 0,
569            reserved_13_32: 0,
570        }
571        .write(&handle)?;
572        std::thread::sleep(std::time::Duration::from_micros(100));
573
574        // Thermometer initalization
575        TempCtrl {
576            temp_buf_cal_en: 0,
577            temp_buf_en: 1,
578            reserved_2_32: 0x80020,
579        }
580        .write(&handle)?;
581        TempCtrl {
582            temp_buf_cal_en: 1,
583            temp_buf_en: 1,
584            reserved_2_32: 0x80020,
585        }
586        .write(&handle)?;
587        std::thread::sleep(std::time::Duration::from_micros(100));
588        AdcControl {
589            adc_en: 1,
590            adc_clk_en: 0,
591            adc_start: 0,
592            reserved_3_32: 0xEC8,
593        }
594        .write(&handle)?;
595
596        // Start thermometer
597        AdcControl {
598            adc_en: 1,
599            adc_clk_en: 1,
600            adc_start: 0,
601            reserved_3_32: 0xEC8,
602        }
603        .write(&handle)?;
604        AdcMiscCtrl {
605            reserved_0_1: 0,
606            adc_buf_cal_en: 1,
607            reserved_2_10: 0x84,
608            adc_rng: 0,
609            adc_temp: 1,
610            reserved_13_32: 0,
611        }
612        .write(&handle)?;
613
614        // Illuminometer
615        IphMirrCtrl {
616            iph_mirr_en: 0,
617            iph_mirr_amp_en: 1,
618            reserved_2_32: 0,
619        }
620        .write(&handle)?;
621        std::thread::sleep(std::time::Duration::from_micros(10));
622        IphMirrCtrl {
623            iph_mirr_en: 1,
624            iph_mirr_amp_en: 1,
625            reserved_2_32: 0,
626        }
627        .write(&handle)?;
628        std::thread::sleep(std::time::Duration::from_micros(20));
629        LifoCtrl {
630            lifo_en: 1,
631            lifo_out_en: 0,
632            lifo_cnt_en: 0,
633            reserved_3_32: 0,
634        }
635        .write(&handle)?;
636        std::thread::sleep(std::time::Duration::from_micros(5));
637        LifoCtrl {
638            lifo_en: 1,
639            lifo_out_en: 1,
640            lifo_cnt_en: 0,
641            reserved_3_32: 0,
642        }
643        .write(&handle)?;
644        LifoCtrl {
645            lifo_en: 1,
646            lifo_out_en: 1,
647            lifo_cnt_en: 1,
648            reserved_3_32: 0,
649        }
650        .write(&handle)?;
651
652        // Anti-flicker (AFK)
653        AfkPeriod {
654            min_cutoff_period: 15,
655            max_cutoff_period: 156,
656            inverted_duty_cycle: 8,
657        }
658        .write(&handle)?;
659        AfkPipelineControl {
660            reserved_0_2: 1,
661            bypass: 1,
662        }
663        .write(&handle)?;
664
665        // Burst filters
666        // Spatio Temporal Contrast filter (STC)
667        // Trail filter (TRAIL)
668        StcTimestamping {
669            prescaler: 13,
670            multiplier: 1,
671            reserved_9_16: 1,
672            reset_refractory_period_on_event: 0,
673        }
674        .write(&handle)?;
675        StcParam {
676            enable: 0,
677            threshold: 1480,
678            reserved_20_24: 0,
679            disable_cut_trail: 1,
680        }
681        .write(&handle)?;
682        TrailParam {
683            enable: 0,
684            threshold: 100000,
685        }
686        .write(&handle)?;
687        BurstPipelineInvalidation {
688            dt_fifo_wait_time: 4,
689            dt_fifo_timeout: 280,
690            reserved_24_29: 10,
691        }
692        .write(&handle)?;
693        BurstPipelineInitialization {
694            force_sram_initialization: 0,
695            reserved_1_2: 0,
696            clear_flag: 0,
697        }
698        .write(&handle)?;
699        BurstPipelineControl {
700            reserved_0_2: 1,
701            bypass: 1,
702        }
703        .write(&handle)?;
704
705        // Event Rate Controler (ERC)
706        ErcReserved6000 { value: 0x00155400 }.write(&handle)?;
707        match &configuration.rate_limiter {
708            Some(rate_limiter) => {
709                ErcInDropRateControl {
710                    enable: 1,
711                    reserved_1_32: 0,
712                }
713                .write(&handle)?;
714                ErcReferencePeriod {
715                    duration_us: rate_limiter.reference_period_us as u32,
716                    reserved_10_32: 0,
717                }
718                .write(&handle)?;
719                ErcTdTargetEventRate {
720                    maximum_per_period: rate_limiter.maximum_events_per_period,
721                    reserved_22_32: 0,
722                }
723                .write(&handle)?;
724                ErcControl {
725                    enable: 1,
726                    reserved_1_32: 1,
727                }
728                .write(&handle)?;
729            }
730            None => {
731                ErcInDropRateControl {
732                    enable: 0,
733                    reserved_1_32: 0,
734                }
735                .write(&handle)?;
736                ErcControl {
737                    enable: 0,
738                    reserved_1_32: 1,
739                }
740                .write(&handle)?;
741            }
742        }
743        ErcReserved602C { value: 0x00000001 }.write(&handle)?;
744        for offset in 0..230 {
745            ErcReserved6800 { value: 0x08080808 }
746                .offset(offset)
747                .write(&handle)?;
748        }
749        ErcReserved602C { value: 0x00000002 }.write(&handle)?;
750        for offset in 0..256 {
751            TDropLut {
752                value: ((offset * 2 + 1) << 16) | (offset * 2),
753            }
754            .offset(offset)
755            .write(&handle)?;
756        }
757        ErcTDroppingControl {
758            enable: configuration.rate_limiter.is_some() as u32,
759            reserved_1_32: 0,
760        }
761        .write(&handle)?;
762        ErcHDroppingControl {
763            enable: 0,
764            reserved_1_32: 0,
765        }
766        .write(&handle)?;
767        ErcVDroppingControl {
768            enable: 0,
769            reserved_1_32: 0,
770        }
771        .write(&handle)?;
772        ErcReserved6000 { value: 0x00155401 }.write(&handle)?;
773        EdfReserved7004 {
774            reserved_0_10: 0b0111111111,
775            external_trigger: if configuration.enable_external_trigger {
776                1
777            } else {
778                0
779            },
780            reserved_11_32: 0b11000,
781        }
782        .write(&handle)?;
783        loop {
784            let mut buffer = vec![0u8; Self::DEFAULT_USB_CONFIGURATION.buffer_length];
785            match handle.read_bulk(0x81, &mut buffer, TIMEOUT) {
786                Ok(size) => {
787                    if size == 0 {
788                        break;
789                    }
790                }
791                Err(error) => match error {
792                    rusb::Error::Timeout => break,
793                    error => return Err(error.into()),
794                },
795            }
796        }
797        request(
798            &handle,
799            &[0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
800            TIMEOUT,
801        )?;
802        update_configuration(&handle, None, &configuration)?;
803
804        // issd_evk3_imx636_start in hal_psee_plugins/include/devices/imx636/imx636_evk3_issd.h {
805        MipiControl { value: 0x000002f9 }.write(&handle)?;
806        if configuration.enable_output {
807            RoCtrl {
808                area_count_enable: 0,
809                output_disable: 0,
810                keep_timer_high: 0,
811            }
812            .write(&handle)?;
813        }
814        match configuration.clock {
815            Clock::Internal => {
816                TimeBaseCtrl {
817                    enable: 1,
818                    external: 0,
819                    primary: 1,
820                    external_enable: 0,
821                    reserved_4_32: 0x64,
822                }
823                .write(&handle)?;
824            }
825            Clock::InternalWithOutputEnabled => {
826                TimeBaseCtrl {
827                    enable: 0,
828                    external: 1,
829                    primary: 1,
830                    external_enable: 1,
831                    reserved_4_32: 0x64,
832                }
833                .write(&handle)?;
834                DigPad2Ctrl {
835                    reserved_0_16: 0xFCCF,
836                    sync: 0b1100,
837                    reserved_20_32: 0xCCF,
838                }
839                .write(&handle)?;
840                std::thread::sleep(std::time::Duration::from_millis(1));
841                TimeBaseCtrl {
842                    enable: 1,
843                    external: 1,
844                    primary: 1,
845                    external_enable: 1,
846                    reserved_4_32: 0x64,
847                }
848                .write(&handle)?;
849            }
850            Clock::External => {
851                TimeBaseCtrl {
852                    enable: 1,
853                    external: 1,
854                    primary: 0,
855                    external_enable: 1,
856                    reserved_4_32: 0x64,
857                }
858                .write(&handle)?;
859                DigPad2Ctrl {
860                    reserved_0_16: 0xFCCF,
861                    sync: 0b1111,
862                    reserved_20_32: 0xCCF,
863                }
864                .write(&handle)?;
865            }
866        }
867        Unknown002C { value: 0x0022c724 }.write(&handle)?;
868        RoiCtrl {
869            reserved_0_1: 0,
870            td_enable: 1,
871            reserved_2_5: 0,
872            td_shadow_trigger: 0,
873            td_roni_n_en: (!configuration.mask_intersection_only) as u32,
874            reserved_7_10: 0,
875            td_rstn: 1,
876            reserved_11_32: 0x1e000a,
877        }
878        .write(&handle)?;
879        // }
880
881        let handle = std::sync::Arc::new(handle);
882        let error_flag = flag.clone();
883        let warning_flag = flag.clone();
884        let register_mutex = std::sync::Arc::new(std::sync::Mutex::new(()));
885        Ok(Device {
886            handle: handle.clone(),
887            ring: usb::Ring::new(
888                handle.clone(),
889                usb_configuration,
890                move |usb_error| {
891                    error_flag.store_error_if_not_set(Self::Error::from(usb_error));
892                },
893                move |overflow| {
894                    warning_flag.store_warning_if_not_set(overflow);
895                },
896                event_loop,
897                usb::TransferType::Bulk {
898                    endpoint: 1 | libusb1_sys::constants::LIBUSB_ENDPOINT_IN,
899                    timeout: std::time::Duration::ZERO,
900                },
901            )?,
902            configuration_updater: configuration::Updater::new(
903                configuration,
904                ConfigurationUpdaterContext {
905                    handle,
906                    flag,
907                    register_mutex: register_mutex.clone(),
908                },
909                |context, previous_configuration, configuration| {
910                    let result = {
911                        let _guard = context
912                            .register_mutex
913                            .lock()
914                            .expect("register mutex is not poisoned");
915                        update_configuration(
916                            &context.handle,
917                            Some(previous_configuration),
918                            configuration,
919                        )
920                    };
921                    if let Err(error) = result {
922                        context.flag.store_error_if_not_set(error);
923                    }
924                    context
925                },
926            ),
927            vendor_and_product_id,
928            serial,
929            chip_firmware_configuration,
930            register_mutex,
931        })
932    }
933
934    fn next_with_timeout(&'_ self, timeout: &std::time::Duration) -> Option<usb::BufferView<'_>> {
935        self.ring.next_with_timeout(timeout)
936    }
937
938    fn backlog(&self) -> usize {
939        self.ring.backlog()
940    }
941
942    fn clutch(&self) -> usb::Clutch {
943        self.ring.clutch()
944    }
945
946    fn vendor_and_product_id(&self) -> (u16, u16) {
947        self.vendor_and_product_id
948    }
949
950    fn serial(&self) -> String {
951        self.serial.clone()
952    }
953
954    fn chip_firmware_configuration(&self) -> Self::Configuration {
955        self.chip_firmware_configuration.clone()
956    }
957
958    fn bus_number(&self) -> u8 {
959        self.handle.device().bus_number()
960    }
961
962    fn address(&self) -> u8 {
963        self.handle.device().address()
964    }
965
966    fn speed(&self) -> usb::Speed {
967        self.handle.device().speed().into()
968    }
969
970    fn create_adapter(&self) -> Self::Adapter {
971        Self::Adapter::from_dimensions(Self::PROPERTIES.width, Self::PROPERTIES.height)
972    }
973}
974
975impl Device {
976    pub fn illuminance(&self) -> Result<u32, Error> {
977        let lifo_status = LifoStatus::read(&self.handle)?;
978        if lifo_status.lifo_ton_valid == 1 {
979            Ok(lifo_status.lifo_ton)
980        } else {
981            Err(Error::Illuminance)
982        }
983    }
984
985    pub fn temperature_celsius(&self) -> Result<device::TemperatureCelsius, Error> {
986        let _guard = self
987            .register_mutex
988            .lock()
989            .expect("register mutex is not poisoned");
990        AdcControl {
991            adc_en: 1,
992            adc_clk_en: 1,
993            adc_start: 1,
994            reserved_3_32: 0xEC8,
995        }
996        .write(&self.handle)?;
997        let adc_status = AdcStatus::read(&self.handle)?;
998        if adc_status.adc_done_dyn == 1 {
999            Ok(device::TemperatureCelsius(
1000                adc_status.adc_dac_dyn as f32 * 0.19 - 56.0,
1001            ))
1002        } else {
1003            Err(Error::Temperature)
1004        }
1005    }
1006}
1007
1008impl Drop for Device {
1009    fn drop(&mut self) {
1010        let _ = LifoCtrl {
1011            lifo_en: 0,
1012            lifo_out_en: 0,
1013            lifo_cnt_en: 0,
1014            reserved_3_32: 0,
1015        }
1016        .write(&self.handle);
1017        let _ = IphMirrCtrl {
1018            iph_mirr_en: 0,
1019            iph_mirr_amp_en: 0,
1020            reserved_2_32: 0,
1021        }
1022        .write(&self.handle);
1023        let _ = TempCtrl {
1024            temp_buf_cal_en: 1,
1025            temp_buf_en: 1,
1026            reserved_2_32: 0x80020,
1027        }
1028        .write(&self.handle);
1029        let _ = AdcControl {
1030            adc_en: 0,
1031            adc_clk_en: 0,
1032            adc_start: 0,
1033            reserved_3_32: 0xEC8,
1034        }
1035        .write(&self.handle);
1036
1037        // issd_evk3_imx636_stop in hal_psee_plugins/include/devices/imx636/imx636_evk3_issd.h {
1038        let _ = RoiCtrl {
1039            reserved_0_1: 0,
1040            td_enable: 1,
1041            reserved_2_5: 0,
1042            td_shadow_trigger: 0,
1043            td_roni_n_en: 1,
1044            reserved_7_10: 0,
1045            td_rstn: 0,
1046            reserved_11_32: 0x1e000a,
1047        }
1048        .write(&self.handle);
1049        let _ = Unknown002C { value: 0x0022c324 }.write(&self.handle);
1050        let _ = RoCtrl {
1051            area_count_enable: 0,
1052            output_disable: 1,
1053            keep_timer_high: 0,
1054        }
1055        .write(&self.handle);
1056        std::thread::sleep(std::time::Duration::from_millis(1));
1057        let _ = TimeBaseCtrl {
1058            enable: 0,
1059            external: 0,
1060            primary: 1,
1061            external_enable: 0,
1062            reserved_4_32: 0x64,
1063        }
1064        .write(&self.handle);
1065        let _ = MipiControl { value: 0x000002f8 }.write(&self.handle);
1066        std::thread::sleep(std::time::Duration::from_micros(300));
1067        // }
1068
1069        // issd_evk3_imx636_destroy in hal_psee_plugins/include/devices/imx636/imx636_evk3_issd.h {
1070        let _ = Unknown0070 { value: 0x00400008 }.write(&self.handle);
1071        let _ = Unknown006C { value: 0x0ee47114 }.write(&self.handle);
1072        std::thread::sleep(std::time::Duration::from_micros(500));
1073        let _ = UnknownA00C { value: 0x00020400 }.write(&self.handle);
1074        std::thread::sleep(std::time::Duration::from_micros(500));
1075        let _ = UnknownA010 { value: 0x00008068 }.write(&self.handle);
1076        std::thread::sleep(std::time::Duration::from_micros(200));
1077        let _ = Unknown1104 { value: 0x00000000 }.write(&self.handle);
1078        std::thread::sleep(std::time::Duration::from_micros(200));
1079        let _ = UnknownA020 { value: 0x00000050 }.write(&self.handle);
1080        std::thread::sleep(std::time::Duration::from_micros(200));
1081        let _ = UnknownA004 { value: 0x000b0500 }.write(&self.handle);
1082        std::thread::sleep(std::time::Duration::from_micros(200));
1083        let _ = UnknownA008 { value: 0x00002404 }.write(&self.handle);
1084        std::thread::sleep(std::time::Duration::from_micros(200));
1085        let _ = UnknownA000 { value: 0x000b0500 }.write(&self.handle);
1086        let _ = UnknownB044 { value: 0x00000000 }.write(&self.handle);
1087        let _ = UnknownB004 { value: 0x0000000a }.write(&self.handle);
1088        let _ = UnknownB040 { value: 0x0000000e }.write(&self.handle);
1089        let _ = UnknownB0C8 { value: 0x00000000 }.write(&self.handle);
1090        let _ = UnknownB040 { value: 0x00000006 }.write(&self.handle);
1091        let _ = UnknownB040 { value: 0x00000004 }.write(&self.handle);
1092        let _ = Unknown0000 { value: 0x4f006442 }.write(&self.handle);
1093        let _ = Unknown0000 { value: 0x0f006442 }.write(&self.handle);
1094        let _ = Unknown00B8 { value: 0x00000401 }.write(&self.handle);
1095        let _ = Unknown00B8 { value: 0x00000400 }.write(&self.handle);
1096        let _ = UnknownB07C { value: 0x00000000 }.write(&self.handle);
1097        // }
1098    }
1099}
1100
1101const TIMEOUT: std::time::Duration = std::time::Duration::from_secs(1);
1102
1103fn request(
1104    handle: &rusb::DeviceHandle<rusb::Context>,
1105    buffer: &[u8],
1106    timeout: std::time::Duration,
1107) -> Result<Vec<u8>, Error> {
1108    let written = handle.write_bulk(0x02, buffer, timeout)?;
1109    if buffer.len() != written {
1110        return Err(Error::ShortWrite {
1111            requested: buffer.len(),
1112            written,
1113        });
1114    }
1115    let mut buffer = vec![0; 1024];
1116    let read = handle.read_bulk(0x82, &mut buffer, timeout)?;
1117    buffer.truncate(read);
1118    Ok(buffer)
1119}
1120
1121macro_rules! update_bias {
1122    ($name:ident, $register:ident, $handle:ident, $previous_biases:ident, $biases:expr) => {
1123        if match $previous_biases {
1124            Some(previous_biases) => previous_biases.$name != $biases.$name,
1125            None => true,
1126        } {
1127            $register {
1128                idac_ctl: $biases.$name as u32,
1129                vdac_ctl: 0,
1130                buf_stg: 1,
1131                ibtype_sel: 0,
1132                mux_sel: 0,
1133                mux_en: 1,
1134                vdac_en: 0,
1135                buf_en: 1,
1136                idac_en: 1,
1137                reserved: 0,
1138                single: 1,
1139            }
1140            .write($handle)?;
1141        }
1142    };
1143}
1144
1145fn update_configuration(
1146    handle: &rusb::DeviceHandle<rusb::Context>,
1147    previous_configuration: Option<&Configuration>,
1148    configuration: &Configuration,
1149) -> Result<(), Error> {
1150    if match previous_configuration {
1151        Some(previous_configuration) => {
1152            previous_configuration.enable_output != configuration.enable_output
1153        }
1154        None => false,
1155    } {
1156        RoCtrl {
1157            area_count_enable: 0,
1158            output_disable: if configuration.enable_output { 0 } else { 1 },
1159            keep_timer_high: 0,
1160        }
1161        .write(handle)?;
1162    }
1163    {
1164        let previous_biases = previous_configuration.map(|configuration| &configuration.biases);
1165        update_bias!(pr, BiasPr, handle, previous_biases, configuration.biases);
1166        update_bias!(fo, BiasFo, handle, previous_biases, configuration.biases);
1167        update_bias!(hpf, BiasHpf, handle, previous_biases, configuration.biases);
1168        update_bias!(
1169            diff_on,
1170            BiasDiffOn,
1171            handle,
1172            previous_biases,
1173            configuration.biases
1174        );
1175        update_bias!(
1176            diff,
1177            BiasDiff,
1178            handle,
1179            previous_biases,
1180            configuration.biases
1181        );
1182        update_bias!(
1183            diff_off,
1184            BiasDiffOff,
1185            handle,
1186            previous_biases,
1187            configuration.biases
1188        );
1189        update_bias!(inv, BiasInv, handle, previous_biases, configuration.biases);
1190        update_bias!(
1191            refr,
1192            BiasRefr,
1193            handle,
1194            previous_biases,
1195            configuration.biases
1196        );
1197        update_bias!(
1198            reqpuy,
1199            BiasReqpuy,
1200            handle,
1201            previous_biases,
1202            configuration.biases
1203        );
1204        update_bias!(
1205            reqpux,
1206            BiasReqpux,
1207            handle,
1208            previous_biases,
1209            configuration.biases
1210        );
1211        update_bias!(
1212            sendreqpdy,
1213            BiasSendreqpdy,
1214            handle,
1215            previous_biases,
1216            configuration.biases
1217        );
1218        update_bias!(
1219            unknown_1,
1220            BiasUnknown1,
1221            handle,
1222            previous_biases,
1223            configuration.biases
1224        );
1225        update_bias!(
1226            unknown_2,
1227            BiasUnknown2,
1228            handle,
1229            previous_biases,
1230            configuration.biases
1231        );
1232    }
1233    if match previous_configuration {
1234        Some(previous_configuration) => {
1235            previous_configuration.x_mask != configuration.x_mask
1236                || previous_configuration.y_mask != configuration.y_mask
1237                || previous_configuration.mask_intersection_only
1238                    != configuration.mask_intersection_only
1239        }
1240        None => true,
1241    } {
1242        for offset in 0..((configuration.x_mask.len() as u32) * 2) {
1243            let register = TdRoiX {
1244                value: if (offset % 2) == 0 {
1245                    (configuration.x_mask[(offset / 2) as usize] & 0xffffffffu64) as u32
1246                } else {
1247                    ((configuration.x_mask[(offset / 2) as usize] & 0xffffffff00000000u64) >> 32)
1248                        as u32
1249                },
1250            }
1251            .offset(offset);
1252            register.write(handle)?;
1253        }
1254        for offset in 0..((configuration.y_mask.len() as u32) * 2 - 1) {
1255            let register = TdRoiY {
1256                value: if (offset % 2) == 0 {
1257                    let [byte2, byte3, _, _, _, _, _, _] = configuration.y_mask
1258                        [configuration.y_mask.len() - 1 - (offset / 2) as usize]
1259                        .to_le_bytes();
1260                    if offset < (configuration.y_mask.len() as u32) * 2 - 2 {
1261                        let [_, _, _, _, _, _, byte0, byte1] = configuration.y_mask
1262                            [configuration.y_mask.len() - 2 - (offset / 2) as usize]
1263                            .to_le_bytes();
1264                        u32::from_le_bytes([
1265                            byte3.reverse_bits(),
1266                            byte2.reverse_bits(),
1267                            byte1.reverse_bits(),
1268                            byte0.reverse_bits(),
1269                        ])
1270                    } else {
1271                        u32::from_le_bytes([byte3.reverse_bits(), byte2.reverse_bits(), 0xff, 0x00])
1272                    }
1273                } else {
1274                    let [_, _, byte0, byte1, byte2, byte3, _, _] = configuration.y_mask
1275                        [configuration.y_mask.len() - 2 - (offset / 2) as usize]
1276                        .to_le_bytes();
1277                    u32::from_le_bytes([
1278                        byte3.reverse_bits(),
1279                        byte2.reverse_bits(),
1280                        byte1.reverse_bits(),
1281                        byte0.reverse_bits(),
1282                    ])
1283                },
1284            }
1285            .offset(offset);
1286            register.write(handle)?;
1287        }
1288        RoiCtrl {
1289            reserved_0_1: 0,
1290            td_enable: 1,
1291            reserved_2_5: 0,
1292            td_shadow_trigger: 1,
1293            td_roni_n_en: (!configuration.mask_intersection_only) as u32,
1294            reserved_7_10: 0,
1295            td_rstn: previous_configuration.is_some() as u32,
1296            reserved_11_32: 0x1e000a,
1297        }
1298        .write(handle)?;
1299    }
1300    if match previous_configuration {
1301        Some(previous_configuration) => {
1302            previous_configuration.pixel_mask != configuration.pixel_mask
1303        }
1304        None => true,
1305    } {
1306        for offset in 0u32..64u32 {
1307            let code = if offset < 63 {
1308                (((configuration.pixel_mask[(offset / 3) as usize]) >> ((offset % 3) * 21))
1309                    & 0x1fffff) as u32
1310            } else {
1311                let mut code: u32 = 0;
1312                for bit in 0..21 {
1313                    code |= ((configuration.pixel_mask[bit] >> 63) << bit) as u32;
1314                }
1315                code
1316            };
1317            if code == 0 {
1318                DigitalMask {
1319                    x: 0,
1320                    reserved_11_16: 0,
1321                    y: 0,
1322                    reserved_26_31: 0,
1323                    enable: 0,
1324                }
1325                .offset(offset)
1326                .write(handle)?;
1327            } else {
1328                let x = (code - 1) % 1280;
1329                let y = 720 - 1 - (code - 1) / 1280;
1330                if x >= 1280 || y >= 720 {
1331                    return Err(Error::PixelMask { code, offset });
1332                }
1333                DigitalMask {
1334                    x,
1335                    reserved_11_16: 0,
1336                    y,
1337                    reserved_26_31: 0,
1338                    enable: 1,
1339                }
1340                .offset(offset)
1341                .write(handle)?;
1342            }
1343        }
1344    }
1345    Ok(())
1346}
1347
1348struct ConfigurationUpdaterContext<IntoError, IntoWarning>
1349where
1350    IntoError: From<Error> + Clone + Send,
1351    IntoWarning: From<usb::Overflow> + Clone + Send,
1352{
1353    handle: std::sync::Arc<rusb::DeviceHandle<rusb::Context>>,
1354    flag: flag::Flag<IntoError, IntoWarning>,
1355    register_mutex: std::sync::Arc<std::sync::Mutex<()>>,
1356}
1357
1358const EVK3_IMX636_TYPE: u8 = 0x31;
1359const EVK3_IMX646_TYPE: u8 = 0x35;
1360
1361struct RuntimeRegister {
1362    address: u32,
1363    value: u32,
1364}
1365
1366trait Register {
1367    fn address(&self) -> u32;
1368
1369    fn value(&self) -> u32;
1370
1371    fn offset(&self, registers: u32) -> RuntimeRegister;
1372
1373    fn write(&self, handle: &rusb::DeviceHandle<rusb::Context>) -> Result<(), Error> {
1374        let address = self.address();
1375        let value = self.value();
1376        request(
1377            handle,
1378            &[
1379                0x02,
1380                0x01,
1381                0x01,
1382                0x40,
1383                0x0c,
1384                0x00,
1385                0x00,
1386                0x00,
1387                0x00,
1388                0x00,
1389                0x00,
1390                0x00,
1391                (address & 0xff) as u8,
1392                ((address >> 8) & 0xff) as u8,
1393                ((address >> 16) & 0xff) as u8,
1394                ((address >> 24) & 0xff) as u8,
1395                (value & 0xff) as u8,
1396                ((value >> 8) & 0xff) as u8,
1397                ((value >> 16) & 0xff) as u8,
1398                ((value >> 24) & 0xff) as u8,
1399            ],
1400            TIMEOUT,
1401        )?;
1402        Ok(())
1403    }
1404}
1405
1406impl Register for RuntimeRegister {
1407    fn address(&self) -> u32 {
1408        self.address
1409    }
1410    fn value(&self) -> u32 {
1411        self.value
1412    }
1413    fn offset(&self, registers: u32) -> RuntimeRegister {
1414        RuntimeRegister {
1415            address: self.address + registers * 4,
1416            value: self.value,
1417        }
1418    }
1419}
1420
1421macro_rules! register {
1422    ($name:ident, $address:literal, {$($subname:ident: $substart:literal..$subend:literal),+ $(,)?}) => {
1423        #[derive(Default)]
1424        struct $name {
1425            $(
1426                $subname: u32,
1427            )+
1428        }
1429        $(
1430            const _: () = assert!($substart < $subend);
1431        )+
1432        impl Register for $name {
1433            fn address(&self) -> u32 {
1434                $address
1435            }
1436            fn value(&self) -> u32 {
1437                0u32
1438                $(
1439                    | ((self.$subname & (((1u64 << ($subend - $substart)) - 1) as u32)) << $substart)
1440                )+
1441            }
1442            fn offset(&self, registers: u32) -> RuntimeRegister {
1443                RuntimeRegister  {
1444                    address: $address + registers * 4,
1445                    value: self.value(),
1446                }
1447            }
1448        }
1449        impl $name {
1450            #[allow(dead_code)]
1451            fn read(handle: &rusb::DeviceHandle<rusb::Context>) -> Result<Self, Error> {
1452                let buffer = [
1453                    0x02,
1454                    0x01,
1455                    0x01,
1456                    0x00,
1457                    0x0c,
1458                    0x00,
1459                    0x00,
1460                    0x00,
1461                    0x00,
1462                    0x00,
1463                    0x00,
1464                    0x00,
1465                    ($address & 0xff) as u8,
1466                    (($address >> 8) & 0xff) as u8,
1467                    (($address >> 16) & 0xff) as u8,
1468                    (($address >> 24) & 0xff) as u8,
1469                    0x01,
1470                    0x00,
1471                    0x00,
1472                    0x00,
1473                ];
1474                let result = request(handle, &buffer, TIMEOUT)?;
1475                if result.len() != buffer.len() {
1476                    return Err(Error::RegisterReadShortResponse($address));
1477                }
1478                if result[0..16] != buffer[0..16] {
1479                    return Err(Error::RegisterReadMismatch($address));
1480                }
1481                // unwrap: slice has the right number of bytes
1482                let value = u32::from_le_bytes(result[16..20].try_into().unwrap());
1483                Ok(Self {
1484                    $(
1485                        $subname: (value >> $substart) & (((1u64 << ($subend - $substart)) - 1) as u32),
1486                    )+
1487                })
1488            }
1489        }
1490    };
1491}
1492
1493register! { Unknown0000, 0x0000, { value: 0..32 } }
1494register! { RoiCtrl, 0x0004, {
1495    reserved_0_1: 0..1,
1496    td_enable: 1..2,
1497    reserved_2_5: 2..5,
1498    td_shadow_trigger: 5..6,
1499    td_roni_n_en: 6..7,
1500    reserved_7_10: 7..10,
1501    td_rstn: 10..11,
1502    reserved_11_32: 11..32,
1503} }
1504register! { LifoCtrl, 0x000C, {
1505    lifo_en: 0..1,
1506    lifo_out_en: 1..2,
1507    lifo_cnt_en: 2..3,
1508    reserved_3_32: 3..32,
1509} }
1510register! { LifoStatus, 0x0010, {
1511    lifo_ton: 0..29,
1512    lifo_ton_valid: 29..30,
1513    reserved_30_32: 30..32,
1514} }
1515register! { Reserved0014, 0x0014, { value: 0..32 } }
1516register! { Spare0, 0x0018, { value: 0..32 } }
1517register! { Unknown001C, 0x001C, { value: 0..32 } }
1518register! { RefractoryCtrl, 0x0020, { value: 0..32 } }
1519register! { Unknown002C, 0x002C, { value: 0..32 } }
1520register! { RoiWinCtrl, 0x0034, { value: 0..32 } }
1521register! { RoiWinStartAddr, 0x0038, { value: 0..32 } }
1522register! { RoiWinEndAddr, 0x003C, { value: 0..32 } }
1523register! { DigPad2Ctrl, 0x0044, {
1524    reserved_0_16: 0..16,
1525    sync: 16..20,
1526    reserved_20_32: 20..32,
1527} }
1528register! { AdcControl, 0x004C, {
1529    adc_en: 0..1,
1530    adc_clk_en: 1..2,
1531    adc_start: 2..3,
1532    reserved_3_32: 3..32
1533} }
1534register! { AdcStatus, 0x0050, {
1535    adc_dac_dyn: 0..10,
1536    reserved_10_11: 10..11,
1537    adc_done_dyn: 11..12,
1538    reserved_12_32: 12..32,
1539} }
1540register! { AdcMiscCtrl, 0x0054, {
1541    reserved_0_1: 0..1,
1542    adc_buf_cal_en: 1..2,
1543    reserved_2_10: 2..10,
1544    adc_rng: 10..12,
1545    adc_temp: 12..13,
1546    reserved_13_32: 13..32,
1547} }
1548register! { TempCtrl, 0x005C, {
1549    temp_buf_cal_en: 0..1,
1550    temp_buf_en: 1..2,
1551    reserved_2_32: 2..32,
1552} }
1553register! { Unknown006C, 0x006C, { value: 0..32 } }
1554register! { Unknown0070, 0x0070, { value: 0..32 } }
1555register! { IphMirrCtrl, 0x0074, {
1556    iph_mirr_en: 0..1,
1557    iph_mirr_amp_en: 1..2,
1558    reserved_2_32: 2..32,
1559} }
1560register! { GcdCtrl1, 0x0078, { value: 0..32 } }
1561register! { GcdShadowCtrl, 0x0090, { value: 0..32 } }
1562register! { GcdShadowStatus, 0x0094, { value: 0..32 } }
1563register! { GcdShadowCounter, 0x0098, { value: 0..32 } }
1564register! { Unknown00B8, 0x00B8, { value: 0..32 } }
1565register! { Unknown00C0, 0x00C0, { value: 0..32 } }
1566register! { StopSequenceControl, 0x00C8, { value: 0..32 } }
1567register! { BiasPr, 0x1000, {
1568    idac_ctl: 0..8,
1569    vdac_ctl: 8..16,
1570    buf_stg: 16..19,
1571    ibtype_sel: 19..20,
1572    mux_sel: 20..21,
1573    mux_en: 21..22,
1574    vdac_en: 22..23,
1575    buf_en: 23..24,
1576    idac_en: 24..25,
1577    reserved: 25..28,
1578    single: 28..29,
1579} }
1580register! { BiasFo, 0x1004, {
1581    idac_ctl: 0..8,
1582    vdac_ctl: 8..16,
1583    buf_stg: 16..19,
1584    ibtype_sel: 19..20,
1585    mux_sel: 20..21,
1586    mux_en: 21..22,
1587    vdac_en: 22..23,
1588    buf_en: 23..24,
1589    idac_en: 24..25,
1590    reserved: 25..28,
1591    single: 28..29,
1592} }
1593register! { BiasHpf, 0x100C, {
1594    idac_ctl: 0..8,
1595    vdac_ctl: 8..16,
1596    buf_stg: 16..19,
1597    ibtype_sel: 19..20,
1598    mux_sel: 20..21,
1599    mux_en: 21..22,
1600    vdac_en: 22..23,
1601    buf_en: 23..24,
1602    idac_en: 24..25,
1603    reserved: 25..28,
1604    single: 28..29,
1605} }
1606register! { BiasDiffOn, 0x1010, {
1607    idac_ctl: 0..8,
1608    vdac_ctl: 8..16,
1609    buf_stg: 16..19,
1610    ibtype_sel: 19..20,
1611    mux_sel: 20..21,
1612    mux_en: 21..22,
1613    vdac_en: 22..23,
1614    buf_en: 23..24,
1615    idac_en: 24..25,
1616    reserved: 25..28,
1617    single: 28..29,
1618} }
1619register! { BiasDiff, 0x1014, {
1620    idac_ctl: 0..8,
1621    vdac_ctl: 8..16,
1622    buf_stg: 16..19,
1623    ibtype_sel: 19..20,
1624    mux_sel: 20..21,
1625    mux_en: 21..22,
1626    vdac_en: 22..23,
1627    buf_en: 23..24,
1628    idac_en: 24..25,
1629    reserved: 25..28,
1630    single: 28..29,
1631} }
1632register! { BiasDiffOff, 0x1018, {
1633    idac_ctl: 0..8,
1634    vdac_ctl: 8..16,
1635    buf_stg: 16..19,
1636    ibtype_sel: 19..20,
1637    mux_sel: 20..21,
1638    mux_en: 21..22,
1639    vdac_en: 22..23,
1640    buf_en: 23..24,
1641    idac_en: 24..25,
1642    reserved: 25..28,
1643    single: 28..29,
1644} }
1645register! { BiasInv, 0x101C, {
1646    idac_ctl: 0..8,
1647    vdac_ctl: 8..16,
1648    buf_stg: 16..19,
1649    ibtype_sel: 19..20,
1650    mux_sel: 20..21,
1651    mux_en: 21..22,
1652    vdac_en: 22..23,
1653    buf_en: 23..24,
1654    idac_en: 24..25,
1655    reserved: 25..28,
1656    single: 28..29,
1657} }
1658register! { BiasRefr, 0x1020, {
1659    idac_ctl: 0..8,
1660    vdac_ctl: 8..16,
1661    buf_stg: 16..19,
1662    ibtype_sel: 19..20,
1663    mux_sel: 20..21,
1664    mux_en: 21..22,
1665    vdac_en: 22..23,
1666    buf_en: 23..24,
1667    idac_en: 24..25,
1668    reserved: 25..28,
1669    single: 28..29,
1670} }
1671register! { BiasReqpuy, 0x1040, {
1672    idac_ctl: 0..8,
1673    vdac_ctl: 8..16,
1674    buf_stg: 16..19,
1675    ibtype_sel: 19..20,
1676    mux_sel: 20..21,
1677    mux_en: 21..22,
1678    vdac_en: 22..23,
1679    buf_en: 23..24,
1680    idac_en: 24..25,
1681    reserved: 25..28,
1682    single: 28..29,
1683} }
1684register! { BiasReqpux, 0x1044, {
1685    idac_ctl: 0..8,
1686    vdac_ctl: 8..16,
1687    buf_stg: 16..19,
1688    ibtype_sel: 19..20,
1689    mux_sel: 20..21,
1690    mux_en: 21..22,
1691    vdac_en: 22..23,
1692    buf_en: 23..24,
1693    idac_en: 24..25,
1694    reserved: 25..28,
1695    single: 28..29,
1696} }
1697register! { BiasSendreqpdy, 0x1048, {
1698    idac_ctl: 0..8,
1699    vdac_ctl: 8..16,
1700    buf_stg: 16..19,
1701    ibtype_sel: 19..20,
1702    mux_sel: 20..21,
1703    mux_en: 21..22,
1704    vdac_en: 22..23,
1705    buf_en: 23..24,
1706    idac_en: 24..25,
1707    reserved: 25..28,
1708    single: 28..29,
1709} }
1710register! { BiasUnknown1, 0x104C, {
1711    idac_ctl: 0..8,
1712    vdac_ctl: 8..16,
1713    buf_stg: 16..19,
1714    ibtype_sel: 19..20,
1715    mux_sel: 20..21,
1716    mux_en: 21..22,
1717    vdac_en: 22..23,
1718    buf_en: 23..24,
1719    idac_en: 24..25,
1720    reserved: 25..28,
1721    single: 28..29,
1722} }
1723register! { BiasUnknown2, 0x1050, {
1724    idac_ctl: 0..8,
1725    vdac_ctl: 8..16,
1726    buf_stg: 16..19,
1727    ibtype_sel: 19..20,
1728    mux_sel: 20..21,
1729    mux_en: 21..22,
1730    vdac_en: 22..23,
1731    buf_en: 23..24,
1732    idac_en: 24..25,
1733    reserved: 25..28,
1734    single: 28..29,
1735} }
1736register! { BgenCtrl, 0x1100, { value: 0..32 } }
1737register! { Unknown1104, 0x1104, { value: 0..32 } }
1738register! { TdRoiX, 0x2000, { value: 0..32 } }
1739register! { TdRoiY, 0x4000, { value: 0..32 } }
1740register! { ErcReserved6000, 0x6000, { value: 0..32 } }
1741register! { ErcInDropRateControl, 0x6004, {
1742    enable: 0..1,
1743    reserved_1_32: 1..32,
1744} }
1745register! { ErcReferencePeriod, 0x6008, {
1746    duration_us: 0..10,
1747    reserved_10_32: 10..32,
1748} }
1749register! { ErcTdTargetEventRate, 0x600C, {
1750    maximum_per_period: 0..22,
1751    reserved_22_32: 22..32,
1752} }
1753register! { ErcControl, 0x6028, {
1754    enable: 0..1,
1755    reserved_1_32: 1..32,
1756} }
1757register! { ErcReserved602C, 0x602C, { value: 0..32 } }
1758register! { ErcTDroppingControl, 0x6050, {
1759    enable: 0..1,
1760    reserved_1_32: 1..32,
1761} }
1762register! { ErcHDroppingControl, 0x6060, {
1763    enable: 0..1,
1764    reserved_1_32: 1..32,
1765} }
1766register! { ErcVDroppingControl, 0x6070, {
1767    enable: 0..1,
1768    reserved_1_32: 1..32,
1769} }
1770register! { TDropLut, 0x6400, { value: 0..32 } }
1771register! { ErcReserved6800, 0x6800, { value: 0..32 } }
1772register! { EdfPipelineControl, 0x7000, { value: 0..32 } }
1773register! { EdfReserved7004, 0x7004, {
1774    reserved_0_10: 0..10,
1775    external_trigger: 10..11,
1776    reserved_11_32: 11..32,
1777} }
1778register! { Unknown7008, 0x7008, { value: 0..32 } }
1779register! { Unknown8000, 0x8000, { value: 0..32 } }
1780register! { ReadoutCtrl, 0x9000, { value: 0..32 } }
1781register! { RoFsmCtrl, 0x9004, {
1782    readout_wait: 0..16,
1783    reserved_16_31: 16..32,
1784} }
1785register! { TimeBaseCtrl, 0x9008, {
1786    enable: 0..1,
1787    external: 1..2,
1788    primary: 2..3,
1789    external_enable: 3..4,
1790    reserved_4_32: 4..32,
1791} }
1792register! { DigCtrl, 0x900C, { value: 0..32 } }
1793register! { DigStartPos, 0x9010, { value: 0..32 } }
1794register! { DigEndPos, 0x9014, { value: 0..32 } }
1795register! { RoCtrl, 0x9028, {
1796    area_count_enable: 0..1,
1797    output_disable: 1..2,
1798    keep_timer_high: 2..3,
1799} }
1800register! { AreaX0Addr, 0x902C, { value: 0..32 } }
1801register! { AreaX1Addr, 0x9030, { value: 0..32 } }
1802register! { AreaX2Addr, 0x9034, { value: 0..32 } }
1803register! { AreaX3Addr, 0x9038, { value: 0..32 } }
1804register! { AreaX4Addr, 0x903C, { value: 0..32 } }
1805register! { AreaY0Addr, 0x9040, { value: 0..32 } }
1806register! { AreaY1Addr, 0x9044, { value: 0..32 } }
1807register! { AreaY2Addr, 0x9048, { value: 0..32 } }
1808register! { AreaY3Addr, 0x904C, { value: 0..32 } }
1809register! { AreaY4Addr, 0x9050, { value: 0..32 } }
1810register! { CounterCtrl, 0x9054, { value: 0..32 } }
1811register! { CounterTimerThreshold, 0x9058, { value: 0..32 } }
1812register! { DigitalMask, 0x9100, {
1813    x: 0..11,
1814    reserved_11_16: 11..16,
1815    y: 16..26,
1816    reserved_26_31: 26..31,
1817    enable: 31..32,
1818} }
1819register! { AreaCnt00, 0x9200, { value: 0..32 } }
1820register! { AreaCnt01, 0x9204, { value: 0..32 } }
1821register! { AreaCnt02, 0x9208, { value: 0..32 } }
1822register! { AreaCnt03, 0x920C, { value: 0..32 } }
1823register! { AreaCnt04, 0x9210, { value: 0..32 } }
1824register! { AreaCnt05, 0x9214, { value: 0..32 } }
1825register! { AreaCnt06, 0x9218, { value: 0..32 } }
1826register! { AreaCnt07, 0x921C, { value: 0..32 } }
1827register! { AreaCnt08, 0x9220, { value: 0..32 } }
1828register! { AreaCnt09, 0x9224, { value: 0..32 } }
1829register! { AreaCnt10, 0x9228, { value: 0..32 } }
1830register! { AreaCnt11, 0x922C, { value: 0..32 } }
1831register! { AreaCnt12, 0x9230, { value: 0..32 } }
1832register! { AreaCnt13, 0x9234, { value: 0..32 } }
1833register! { AreaCnt14, 0x9238, { value: 0..32 } }
1834register! { AreaCnt15, 0x923C, { value: 0..32 } }
1835register! { EvtVectorCntVal, 0x9244, { value: 0..32 } }
1836register! { UnknownA000, 0xA000, { value: 0..32 } }
1837register! { UnknownA004, 0xA004, { value: 0..32 } }
1838register! { UnknownA008, 0xA008, { value: 0..32 } }
1839register! { UnknownA00C, 0xA00C, { value: 0..32 } }
1840register! { UnknownA010, 0xA010, { value: 0..32 } }
1841register! { UnknownA020, 0xA020, { value: 0..32 } }
1842register! { MipiControl, 0xB000, { value: 0..32 } }
1843register! { UnknownB004, 0xB004, { value: 0..32 } }
1844register! { UnknownB01C, 0xB01C, { value: 0..32 } }
1845register! { MipiPacketSize, 0xB020, { value: 0..32 } }
1846register! { MipiPacketTimeout, 0xB024, { value: 0..32 } }
1847register! { MipiFramePeriod, 0xB028, { value: 0..32 } }
1848register! { UnknownB02C, 0xB02C, { value: 0..32 } }
1849register! { MipiFrameBlanking, 0xB030, { value: 0..32 } }
1850register! { UnknownB040, 0xB040, { value: 0..32 } }
1851register! { UnknownB044, 0xB044, { value: 0..32 } }
1852register! { UnknownB064, 0xB064, { value: 0..32 } }
1853register! { UnknownB068, 0xB068, { value: 0..32 } }
1854register! { UnknownB074, 0xB074, { value: 0..32 } }
1855register! { UnknownB078, 0xB078, { value: 0..32 } }
1856register! { UnknownB07C, 0xB07C, { value: 0..32 } }
1857register! { UnknownB080, 0xB080, { value: 0..32 } }
1858register! { UnknownB084, 0xB084, { value: 0..32 } }
1859register! { UnknownB088, 0xB088, { value: 0..32 } }
1860register! { UnknownB08C, 0xB08C, { value: 0..32 } }
1861register! { UnknownB090, 0xB090, { value: 0..32 } }
1862register! { UnknownB094, 0xB094, { value: 0..32 } }
1863register! { UnknownB098, 0xB098, { value: 0..32 } }
1864register! { UnknownB09C, 0xB09C, { value: 0..32 } }
1865register! { UnknownB0A0, 0xB0A0, { value: 0..32 } }
1866register! { UnknownB0A4, 0xB0A4, { value: 0..32 } }
1867register! { UnknownB0AC, 0xB0AC, { value: 0..32 } }
1868register! { UnknownB0C8, 0xB0C8, { value: 0..32 } }
1869register! { UnknownB0CC, 0xB0CC, { value: 0..32 } }
1870register! { UnknownB120, 0xB120, { value: 0..32 } }
1871register! { AfkPipelineControl, 0xC000, {
1872    reserved_0_2: 0..2,
1873    bypass: 2..3,
1874} }
1875register! { ReservedC004, 0xC004, { value: 0..32 } }
1876register! { AfkPeriod, 0xC008, {
1877    min_cutoff_period: 0..8,
1878    max_cutoff_period: 8..16,
1879    inverted_duty_cycle: 16..20,
1880} }
1881register! { Invalidation, 0xC0C0, { value: 0..32 } }
1882register! { AfkInitialization, 0xC0C4, { value: 0..32 } }
1883register! { BurstPipelineControl, 0xD000, {
1884    reserved_0_2: 0..2,
1885    bypass: 2..3,
1886} }
1887register! { StcParam, 0xD004, {
1888    enable: 0..1,
1889    threshold: 1..20,
1890    reserved_20_24: 20..24,
1891    disable_cut_trail: 24..25,
1892} }
1893register! { TrailParam, 0xD008, {
1894    enable: 0..1,
1895    threshold: 1..20,
1896} }
1897register! { StcTimestamping, 0xD00C, {
1898    prescaler: 0..5,
1899    multiplier: 5..9,
1900    reserved_9_16: 9..16,
1901    reset_refractory_period_on_event: 16..17,
1902} }
1903register! { BurstPipelineInvalidation, 0xD0C0, {
1904    dt_fifo_wait_time: 0..12,
1905    dt_fifo_timeout: 12..24,
1906    reserved_24_29: 24..29,
1907} }
1908register! { BurstPipelineInitialization, 0xD0C4, {
1909    force_sram_initialization: 0..1,
1910    reserved_1_2: 1..2,
1911    clear_flag: 2..3,
1912} }
1913register! { SlvsControl, 0xE000, { value: 0..32 } }
1914register! { SlvsPacketSize, 0xE020, { value: 0..32 } }
1915register! { SlvsPacketTimeout, 0xE024, { value: 0..32 } }
1916register! { SlvsFrameBlanking, 0xE030, { value: 0..32 } }
1917register! { UnknownE120, 0xE120, { value: 0..32 } }
1918register! { SlvsPhyLogicCtrl00, 0xE150, { value: 0..32 } }
1919register! { Reset, 0x400004, { value: 0..32 } }