waverave_hackrf/
debug.rs

1use std::ops::Range;
2
3use nusb::transfer::{ControlIn, ControlOut, ControlType, Recipient};
4
5use crate::{ControlRequest, Error, HackRf, TransceiverMode};
6
7#[repr(C)]
8#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)]
9pub struct M0State {
10    /// Requested Mode. Possible values are: 0(IDLE), 1(WAIT), 2(RX),
11    /// 3(TX_START), 4(TX_RUN)
12    pub requested_mode: u16,
13    /// Request flag, 0 means request is completed, any other value means
14    /// request is pending
15    pub request_flag: u16,
16    /// Active mode. Possible values are: 0(IDLE), 1(WAIT), 2(RX), 3(TX_START),
17    /// 4(TX_RUN)
18    pub active_mode: u32,
19    /// Number of bytes transferred by M0
20    pub m0_count: u32,
21    /// Number of bytes transferred by M4
22    pub m4_count: u32,
23    /// Number of shortfalls
24    pub num_shortfalls: u32,
25    /// Longest shortfall in bytes
26    pub longest_shortfall: u32,
27    /// Shortfall limit in bytes
28    pub shortfall_limit: u32,
29    /// Threshold `m0_count` value in bytes for next mode change
30    pub threshold: u32,
31    /// Mode which will be switched to when threshold is reached.
32    pub next_mode: u32,
33    /// Error, if any, that caused M0 to revert to IDLE mode. Possible values
34    /// are: 0 (NONE), 1 (RX_TIMEOUT), 2 (TX_TIMEOUT), or 3 (MISSED_DEADLINE)
35    pub error: u32,
36}
37
38impl M0State {
39    fn le_convert(&mut self) {
40        self.requested_mode = self.requested_mode.to_le();
41        self.request_flag = self.request_flag.to_le();
42        self.active_mode = self.active_mode.to_le();
43        self.m0_count = self.m0_count.to_le();
44        self.m4_count = self.m4_count.to_le();
45        self.num_shortfalls = self.num_shortfalls.to_le();
46        self.longest_shortfall = self.longest_shortfall.to_le();
47        self.shortfall_limit = self.shortfall_limit.to_le();
48        self.threshold = self.threshold.to_le();
49        self.next_mode = self.next_mode.to_le();
50        self.error = self.error.to_le();
51    }
52}
53
54/// Debug operations for the HackRF, including programming operations.
55///
56/// Borrows the interface while doing operations.
57pub struct Debug<'a> {
58    inner: &'a mut HackRf,
59}
60
61impl<'a> Debug<'a> {
62    pub(crate) fn new(inner: &'a mut HackRf) -> Debug<'a> {
63        Self { inner }
64    }
65
66    /// Get the internal state of the M0 code of the LPC43xx MCU.
67    ///
68    /// Requires API version 0x0106 or higher.
69    pub async fn get_m0_state(&self) -> Result<M0State, Error> {
70        self.inner.api_check(0x0106)?;
71        let mut v: M0State = self.inner.read_struct(ControlRequest::GetM0State).await?;
72        v.le_convert();
73        Ok(v)
74    }
75
76    /// Access the attached SPI flash.
77    pub fn spi_flash(&self) -> SpiFlash<'_> {
78        SpiFlash { inner: self.inner }
79    }
80
81    /// Update the XC2C64A-7VQ100C CPLD with a new bitstream.
82    ///
83    /// After every transfer completes, an optional callback will be invoked
84    /// with the number of bytes transferred as the first argument, and the
85    /// total number of bytes to be transferred as the second argument.
86    pub async fn cpld_write<F>(&mut self, data: &[u8], mut callback: Option<F>) -> Result<(), Error>
87    where
88        F: FnMut(usize, usize),
89    {
90        const CHUNK_SIZE: usize = 512;
91        self.inner
92            .set_transceiver_mode(TransceiverMode::CpldUpdate)
93            .await?;
94        let mut queue = self
95            .inner
96            .interface
97            .bulk_out_queue(crate::consts::TX_ENDPOINT_ADDRESS);
98        let mut sent = 0;
99        let total = data.len();
100        for chunk in data.chunks(CHUNK_SIZE) {
101            let mut buf = if queue.pending() != 0 {
102                let resp = queue.next_complete().await.into_result()?;
103                sent += resp.actual_length();
104                if let Some(ref mut c) = callback {
105                    c(sent, total);
106                }
107                resp.reuse()
108            } else {
109                Vec::with_capacity(CHUNK_SIZE)
110            };
111            buf.copy_from_slice(chunk);
112            queue.submit(buf);
113        }
114        while queue.pending() != 0 {
115            let resp = queue.next_complete().await.into_result()?;
116            sent += resp.actual_length();
117            if let Some(ref mut c) = callback {
118                c(sent, total);
119            }
120        }
121        self.inner
122            .set_transceiver_mode(TransceiverMode::Off)
123            .await?;
124        Ok(())
125    }
126
127    /// Get the checksum of the CPLD bitstream.
128    ///
129    /// Requires API version 0x0103 or higher.
130    pub async fn cpld_checksum(&self) -> Result<u32, Error> {
131        self.inner.api_check(0x0103)?;
132        let ret = self
133            .inner
134            .read_bytes(ControlRequest::CpldChecksum, 4)
135            .await?;
136        let ret: [u8; 4] = ret.as_slice().try_into().map_err(|_| Error::ReturnData)?;
137        Ok(u32::from_le_bytes(ret))
138    }
139
140    /// Read a register from the SI5351C.
141    pub async fn si5351c_read(&self, register: u8) -> Result<u8, Error> {
142        self.inner
143            .read_u8(ControlRequest::Si5351cRead, register as u16)
144            .await
145    }
146
147    /// Write a register to the SI5351C.
148    pub async fn si5351c_write(&self, register: u8, value: u8) -> Result<(), Error> {
149        self.inner
150            .write_u8(ControlRequest::Si5351cWrite, register as u16, value)
151            .await
152    }
153
154    /// Read a register from the RFFC5071.
155    pub async fn rffc5071_read(&self, register: u8) -> Result<u16, Error> {
156        if register >= 31 {
157            return Err(Error::AddressRange {
158                range: Range { start: 0, end: 31 },
159                addr: register as u32,
160            });
161        }
162
163        self.inner
164            .read_u16(ControlRequest::Rffc5071Read, register as u16)
165            .await
166    }
167
168    /// Write a register to the RFFC5071.
169    pub async fn rffc5071_write(&self, register: u8, value: u16) -> Result<(), Error> {
170        if register >= 31 {
171            return Err(Error::AddressRange {
172                range: Range { start: 0, end: 31 },
173                addr: register as u32,
174            });
175        }
176
177        self.inner
178            .write_u16(ControlRequest::Rffc5071Write, register as u16, value)
179            .await
180    }
181
182    /// Read a register from the MAX2837.
183    pub async fn max2837_read(&self, register: u8) -> Result<u16, Error> {
184        if register >= 32 {
185            return Err(Error::AddressRange {
186                range: Range { start: 0, end: 32 },
187                addr: register as u32,
188            });
189        }
190
191        self.inner
192            .read_u16(ControlRequest::Max2837Read, register as u16)
193            .await
194    }
195
196    /// Write a register to the MAX2837.
197    pub async fn max2837_write(&self, register: u8, value: u16) -> Result<(), Error> {
198        if register >= 32 {
199            return Err(Error::AddressRange {
200                range: Range { start: 0, end: 32 },
201                addr: register as u32,
202            });
203        }
204
205        if value >= 0x400 {
206            return Err(Error::ValueRange {
207                range: Range {
208                    start: 0,
209                    end: 0x400,
210                },
211                val: value as u32,
212            });
213        }
214
215        self.inner
216            .write_u16(ControlRequest::Max2837Write, register as u16, value)
217            .await
218    }
219}
220
221/// Accessor for the W25Q80BV SPI Flash in the HackRF.
222pub struct SpiFlash<'a> {
223    inner: &'a HackRf,
224}
225
226impl SpiFlash<'_> {
227    /// Erase the entire flash memory.
228    ///
229    /// Should be immediately followed by writing a new image, or the HackRF
230    /// will be soft-bricked (but recoverable by DFU).
231    pub async fn erase(&self) -> Result<(), Error> {
232        self.inner
233            .write_u8(ControlRequest::SpiflashErase, 0, 0)
234            .await
235    }
236
237    /// Write firmware to the flash memory.
238    ///
239    /// Should only be used for firmware image writing, and likely needs to be
240    /// preceeded by an erase command before doing a write sequence.
241    ///
242    /// Writes can be up to the max size of the memory; this command will split
243    /// them into sub-commands if needed.
244    pub async fn write(&self, addr: u32, data: &[u8]) -> Result<(), Error> {
245        const END_ADDR: u32 = 0x100000;
246        if addr >= END_ADDR {
247            return Err(Error::AddressRange {
248                range: Range {
249                    start: 0,
250                    end: END_ADDR,
251                },
252                addr,
253            });
254        }
255
256        if (data.len() + addr as usize) > (END_ADDR as usize) {
257            let end = END_ADDR - addr;
258            return Err(Error::ValueRange {
259                range: Range { start: 0, end },
260                val: data.len() as u32,
261            });
262        }
263
264        let mut addr = addr;
265        let mut data = data;
266        let mut chunk: &[u8];
267        while !data.is_empty() {
268            // Split so that all writes are within a 256-byte page.
269            let len = (0x100 - ((addr & 0xff) as usize)).min(data.len());
270            (chunk, data) = data.split_at(len);
271            self.inner
272                .interface
273                .control_out(ControlOut {
274                    control_type: ControlType::Vendor,
275                    recipient: Recipient::Device,
276                    request: ControlRequest::SpiflashWrite as u8,
277                    value: (addr >> 16) as u16,
278                    index: (addr & 0xFFFF) as u16,
279                    data: chunk,
280                })
281                .await
282                .into_result()?;
283            addr += len as u32;
284        }
285        Ok(())
286    }
287
288    /// Read from the flash memory.
289    ///
290    /// This should only be used for firmware verification.
291    ///
292    /// Reads can be up to the max size of the memory; this command will split
293    /// them into sub-commands if needed.
294    pub async fn read(&self, addr: u32, len: usize) -> Result<Vec<u8>, Error> {
295        const END_ADDR: u32 = 0x10_0000;
296        if addr >= END_ADDR {
297            return Err(Error::AddressRange {
298                range: Range {
299                    start: 0,
300                    end: END_ADDR,
301                },
302                addr,
303            });
304        }
305
306        if (len + addr as usize) > (END_ADDR as usize) {
307            let end = END_ADDR - addr;
308            return Err(Error::ValueRange {
309                range: Range { start: 0, end },
310                val: len as u32,
311            });
312        }
313
314        let mut addr = addr;
315        let mut data = Vec::with_capacity(len);
316        while data.len() < len {
317            // Read from one 256-byte page at a time, dividing up as needed.
318            let block_len = (0x100 - ((addr & 0xff) as usize)).min(len - data.len());
319            let resp = self
320                .inner
321                .interface
322                .control_in(ControlIn {
323                    control_type: ControlType::Vendor,
324                    recipient: Recipient::Device,
325                    request: ControlRequest::SpiflashRead as u8,
326                    value: (addr >> 16) as u16,
327                    index: (addr & 0xFFFF) as u16,
328                    length: block_len as u16,
329                })
330                .await
331                .into_result()?;
332            data.extend_from_slice(&resp);
333            addr += resp.len() as u32;
334        }
335        Ok(data)
336    }
337
338    /// Get the status registers of the W25Q80BV flash memory.
339    ///
340    /// Requires API version 0x0103 or higher.
341    pub async fn status(&self) -> Result<[u8; 2], Error> {
342        self.inner.api_check(0x0103)?;
343        let val = self
344            .inner
345            .read_u16(ControlRequest::SpiflashStatus, 0)
346            .await?;
347        Ok(val.to_le_bytes())
348    }
349
350    /// Clear the status registers of the W25Q80BV flash memory.
351    pub async fn clear_status(&self) -> Result<(), Error> {
352        self.inner.api_check(0x0103)?;
353        self.inner
354            .write_u16(ControlRequest::SpiflashClearStatus, 0, 0)
355            .await
356    }
357}