1use crate::{Error, HackRf, HackRfType, consts::ControlRequest};
33
34#[allow(missing_docs)]
46#[repr(C)]
47#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)]
48pub struct SerialNumber {
49 pub part_id: [u32; 2],
50 pub serial_no: [u32; 4],
51}
52
53impl SerialNumber {
54 fn le_convert(&mut self) {
55 for x in self.part_id.iter_mut() {
56 *x = x.to_le();
57 }
58 for x in self.serial_no.iter_mut() {
59 *x = x.to_le();
60 }
61 }
62}
63
64#[allow(missing_docs)]
68#[derive(Clone, Copy, Debug)]
69pub enum BoardRev {
70 Old,
71 R6,
72 R7,
73 R8,
74 R9,
75 R10,
76 GsgR6,
77 GsgR7,
78 GsgR8,
79 GsgR9,
80 GsgR10,
81 Unknown(u8),
82}
83
84impl std::fmt::Display for BoardRev {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 match self {
87 Self::Old => f.write_str("Older than r6"),
88 Self::R6 => f.write_str("r6"),
89 Self::R7 => f.write_str("r7"),
90 Self::R8 => f.write_str("r8"),
91 Self::R9 => f.write_str("r9"),
92 Self::R10 => f.write_str("r10"),
93 Self::GsgR6 => f.write_str("Great Scott Gadgets r6"),
94 Self::GsgR7 => f.write_str("Great Scott Gadgets r7"),
95 Self::GsgR8 => f.write_str("Great Scott Gadgets r8"),
96 Self::GsgR9 => f.write_str("Great Scott Gadgets r9"),
97 Self::GsgR10 => f.write_str("Great Scott Gadgets r10"),
98 Self::Unknown(v) => write!(f, "unknown (0x{v:x})"),
99 }
100 }
101}
102
103impl BoardRev {
104 pub fn is_official(&self) -> bool {
106 use BoardRev::*;
107 matches!(self, GsgR6 | GsgR7 | GsgR8 | GsgR9 | GsgR10)
108 }
109
110 fn from_u8(v: u8) -> Self {
111 use BoardRev::*;
112 match v {
113 0 => Old,
114 1 => R6,
115 2 => R7,
116 3 => R8,
117 4 => R9,
118 5 => R10,
119 0x81 => GsgR6,
120 0x82 => GsgR7,
121 0x83 => GsgR8,
122 0x84 => GsgR9,
123 0x85 => GsgR10,
124 v => Unknown(v),
125 }
126 }
127}
128
129#[allow(missing_docs)]
132#[derive(Clone, Copy, Debug)]
133pub enum BoardId {
134 Jellybean,
135 Jawbreaker,
136 HackRf1Og,
137 Rad1o,
138 HackRf1R9,
139 Unknown(u8),
140}
141
142impl std::fmt::Display for BoardId {
143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144 match self {
145 Self::Jellybean => f.write_str("Jellybean"),
146 Self::Jawbreaker => f.write_str("Jawbreaker"),
147 Self::HackRf1Og => f.write_str("HackRF One"),
148 Self::Rad1o => f.write_str("rad1o"),
149 Self::HackRf1R9 => f.write_str("HackRF One Rev9"),
150 Self::Unknown(v) => write!(f, "Unknown (0x{v:x})"),
151 }
152 }
153}
154
155impl BoardId {
156 fn from_u8(v: u8) -> Self {
157 use BoardId::*;
158 match v {
159 0 => Jellybean,
160 1 => Jawbreaker,
161 2 => HackRf1Og,
162 3 => Rad1o,
163 4 => HackRf1R9,
164 v => Unknown(v),
165 }
166 }
167}
168
169#[allow(missing_docs)]
171#[derive(Clone, Copy, Debug)]
172pub struct SupportedPlatform {
173 pub jawbreaker: bool,
174 pub hackrf1_og: bool,
175 pub rad1o: bool,
176 pub hackrf1_r9: bool,
177}
178
179impl SupportedPlatform {
180 fn from_u32(v: u32) -> Self {
181 Self {
182 jawbreaker: v & 1 != 0,
183 hackrf1_og: v & 2 != 0,
184 rad1o: v & 4 != 0,
185 hackrf1_r9: v & 8 != 0,
186 }
187 }
188}
189
190pub struct Info<'a> {
194 inner: &'a HackRf,
195}
196
197impl<'a> Info<'a> {
198 pub(crate) fn new(inner: &'a HackRf) -> Info<'a> {
199 Self { inner }
200 }
201
202 pub fn api_version(&self) -> u16 {
205 self.inner.version
206 }
207
208 pub fn radio_type(&self) -> HackRfType {
210 self.inner.ty
211 }
212
213 pub async fn board_id(&self) -> Result<BoardId, Error> {
215 let ret = self.inner.read_u8(ControlRequest::BoardIdRead, 0).await?;
216 Ok(BoardId::from_u8(ret))
217 }
218
219 pub async fn version_string(&self) -> Result<String, Error> {
221 let resp = self
222 .inner
223 .read_bytes(ControlRequest::VersionStringRead, 255)
224 .await?;
225 String::from_utf8(resp).map_err(|_| Error::ReturnData)
226 }
227
228 pub async fn serial(&self) -> Result<SerialNumber, Error> {
235 let mut v: SerialNumber = self
236 .inner
237 .read_struct(ControlRequest::BoardPartidSerialnoRead)
238 .await?;
239 v.le_convert();
240 Ok(v)
241 }
242
243 pub async fn board_rev(&self) -> Result<BoardRev, Error> {
247 self.inner.api_check(0x0106)?;
248 let rev = self.inner.read_u8(ControlRequest::BoardRevRead, 0).await?;
249 Ok(BoardRev::from_u8(rev))
250 }
251
252 pub async fn supported_platform(&self) -> Result<SupportedPlatform, Error> {
256 self.inner.api_check(0x0106)?;
257 let ret = self
258 .inner
259 .read_bytes(ControlRequest::SupportedPlatformRead, 4)
260 .await?;
261 let ret: [u8; 4] = ret.as_slice().try_into().map_err(|_| Error::ReturnData)?;
262 let val = u32::from_be_bytes(ret);
263 Ok(SupportedPlatform::from_u32(val))
264 }
265}