waverave_hackrf/debug.rs
1/*!
2Debug operations for the HackRF.
3
4The HackRF exposes a number of internal debugging operations through the
5[`Debug`][struct@Debug] struct, allowing for direct read & write of most
6peripheral ICs. This is also how it can be reprogrammed without entering the DFU
7mode.
8
9The way to do this with a HackRF is by calling [`HackRf::debug`] with an open
10peripheral, like so:
11
12```no_run
13
14# use anyhow::Result;
15# #[tokio::main]
16# async fn main() -> Result<()> {
17
18use waverave_hackrf::debug::*;
19
20let mut hackrf = waverave_hackrf::open_hackrf()?;
21// Mutably borrow - make sure no other operations are in progress.
22let mut debug = hackrf.debug();
23
24// Just grab the internal state of the M0 processor and dump it
25let state = debug.get_m0_state().await?;
26dbg!(&state);
27
28# Ok(())
29# }
30```
31
32 */
33use std::ops::Range;
34
35use nusb::transfer::{ControlIn, ControlOut, ControlType, Recipient};
36
37use crate::{ControlRequest, Error, HackRf, TransceiverMode};
38
39/// Internal state data of the Cortex M0 sub-processor.
40///
41/// This can be retrieved with [`Debug::get_m0_state`].
42///
43/// The best use of this struct is that it will show any shortfalls that
44/// occurred during the last TX/RX/Sweep operation, i.e. a TX underrun or RX
45/// overrun.
46///
47#[repr(C)]
48#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)]
49pub struct M0State {
50 /// Requested Mode. Possible values are: 0(IDLE), 1(WAIT), 2(RX),
51 /// 3(TX_START), 4(TX_RUN)
52 pub requested_mode: u16,
53 /// Request flag, 0 means request is completed, any other value means
54 /// request is pending
55 pub request_flag: u16,
56 /// Active mode. Possible values are: 0(IDLE), 1(WAIT), 2(RX), 3(TX_START),
57 /// 4(TX_RUN)
58 pub active_mode: u32,
59 /// Number of bytes transferred by M0
60 pub m0_count: u32,
61 /// Number of bytes transferred by M4
62 pub m4_count: u32,
63 /// Number of shortfalls
64 pub num_shortfalls: u32,
65 /// Longest shortfall in bytes
66 pub longest_shortfall: u32,
67 /// Shortfall limit in bytes
68 pub shortfall_limit: u32,
69 /// Threshold `m0_count` value in bytes for next mode change
70 pub threshold: u32,
71 /// Mode which will be switched to when threshold is reached.
72 pub next_mode: u32,
73 /// Error, if any, that caused M0 to revert to IDLE mode. Possible values
74 /// are: 0 (NONE), 1 (RX_TIMEOUT), 2 (TX_TIMEOUT), or 3 (MISSED_DEADLINE)
75 pub error: u32,
76}
77
78impl M0State {
79 fn le_convert(&mut self) {
80 self.requested_mode = self.requested_mode.to_le();
81 self.request_flag = self.request_flag.to_le();
82 self.active_mode = self.active_mode.to_le();
83 self.m0_count = self.m0_count.to_le();
84 self.m4_count = self.m4_count.to_le();
85 self.num_shortfalls = self.num_shortfalls.to_le();
86 self.longest_shortfall = self.longest_shortfall.to_le();
87 self.shortfall_limit = self.shortfall_limit.to_le();
88 self.threshold = self.threshold.to_le();
89 self.next_mode = self.next_mode.to_le();
90 self.error = self.error.to_le();
91 }
92}
93
94/// Debug operations for the HackRF, including programming operations.
95///
96/// Borrows the interface while doing operations.
97///
98/// The way to get to this struct is by calling [`HackRf::debug`] with an open
99/// peripheral, like so:
100///
101/// ```no_run
102///
103/// # use anyhow::Result;
104/// # #[tokio::main]
105/// # async fn main() -> Result<()> {
106///
107/// use waverave_hackrf::debug::*;
108///
109/// let mut hackrf = waverave_hackrf::open_hackrf()?;
110/// // Mutably borrow - make sure no other operations are in progress.
111/// let mut debug = hackrf.debug();
112///
113/// // Just grab the internal state of the M0 processor and dump it
114/// let state = debug.get_m0_state().await?;
115/// dbg!(&state);
116///
117/// # Ok(())
118/// # }
119/// ```
120pub struct Debug<'a> {
121 inner: &'a mut HackRf,
122}
123
124impl<'a> Debug<'a> {
125 pub(crate) fn new(inner: &'a mut HackRf) -> Debug<'a> {
126 Self { inner }
127 }
128
129 /// Get the internal state of the M0 code of the LPC43xx MCU.
130 ///
131 /// Requires API version 0x0106 or higher.
132 pub async fn get_m0_state(&self) -> Result<M0State, Error> {
133 self.inner.api_check(0x0106)?;
134 let mut v: M0State = self.inner.read_struct(ControlRequest::GetM0State).await?;
135 v.le_convert();
136 Ok(v)
137 }
138
139 /// Access the attached SPI flash.
140 ///
141 /// See [`SpiFlash`] for what to do with it.
142 pub fn spi_flash(&self) -> SpiFlash<'_> {
143 SpiFlash { inner: self.inner }
144 }
145
146 /// Update the XC2C64A-7VQ100C CPLD with a new bitstream.
147 ///
148 /// After every transfer completes, an optional callback will be invoked
149 /// with the number of bytes transferred as the first argument, and the
150 /// total number of bytes to be transferred as the second argument.
151 pub async fn cpld_write<F>(&mut self, data: &[u8], mut callback: Option<F>) -> Result<(), Error>
152 where
153 F: FnMut(usize, usize),
154 {
155 const CHUNK_SIZE: usize = 512;
156 self.inner
157 .set_transceiver_mode(TransceiverMode::CpldUpdate)
158 .await?;
159 let mut sent = 0;
160 let total = data.len();
161 let queue = &mut self.inner.tx.queue;
162 for chunk in data.chunks(CHUNK_SIZE) {
163 let mut buf = if queue.pending() != 0 {
164 let resp = queue.next_complete().await.into_result()?;
165 sent += resp.actual_length();
166 if let Some(ref mut c) = callback {
167 c(sent, total);
168 }
169 resp.reuse()
170 } else {
171 Vec::with_capacity(CHUNK_SIZE)
172 };
173 buf.copy_from_slice(chunk);
174 queue.submit(buf);
175 }
176 while queue.pending() != 0 {
177 let resp = queue.next_complete().await.into_result()?;
178 sent += resp.actual_length();
179 if let Some(ref mut c) = callback {
180 c(sent, total);
181 }
182 }
183 self.inner
184 .set_transceiver_mode(TransceiverMode::Off)
185 .await?;
186 Ok(())
187 }
188
189 /// Get the checksum of the CPLD bitstream.
190 ///
191 /// Requires API version 0x0103 or higher.
192 pub async fn cpld_checksum(&self) -> Result<u32, Error> {
193 self.inner.api_check(0x0103)?;
194 let ret = self
195 .inner
196 .read_bytes(ControlRequest::CpldChecksum, 4)
197 .await?;
198 let ret: [u8; 4] = ret.as_slice().try_into().map_err(|_| Error::ReturnData)?;
199 Ok(u32::from_le_bytes(ret))
200 }
201
202 /// Read a register from the SI5351C.
203 pub async fn si5351c_read(&self, register: u8) -> Result<u8, Error> {
204 self.inner
205 .read_u8(ControlRequest::Si5351cRead, register as u16)
206 .await
207 }
208
209 /// Write a register to the SI5351C.
210 pub async fn si5351c_write(&self, register: u8, value: u8) -> Result<(), Error> {
211 self.inner
212 .write_u8(ControlRequest::Si5351cWrite, register as u16, value)
213 .await
214 }
215
216 /// Read a register from the RFFC5071.
217 pub async fn rffc5071_read(&self, register: u8) -> Result<u16, Error> {
218 if register >= 31 {
219 return Err(Error::AddressRange {
220 range: Range { start: 0, end: 31 },
221 addr: register as u32,
222 });
223 }
224
225 self.inner
226 .read_u16(ControlRequest::Rffc5071Read, register as u16)
227 .await
228 }
229
230 /// Write a register to the RFFC5071.
231 pub async fn rffc5071_write(&self, register: u8, value: u16) -> Result<(), Error> {
232 if register >= 31 {
233 return Err(Error::AddressRange {
234 range: Range { start: 0, end: 31 },
235 addr: register as u32,
236 });
237 }
238
239 self.inner
240 .write_u16(ControlRequest::Rffc5071Write, register as u16, value)
241 .await
242 }
243
244 /// Read a register from the MAX2837.
245 pub async fn max2837_read(&self, register: u8) -> Result<u16, Error> {
246 if register >= 32 {
247 return Err(Error::AddressRange {
248 range: Range { start: 0, end: 32 },
249 addr: register as u32,
250 });
251 }
252
253 self.inner
254 .read_u16(ControlRequest::Max2837Read, register as u16)
255 .await
256 }
257
258 /// Write a register to the MAX2837.
259 pub async fn max2837_write(&self, register: u8, value: u16) -> Result<(), Error> {
260 if register >= 32 {
261 return Err(Error::AddressRange {
262 range: Range { start: 0, end: 32 },
263 addr: register as u32,
264 });
265 }
266
267 if value >= 0x400 {
268 return Err(Error::ValueRange {
269 range: Range {
270 start: 0,
271 end: 0x400,
272 },
273 val: value as u32,
274 });
275 }
276
277 self.inner
278 .write_u16(ControlRequest::Max2837Write, register as u16, value)
279 .await
280 }
281}
282
283/// Accessor for the W25Q80BV SPI Flash in the HackRF.
284///
285/// ⚠️ WARNING: This allows for directly manipulating the SPI flash, which is a
286/// great way to brick your HackRF and require [recovering through DFU mode][dfu].
287///
288/// The general write procedure is to [erase][SpiFlash::erase] the flash,
289/// [write][SpiFlash::write] all bytes to it starting from address 0, then
290/// verify by [reading][SpiFlash::read] the flash to verify a successful write.
291/// As long as you don't depower it after a flash operation, a failed write
292/// attempt can potentially be repeated, as it appears the HackRF only accesses
293/// flash during initial boot and configuration.
294///
295/// [dfu]: https://hackrf.readthedocs.io/en/latest/updating_firmware.html#only-if-necessary-recovering-the-spi-flash-firmware
296pub struct SpiFlash<'a> {
297 inner: &'a HackRf,
298}
299
300impl SpiFlash<'_> {
301 /// Erase the entire flash memory.
302 ///
303 /// Should be immediately followed by writing a new image, or the HackRF
304 /// will be soft-bricked (but recoverable by DFU).
305 pub async fn erase(&self) -> Result<(), Error> {
306 self.inner
307 .write_u8(ControlRequest::SpiflashErase, 0, 0)
308 .await
309 }
310
311 /// Write firmware to the flash memory.
312 ///
313 /// Should only be used for firmware image writing, and needs to be
314 /// preceeded by an erase command before doing a write sequence.
315 ///
316 /// Writes can be up to the max size of the memory; this command will split
317 /// them into sub-commands if needed.
318 pub async fn write(&self, addr: u32, data: &[u8]) -> Result<(), Error> {
319 const END_ADDR: u32 = 0x100000;
320 if addr >= END_ADDR {
321 return Err(Error::AddressRange {
322 range: Range {
323 start: 0,
324 end: END_ADDR,
325 },
326 addr,
327 });
328 }
329
330 if (data.len() + addr as usize) > (END_ADDR as usize) {
331 let end = END_ADDR - addr;
332 return Err(Error::ValueRange {
333 range: Range { start: 0, end },
334 val: data.len() as u32,
335 });
336 }
337
338 let mut addr = addr;
339 let mut data = data;
340 let mut chunk: &[u8];
341 while !data.is_empty() {
342 // Split so that all writes are within a 256-byte page.
343 let len = (0x100 - ((addr & 0xff) as usize)).min(data.len());
344 (chunk, data) = data.split_at(len);
345 self.inner
346 .interface
347 .control_out(ControlOut {
348 control_type: ControlType::Vendor,
349 recipient: Recipient::Device,
350 request: ControlRequest::SpiflashWrite as u8,
351 value: (addr >> 16) as u16,
352 index: (addr & 0xFFFF) as u16,
353 data: chunk,
354 })
355 .await
356 .into_result()?;
357 addr += len as u32;
358 }
359 Ok(())
360 }
361
362 /// Read from the flash memory.
363 ///
364 /// This should only be used for firmware verification.
365 ///
366 /// Reads can be up to the max size of the memory; this command will split
367 /// them into sub-commands if needed.
368 pub async fn read(&self, addr: u32, len: usize) -> Result<Vec<u8>, Error> {
369 const END_ADDR: u32 = 0x10_0000;
370 if addr >= END_ADDR {
371 return Err(Error::AddressRange {
372 range: Range {
373 start: 0,
374 end: END_ADDR,
375 },
376 addr,
377 });
378 }
379
380 if (len + addr as usize) > (END_ADDR as usize) {
381 let end = END_ADDR - addr;
382 return Err(Error::ValueRange {
383 range: Range { start: 0, end },
384 val: len as u32,
385 });
386 }
387
388 let mut addr = addr;
389 let mut data = Vec::with_capacity(len);
390 while data.len() < len {
391 // Read from one 256-byte page at a time, dividing up as needed.
392 let block_len = (0x100 - ((addr & 0xff) as usize)).min(len - data.len());
393 let resp = self
394 .inner
395 .interface
396 .control_in(ControlIn {
397 control_type: ControlType::Vendor,
398 recipient: Recipient::Device,
399 request: ControlRequest::SpiflashRead as u8,
400 value: (addr >> 16) as u16,
401 index: (addr & 0xFFFF) as u16,
402 length: block_len as u16,
403 })
404 .await
405 .into_result()?;
406 data.extend_from_slice(&resp);
407 addr += resp.len() as u32;
408 }
409 Ok(data)
410 }
411
412 /// Get the status registers of the W25Q80BV flash memory.
413 ///
414 /// Requires API version 0x0103 or higher.
415 pub async fn status(&self) -> Result<[u8; 2], Error> {
416 self.inner.api_check(0x0103)?;
417 let val = self
418 .inner
419 .read_u16(ControlRequest::SpiflashStatus, 0)
420 .await?;
421 Ok(val.to_le_bytes())
422 }
423
424 /// Clear the status registers of the W25Q80BV flash memory.
425 pub async fn clear_status(&self) -> Result<(), Error> {
426 self.inner.api_check(0x0103)?;
427 self.inner
428 .write_u16(ControlRequest::SpiflashClearStatus, 0, 0)
429 .await
430 }
431}