waverave_hackrf/
info.rs

1use crate::{Error, HackRf, HackRfType, consts::ControlRequest};
2
3/// The MCU serial number.
4///
5/// See the LPC43xx documentation for details.
6#[repr(C)]
7#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)]
8pub struct SerialNumber {
9    pub part_id: [u32; 2],
10    pub serial_no: [u32; 4],
11}
12
13impl SerialNumber {
14    fn le_convert(&mut self) {
15        for x in self.part_id.iter_mut() {
16            *x = x.to_le();
17        }
18        for x in self.serial_no.iter_mut() {
19            *x = x.to_le();
20        }
21    }
22}
23
24/// The board revision.
25#[derive(Clone, Copy, Debug)]
26pub enum BoardRev {
27    Old,
28    R6,
29    R7,
30    R8,
31    R9,
32    R10,
33    GsgR6,
34    GsgR7,
35    GsgR8,
36    GsgR9,
37    GsgR10,
38    Unknown(u8),
39}
40
41impl std::fmt::Display for BoardRev {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        match self {
44            Self::Old => f.write_str("Older than r6"),
45            Self::R6 => f.write_str("r6"),
46            Self::R7 => f.write_str("r7"),
47            Self::R8 => f.write_str("r8"),
48            Self::R9 => f.write_str("r9"),
49            Self::R10 => f.write_str("r10"),
50            Self::GsgR6 => f.write_str("Great Scott Gadgets r6"),
51            Self::GsgR7 => f.write_str("Great Scott Gadgets r7"),
52            Self::GsgR8 => f.write_str("Great Scott Gadgets r8"),
53            Self::GsgR9 => f.write_str("Great Scott Gadgets r9"),
54            Self::GsgR10 => f.write_str("Great Scott Gadgets r10"),
55            Self::Unknown(v) => write!(f, "unknown (0x{:x})", v),
56        }
57    }
58}
59
60impl BoardRev {
61    fn from_u8(v: u8) -> Self {
62        use BoardRev::*;
63        match v {
64            0 => Old,
65            1 => R6,
66            2 => R7,
67            3 => R8,
68            4 => R9,
69            5 => R10,
70            0x81 => GsgR6,
71            0x82 => GsgR7,
72            0x83 => GsgR8,
73            0x84 => GsgR9,
74            0x85 => GsgR10,
75            v => Unknown(v),
76        }
77    }
78}
79
80/// The physical board's identifier.
81#[derive(Clone, Copy, Debug)]
82pub enum BoardId {
83    Jellybean,
84    Jawbreaker,
85    HackRf1Og,
86    Rad1o,
87    HackRf1R9,
88    Unknown(u8),
89}
90
91impl std::fmt::Display for BoardId {
92    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93        match self {
94            Self::Jellybean => f.write_str("Jellybean"),
95            Self::Jawbreaker => f.write_str("Jawbreaker"),
96            Self::HackRf1Og => f.write_str("HackRF One"),
97            Self::Rad1o => f.write_str("rad1o"),
98            Self::HackRf1R9 => f.write_str("HackRF One Rev9"),
99            Self::Unknown(v) => write!(f, "Unknown (0x{:x})", v),
100        }
101    }
102}
103
104impl BoardId {
105    fn from_u8(v: u8) -> Self {
106        use BoardId::*;
107        match v {
108            0 => Jellybean,
109            1 => Jawbreaker,
110            2 => HackRf1Og,
111            3 => Rad1o,
112            4 => HackRf1R9,
113            v => Unknown(v),
114        }
115    }
116}
117
118/// Compatible platforms for this board.
119#[derive(Clone, Copy, Debug)]
120pub struct SupportedPlatform {
121    pub jawbreaker: bool,
122    pub hackrf1_og: bool,
123    pub rad1o: bool,
124    pub hackrf1_r9: bool,
125}
126
127impl SupportedPlatform {
128    fn from_u32(v: u32) -> Self {
129        Self {
130            jawbreaker: v & 1 != 0,
131            hackrf1_og: v & 2 != 0,
132            rad1o: v & 4 != 0,
133            hackrf1_r9: v & 8 != 0,
134        }
135    }
136}
137
138/// Info-gathering operations for the HackRF.
139///
140/// Borrows the interface while doing operations.
141pub struct Info<'a> {
142    inner: &'a HackRf,
143}
144
145impl<'a> Info<'a> {
146    pub(crate) fn new(inner: &'a HackRf) -> Info<'a> {
147        Self { inner }
148    }
149
150    /// Get the device's implemented API version, as a binary-coded decimal
151    /// (BCD) value.
152    pub fn api_version(&self) -> u16 {
153        self.inner.version
154    }
155
156    /// Get the type of HackRF radio.
157    pub fn radio_type(&self) -> HackRfType {
158        self.inner.ty
159    }
160
161    pub async fn board_id_read(&self) -> Result<BoardId, Error> {
162        let ret = self.inner.read_u8(ControlRequest::BoardIdRead, 0).await?;
163        Ok(BoardId::from_u8(ret))
164    }
165
166    pub async fn version_string_read(&self) -> Result<String, Error> {
167        let resp = self
168            .inner
169            .read_bytes(ControlRequest::VersionStringRead, 255)
170            .await?;
171        String::from_utf8(resp).map_err(|_| Error::ReturnData)
172    }
173
174    pub async fn read_serial(&self) -> Result<SerialNumber, Error> {
175        let mut v: SerialNumber = self
176            .inner
177            .read_struct(ControlRequest::BoardPartidSerialnoRead)
178            .await?;
179        v.le_convert();
180        Ok(v)
181    }
182
183    ///
184    /// Requires API version 0x0106 or higher.
185    pub async fn rev_read(&self) -> Result<BoardRev, Error> {
186        self.inner.api_check(0x0106)?;
187        let rev = self.inner.read_u8(ControlRequest::BoardRevRead, 0).await?;
188        Ok(BoardRev::from_u8(rev))
189    }
190
191    ///
192    /// Requires API version 0x0106 or higher.
193    pub async fn supported_platform_read(&self) -> Result<SupportedPlatform, Error> {
194        self.inner.api_check(0x0106)?;
195        let ret = self
196            .inner
197            .read_bytes(ControlRequest::SupportedPlatformRead, 4)
198            .await?;
199        let ret: [u8; 4] = ret.as_slice().try_into().map_err(|_| Error::ReturnData)?;
200        let val = u32::from_be_bytes(ret);
201        Ok(SupportedPlatform::from_u32(val))
202    }
203}