1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
pub mod constants;
pub use constants::*;
pub mod device_handle;
use device_handle::DeviceHandle;

use crate::error::Result;
use byteorder::{ByteOrder, LittleEndian};
/// Low-level io functions for interfacing with rusb(libusb)
use log::{error, info};
use std::time::Duration;

#[derive(Debug)]
pub struct Device {
    handle: DeviceHandle,
}

impl Device {
    pub fn new(index: usize) -> Result<Device> {
        Ok(Device {
            handle: DeviceHandle::open(index)?,
        })
    }

    pub fn claim_interface(&mut self, iface: u8) -> Result<()> {
        self.handle.claim_interface(iface)
    }

    pub fn test_write(&mut self) -> Result<()> {
        // try a dummy write and reset device if it fails
        let len: usize = self.write_reg(BLOCK_USB, USB_SYSCTL, 0x09, 1)?;
        if len == 0 {
            info!("Resetting device...");
            self.handle.reset()?;
        }
        Ok(())
    }

    pub fn reset_demod(&self) -> Result<()> {
        self.demod_write_reg(1, 0x01, 0x14, 1)?;
        self.demod_write_reg(1, 0x01, 0x10, 1)?;
        Ok(())
    }

    /// TODO: This only supports len of 1 or 2, maybe use an enum or make this generic?
    pub fn read_reg(&self, block: u16, addr: u16, len: usize) -> Result<u16> {
        assert!(len == 1 || len == 2);
        let mut data: [u8; 2] = [0, 0];
        let index: u16 = block << 8;
        self.handle
            .read_control(CTRL_IN, 0, addr, index, &mut data[..len], CTRL_TIMEOUT)?;
        // Read registers as little endian, but write as big; not sure why
        Ok(LittleEndian::read_u16(&data))
    }

    pub fn write_reg(&self, block: u16, addr: u16, val: u16, len: usize) -> Result<usize> {
        assert!(len == 1 || len == 2);
        // Read registers as little endian, but write as big; not sure why
        let data: [u8; 2] = val.to_be_bytes();
        let data_slice = if len == 1 { &data[1..2] } else { &data };
        let index = (block << 8) | 0x10;
        // info!("write_reg addr: {:x} index: {:x} data: {:x?} data slice: {}", addr, index, data, data_slice.len());
        self
            .handle
            .write_control(CTRL_OUT, 0, addr, index, data_slice, CTRL_TIMEOUT)
    }

    /// Only supports u8 reads
    pub fn demod_read_reg(&self, page: u16, addr: u16) -> Result<u16> {
        let mut data = [0_u8];
        let index = page;
        let _bytes = match self.handle.read_control(
            CTRL_IN,
            0,
            (addr << 8) | 0x20,
            index,
            &mut data,
            CTRL_TIMEOUT,
        ) {
            Ok(n) => {
                // info!("demod_read_reg got {} bytes: [{:#02x}, {:#02x}] value: {:x}", n, data[0], data[1], BigEndian::read_u16(&data));
                Ok(n)
            }
            Err(e) => {
                error!(
                    "demod_read_reg failed: {} page: {:#02x} addr: {:#02x}",
                    e, page, addr
                );
                Err(e)
            }
        };
        let reg: u16 = data[0] as u16;
        Ok(reg)
    }

    /// TODO: only supports len of 1 or 2, maybe use enum or make this generic
    pub fn demod_write_reg(&self, page: u16, mut addr: u16, val: u16, len: usize) -> Result<usize> {
        assert!(len == 1 || len == 2);
        let index = 0x10 | page;
        addr = (addr << 8) | 0x20;
        let data: [u8; 2] = val.to_be_bytes();
        let data_slice = if len == 1 { &data[1..2] } else { &data };

        let bytes =
            match self
                .handle
                .write_control(CTRL_OUT, 0, addr, index, data_slice, CTRL_TIMEOUT)
            {
                Ok(n) => n,
                Err(e) => {
                    error!(
                        "demod_write_reg failed: {} page: {:#02x} addr: {:#02x} val: {:#02x}",
                        e, page, addr, val
                    );
                    0
                }
            };

        self.demod_read_reg(0x0a, 0x1)?;

        Ok(bytes)
    }

    pub fn bulk_transfer(&self, buf: &mut [u8]) -> Result<usize> {
        self.handle.read_bulk(0x81, buf, Duration::ZERO)
    }

    pub fn read_eeprom(&self, data: &[u8], offset: u8, len: usize) -> Result<usize> {
        assert!((len + offset as usize) <= EEPROM_SIZE);
        self.write_array(BLOCK_IIC, EEPROM_ADDR, &[offset], 1)?;
        for i in data.iter().take(len) {
            self.read_array(BLOCK_IIC, EEPROM_ADDR, &mut [*i], 1)?;
        }
        Ok(len)
    }

    pub fn i2c_read_reg(&self, i2c_addr: u8, reg: u8) -> Result<u8> {
        let addr: u16 = i2c_addr.into();
        let reg: [u8; 1] = [reg];
        let mut data: [u8; 1] = [0];

        match self.write_array(BLOCK_IIC, addr, &reg, 1) {
            Ok(_res) => {
                self.read_array(BLOCK_IIC, addr, &mut data, 1)?;
                Ok(data[0])
            }
            Err(e) => Err(e),
        }
    }

    pub fn i2c_write(&self, i2c_addr: u16, buffer: &[u8]) -> Result<usize> {
        self.write_array(BLOCK_IIC, i2c_addr, buffer, buffer.len())
    }

    pub fn i2c_read(&self, i2c_addr: u16, buffer: &mut [u8], len: u8) -> Result<usize> {
        self.read_array(BLOCK_IIC, i2c_addr, buffer, len)
    }

    pub fn read_array(&self, block: u16, addr: u16, arr: &mut [u8], _len: u8) -> Result<usize> {
        let index: u16 = block << 8;
        self
            .handle
            .read_control(CTRL_IN, 0, addr, index, arr, CTRL_TIMEOUT)
    }

    pub fn write_array(&self, block: u16, addr: u16, arr: &[u8], len: usize) -> Result<usize> {
        let index: u16 = (block << 8) | 0x10;
        self
            .handle
            .write_control(CTRL_OUT, 0, addr, index, &arr[..len], CTRL_TIMEOUT)
    }
}