seify_hackrfone/
types.rs

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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#[repr(u8)]
#[allow(dead_code)]
pub(crate) enum Request {
    SetTransceiverMode = 1,
    Max2837Write = 2,
    Max2837Read = 3,
    Si5351CWrite = 4,
    Si5351CRead = 5,
    SampleRateSet = 6,
    BasebandFilterBandwidthSet = 7,
    Rffc5071Write = 8,
    Rffc5071Read = 9,
    SpiflashErase = 10,
    SpiflashWrite = 11,
    SpiflashRead = 12,
    BoardIdRead = 14,
    VersionStringRead = 15,
    SetFreq = 16,
    AmpEnable = 17,
    BoardPartidSerialnoRead = 18,
    SetLnaGain = 19,
    SetVgaGain = 20,
    SetTxvgaGain = 21,
    AntennaEnable = 23,
    SetFreqExplicit = 24,
    UsbWcidVendorReq = 25,
    InitSweep = 26,
    OperacakeGetBoards = 27,
    OperacakeSetPorts = 28,
    SetHwSyncMode = 29,
    Reset = 30,
    OperacakeSetRanges = 31,
    ClkoutEnable = 32,
    SpiflashStatus = 33,
    SpiflashClearStatus = 34,
    OperacakeGpioTest = 35,
    CpldChecksum = 36,
    UiEnable = 37,
}

/// Operating modes of the HackRF One.
#[atomic_enum::atomic_enum]
#[derive(PartialEq)]
#[repr(u16)]
pub enum Mode {
    /// Transceiver is off.
    Off = 0,
    /// Transceiver is in receive mode.
    Receive = 1,
    /// Transceiver is in transmit mode.
    Transmit = 2,
    // TODO: HACKRF_TRANSCEIVER_MODE_SS, TRANSCEIVER_MODE_CPLD_UPDATE, TRANSCEIVER_MODE_RX_SWEEP
}

/// Configurable parameters on the hackrf
#[derive(Debug)]
pub struct Config {
    /// Baseband gain, 0-62dB in 2dB increments (rx only)
    pub vga_db: u16,
    /// 0 - 47 dB in 1dB increments (tx only)
    pub txvga_db: u16,

    /// Low-noise amplifier gain, in 0-40dB in 8dB increments (rx only)
    // Pre baseband receive
    pub lna_db: u16,
    /// RF amplifier (on/off)
    pub amp_enable: bool,

    /// Antenna power port control
    // Power enable on antenna
    pub antenna_enable: bool,
    /// Frequency in hz
    pub frequency_hz: u64,
    /// Sample rate in Hz.
    pub sample_rate_hz: u32,
    // TODO: provide helpers for setting this up
    /// Sample rate divider.
    pub sample_rate_div: u32,
}

impl Config {
    /// Returns the default configuration for transmitting.
    pub fn tx_default() -> Self {
        Self {
            vga_db: 0,
            lna_db: 0,
            txvga_db: 40,
            amp_enable: false,
            antenna_enable: false,
            frequency_hz: 908_000_000,
            sample_rate_hz: 2_500_000,
            sample_rate_div: 1,
        }
    }

    /// Returns the default configuration for receiving.
    pub fn rx_default() -> Self {
        Self {
            vga_db: 24,
            lna_db: 0,
            txvga_db: 0,
            amp_enable: false,
            antenna_enable: false,
            frequency_hz: 908_000_000,
            sample_rate_hz: 2_500_000,
            sample_rate_div: 1,
        }
    }
}

/// HackRF One errors.
#[derive(thiserror::Error, Debug)]
pub enum Error {
    /// I/O error occurred.
    #[error("io")]
    Io(#[from] std::io::Error),
    /// USB transfer error.
    #[error("transfer")]
    Transfer(#[from] nusb::transfer::TransferError),
    /// Transfer truncated.
    #[error("transfer truncated")]
    TransferTruncated {
        /// Actual amount of bytes transferred.
        actual: usize,
        /// Expected number of bytes transferred.
        expected: usize,
    },
    /// An API call is not supported by your hardware.
    ///
    /// Try updating the firmware on your device.
    #[error("no api")]
    NoApi {
        /// Current device version.
        device: UsbVersion,
        /// Minimum version required.
        min: UsbVersion,
    },
    /// Invalid argument provided.
    #[error("{0}")]
    Argument(&'static str),
    /// HackRF is in an invalid mode.
    #[error("HackRF in invalid mode. Required: {required:?}, actual: {actual:?}")]
    WrongMode {
        /// The mode required for this operation.
        required: Mode,
        /// The actual mode of the device which differs from `required`.
        actual: Mode,
    },
    /// Device not found.
    #[error("Device not found")]
    NotFound,
}

/// Result type for operations that may return an `Error`.
pub type Result<T> = std::result::Result<T, Error>;

/// A three-part version consisting of major, minor, and sub minor components.
///
/// The intended use case of `Version` is to extract meaning from the version fields in USB
/// descriptors, such as `bcdUSB` and `bcdDevice` in device descriptors.
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)]
// Taken from rusb::Version: https://github.com/a1ien/rusb/blob/8f8c3c6bff6a494a140da4d93dd946bf1e564d66/src/fields.rs#L142-L203
// nusb doesnt currently have this
pub struct UsbVersion(pub u8, pub u8, pub u8);

impl UsbVersion {
    /// Extracts a version from a binary coded decimal (BCD) field. BCD fields exist in USB
    /// descriptors as 16-bit integers encoding a version as `0xJJMN`, where `JJ` is the major
    /// version, `M` is the minor version, and `N` is the sub minor version. For example, 2.0 is
    /// encoded as `0x0200` and 1.1 is encoded as `0x0110`.
    pub fn from_bcd(mut raw: u16) -> Self {
        let sub_minor: u8 = (raw & 0x000F) as u8;
        raw >>= 4;

        let minor: u8 = (raw & 0x000F) as u8;
        raw >>= 4;

        let mut major: u8 = (raw & 0x000F) as u8;
        raw >>= 4;

        major += (10 * raw) as u8;

        UsbVersion(major, minor, sub_minor)
    }

    /// Returns the major version.
    pub fn major(self) -> u8 {
        let UsbVersion(major, _, _) = self;
        major
    }

    /// Returns the minor version.
    pub fn minor(self) -> u8 {
        let UsbVersion(_, minor, _) = self;
        minor
    }

    /// Returns the sub minor version.
    pub fn sub_minor(self) -> u8 {
        let UsbVersion(_, _, sub_minor) = self;
        sub_minor
    }
}

impl std::fmt::Display for UsbVersion {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}.{}.{}", self.major(), self.minor(), self.sub_minor())
    }
}