Skip to main content

pamoja_radios/sx1302/
register.rs

1//! Where the concentrator keeps its registers.
2//!
3//! The chip is laid out in blocks, each with a base address: the receive buffer, the two
4//! transmit chains, the common block, the front end, the two microcontrollers, the timestamp
5//! counter, and the one-time programmable memory that carries the part number.
6//!
7//! Most registers are narrower than the byte they live in, so a register is an address plus
8//! the bits it occupies inside it. Writing one means reading that byte, replacing those bits,
9//! and writing it back, which is why [`Register`] carries the offset and the width rather
10//! than just an address.
11
12use super::spi;
13
14/// The paged external memory, where the microcontroller firmware is written.
15pub const EXTERNAL_MEMORY_BASE: u16 = 0x0000;
16
17/// The buffer received packets are read out of.
18pub const RX_BUFFER_BASE: u16 = 0x4000;
19
20/// The first transmit chain.
21pub const TX_TOP_A_BASE: u16 = 0x5200;
22
23/// The second transmit chain.
24pub const TX_TOP_B_BASE: u16 = 0x5400;
25
26/// The block holding the version, the page selector, and the chip-wide controls.
27pub const COMMON_BASE: u16 = 0x5600;
28
29/// The general purpose pins.
30pub const GPIO_BASE: u16 = 0x5640;
31
32/// The built-in memory self test.
33pub const MBIST_BASE: u16 = 0x56c0;
34
35/// The radio front end.
36pub const RADIO_FE_BASE: u16 = 0x5700;
37
38/// The automatic gain control microcontroller.
39pub const AGC_MCU_BASE: u16 = 0x5780;
40
41/// The clock controls.
42pub const CLK_CTRL_BASE: u16 = 0x57c0;
43
44/// The receive chain.
45pub const RX_TOP_BASE: u16 = 0x5800;
46
47/// The single-spreading-factor receiver and the FSK receiver.
48pub const RX_TOP_LORA_SERVICE_FSK_BASE: u16 = 0x5b00;
49
50/// The capture memory.
51pub const CAPTURE_RAM_BASE: u16 = 0x6000;
52
53/// The arbiter microcontroller, which shares the radios between the receivers.
54pub const ARB_MCU_BASE: u16 = 0x6080;
55
56/// The counter a received packet is timestamped against.
57pub const TIMESTAMP_BASE: u16 = 0x6100;
58
59/// The one-time programmable memory, which carries the part number.
60pub const OTP_BASE: u16 = 0x6180;
61
62/// A register, which is some of the bits of a byte at an address.
63#[derive(Clone, Copy, Debug, PartialEq, Eq)]
64pub struct Register {
65    /// The byte it lives in.
66    pub address: u16,
67    /// Which bit of that byte it starts at.
68    pub offset: u8,
69    /// How many bits it spans.
70    pub width: u8,
71    /// Whether the chip refuses to be written here.
72    pub read_only: bool,
73}
74
75impl Register {
76    /// Names a register by where it is and how wide it is.
77    ///
78    /// # Arguments
79    ///
80    /// * `address` - the byte it lives in.
81    /// * `offset` - which bit it starts at.
82    /// * `width` - how many bits it spans.
83    /// * `read_only` - whether the chip refuses to be written here.
84    ///
85    /// # Returns
86    ///
87    /// The register.
88    #[must_use]
89    pub const fn new(address: u16, offset: u8, width: u8, read_only: bool) -> Register {
90        Register {
91            address,
92            offset,
93            width,
94            read_only,
95        }
96    }
97
98    /// Whether this register is the whole byte rather than a field inside one.
99    ///
100    /// A whole byte is written directly; anything narrower has to be read first, so the bits
101    /// beside it survive the write.
102    ///
103    /// # Returns
104    ///
105    /// Whether a write can skip reading the byte first.
106    ///
107    /// # Examples
108    ///
109    /// ```
110    /// use pamoja_radios::sx1302::register::{COMMON_VERSION, AGC_MCU_HOST_PROG};
111    ///
112    /// assert!(COMMON_VERSION.is_whole_byte());
113    /// assert!(!AGC_MCU_HOST_PROG.is_whole_byte());
114    /// ```
115    #[must_use]
116    pub const fn is_whole_byte(&self) -> bool {
117        self.offset == 0 && self.width == 8
118    }
119
120    /// Reads this register out of the byte it shares.
121    ///
122    /// # Arguments
123    ///
124    /// * `byte` - the byte read from [`address`](Register::address).
125    ///
126    /// # Returns
127    ///
128    /// The value, shifted down to where it reads as a number.
129    #[must_use]
130    pub const fn decode(&self, byte: u8) -> u8 {
131        spi::field(byte, self.offset, self.width)
132    }
133
134    /// Puts a value into this register, leaving the rest of the byte as it was.
135    ///
136    /// # Arguments
137    ///
138    /// * `byte` - the byte as it reads now.
139    /// * `value` - what to put in this register.
140    ///
141    /// # Returns
142    ///
143    /// The byte to write back.
144    #[must_use]
145    pub const fn encode(&self, byte: u8, value: u8) -> u8 {
146        spi::with_field(byte, self.offset, self.width, value)
147    }
148}
149
150/// Which of the four memory pages the external memory window shows.
151pub const COMMON_PAGE: Register = Register::new(COMMON_BASE, 0, 2, false);
152
153/// The chip version, which a working concentrator answers with
154/// [`EXPECTED_VERSION`](super::chip::EXPECTED_VERSION).
155pub const COMMON_VERSION: Register = Register::new(COMMON_BASE + 6, 0, 8, true);
156
157/// Holds the gain control microcontroller in reset.
158pub const AGC_MCU_CLEAR: Register = Register::new(AGC_MCU_BASE, 2, 1, false);
159
160/// Gives the host the gain control microcontroller memory, so firmware can be written.
161pub const AGC_MCU_HOST_PROG: Register = Register::new(AGC_MCU_BASE, 1, 1, false);
162
163/// Runs the clock of the gain control microcontroller.
164pub const AGC_MCU_CLK_EN: Register = Register::new(AGC_MCU_BASE, 4, 1, false);
165
166/// Set by the chip when the firmware it holds does not check out.
167pub const AGC_MCU_PARITY_ERROR: Register = Register::new(AGC_MCU_BASE, 0, 1, true);
168
169/// Holds the arbiter microcontroller in reset.
170pub const ARB_MCU_CLEAR: Register = Register::new(ARB_MCU_BASE, 2, 1, false);
171
172/// Gives the host the arbiter microcontroller memory.
173pub const ARB_MCU_HOST_PROG: Register = Register::new(ARB_MCU_BASE, 1, 1, false);
174
175/// Runs the clock of the arbiter microcontroller.
176pub const ARB_MCU_CLK_EN: Register = Register::new(ARB_MCU_BASE, 5, 1, false);
177
178/// Set by the chip when the arbiter firmware does not check out.
179pub const ARB_MCU_PARITY_ERROR: Register = Register::new(ARB_MCU_BASE, 0, 1, true);
180
181/// Runs the radios from the host clock rather than their own.
182///
183/// A front end is reset with this cleared, so the concentrator is still clocked while the
184/// radio it drives is held down.
185pub const COMMON_CLK32_RIF_CTRL: Register = Register::new(COMMON_BASE + 1, 4, 1, false);
186
187/// Whether the host drives the front ends directly rather than the gain control
188/// microcontroller.
189pub const COMMON_HOST_RADIO_CTRL: Register = Register::new(COMMON_BASE + 1, 3, 1, false);
190
191/// Powers the front end on the first chain.
192pub const RF_EN_A_RADIO_EN: Register = Register::new(AGC_MCU_BASE + 3, 2, 1, false);
193
194/// Holds the front end on the first chain in reset.
195pub const RF_EN_A_RADIO_RST: Register = Register::new(AGC_MCU_BASE + 3, 3, 1, false);
196
197/// Powers the front end on the second chain.
198pub const RF_EN_B_RADIO_EN: Register = Register::new(AGC_MCU_BASE + 4, 2, 1, false);
199
200/// Holds the front end on the second chain in reset.
201pub const RF_EN_B_RADIO_RST: Register = Register::new(AGC_MCU_BASE + 4, 3, 1, false);
202
203/// Which byte of the one-time programmable memory the read register answers with.
204pub const OTP_BYTE_ADDR: Register = Register::new(OTP_BASE, 0, 8, false);
205
206/// The byte at the address [`OTP_BYTE_ADDR`] selected.
207pub const OTP_RD_DATA: Register = Register::new(OTP_BASE + 1, 0, 8, true);
208
209/// Whether the one-time programmable memory is ready to be read.
210pub const OTP_FSM_READY: Register = Register::new(OTP_BASE + 2, 0, 1, true);
211
212/// What the one-time programmable memory made of its own checksum.
213pub const OTP_CHECKSUM_STATUS: Register = Register::new(OTP_BASE + 2, 4, 4, true);
214
215/// How many bytes the receive buffer is holding, the high bits of the count.
216///
217/// Read this pair twice and take the larger answer. A read of the two bytes can report a
218/// count below the true one, and the reference guards against it the same way.
219pub const RX_BUFFER_NB_BYTES_MSB: Register = Register::new(RX_TOP_BASE + 200, 0, 5, true);
220
221/// The low bits of that count.
222pub const RX_BUFFER_NB_BYTES_LSB: Register = Register::new(RX_TOP_BASE + 201, 0, 8, true);
223
224/// Which radio each of the eight channels takes its samples from, one bit per channel.
225pub const RX_RADIO_SELECT: Register = Register::new(RX_TOP_BASE + 16, 0, 8, false);
226
227/// How heavily the channel power reading is filtered.
228pub const RX_RSSI_FILTER_ALPHA: Register = Register::new(RX_TOP_BASE + 17, 3, 5, false);
229
230/// What a channel power reading starts from before anything is heard.
231pub const RX_RSSI_DEFAULT: Register = Register::new(RX_TOP_BASE + 18, 0, 8, false);
232
233/// The level the channel gain control backs off above.
234pub const RX_GAIN_THRESHOLD_HIGH: Register = Register::new(RX_TOP_BASE + 19, 0, 8, false);
235
236/// The level it comes back below.
237pub const RX_GAIN_THRESHOLD_LOW: Register = Register::new(RX_TOP_BASE + 20, 0, 8, false);
238
239/// The most the channel gain control will attenuate.
240pub const RX_GAIN_MAX_ATTENUATION: Register = Register::new(RX_TOP_BASE + 21, 4, 4, false);
241
242/// The least it will attenuate.
243pub const RX_GAIN_MIN_ATTENUATION: Register = Register::new(RX_TOP_BASE + 21, 0, 4, false);
244
245/// Whether the gain control microcontroller drives the channel gain rather than the host.
246pub const RX_GAIN_AUTOMATIC: Register = Register::new(RX_TOP_BASE + 23, 0, 2, false);
247
248/// The fixed channel gain, which is taken only when the host drives it.
249pub const RX_CHANNEL_GAIN: Register = Register::new(RX_TOP_BASE + 25, 0, 4, false);
250
251/// Whether that fixed gain is to be taken.
252pub const RX_CHANNEL_GAIN_VALID: Register = Register::new(RX_TOP_BASE + 25, 4, 1, false);
253
254/// Which correlators are clocked, one bit per channel.
255pub const RX_CORRELATOR_CLOCK_ENABLE: Register = Register::new(RX_TOP_BASE + 32, 0, 8, false);
256
257/// Which spreading factors the correlators look for, one bit each counting from SF5.
258pub const RX_CORRELATOR_SF_ENABLE: Register = Register::new(RX_TOP_BASE + 34, 0, 8, false);
259
260/// Whether a correlator takes only the first edge it detects.
261pub const RX_CORRELATOR_FIRST_EDGE: Register = Register::new(RX_TOP_BASE + 35, 0, 8, false);
262
263/// Whether a correlator clears its accumulator between detections.
264pub const RX_CORRELATOR_CLEAR: Register = Register::new(RX_TOP_BASE + 36, 0, 8, false);
265
266/// Whether the notch that removes the carrier at zero is in circuit.
267pub const RX_DC_NOTCH_ENABLE: Register = Register::new(RX_TOP_BASE + 96, 0, 1, false);
268
269/// Whether the receive filter is held at its default rather than tracking the gain.
270pub const RX_FORCE_DEFAULT_FILTER: Register = Register::new(RX_TOP_BASE + 117, 3, 1, false);
271
272/// The level the demodulator gain control aims for.
273pub const RX_GAIN_TARGET_LEVEL: Register = Register::new(RX_TOP_BASE + 120, 6, 2, false);
274
275/// Whether a gain drop is compensated for in the demodulator.
276pub const RX_GAIN_DROP_COMPENSATION: Register = Register::new(RX_TOP_BASE + 120, 4, 1, false);
277
278/// How many preamble symbols a receiver expects, low bits.
279pub const RX_PREAMBLE_SYMBOLS_LSB: Register = Register::new(RX_TOP_BASE + 131, 0, 8, false);
280
281/// The high bits of that count.
282pub const RX_PREAMBLE_SYMBOLS_MSB: Register = Register::new(RX_TOP_BASE + 132, 0, 8, false);
283
284/// Which peaks the frequency transform takes.
285pub const RX_DFT_PEAK_MODE: Register = Register::new(RX_TOP_BASE + 135, 4, 2, false);
286
287/// Where the first sync symbol sits for SF5, which has only the private form.
288pub const RX_SYNC_SF5_PEAK1: Register = Register::new(RX_TOP_BASE + 138, 0, 5, false);
289
290/// Where the second one sits.
291pub const RX_SYNC_SF5_PEAK2: Register = Register::new(RX_TOP_BASE + 139, 0, 5, false);
292
293/// The same for SF6.
294pub const RX_SYNC_SF6_PEAK1: Register = Register::new(RX_TOP_BASE + 140, 0, 5, false);
295
296/// And its second symbol.
297pub const RX_SYNC_SF6_PEAK2: Register = Register::new(RX_TOP_BASE + 141, 0, 5, false);
298
299/// Where the first sync symbol sits for SF7 through SF12, which is what says whether the
300/// receivers are listening to a public network or a private one.
301pub const RX_SYNC_SF7_TO_SF12_PEAK1: Register = Register::new(RX_TOP_BASE + 142, 0, 5, false);
302
303/// Where the second one sits.
304pub const RX_SYNC_SF7_TO_SF12_PEAK2: Register = Register::new(RX_TOP_BASE + 143, 0, 5, false);
305
306/// The proportional gain the fine timing uses while it is finding a packet.
307pub const RX_FINE_TIMING_GAIN_AUTO: Register = Register::new(RX_TOP_BASE + 146, 6, 2, false);
308
309/// The proportional gain it uses through the payload.
310pub const RX_FINE_TIMING_GAIN_PAYLOAD: Register = Register::new(RX_TOP_BASE + 146, 3, 3, false);
311
312/// Whether the fine timing runs its integrator at SF11.
313pub const RX_FINE_TIMING_INTEGRATE_SF11: Register = Register::new(RX_TOP_BASE + 150, 4, 2, false);
314
315/// Whether it runs it at SF12.
316pub const RX_FINE_TIMING_INTEGRATE_SF12: Register = Register::new(RX_TOP_BASE + 150, 6, 2, false);
317
318/// Whether the timestamping bank rounds its result.
319pub const RX_TIMING_ROUNDING: Register = Register::new(RX_TOP_BASE + 153, 6, 1, false);
320
321/// How the timestamping bank tracks timing.
322pub const RX_TIMING_MODE: Register = Register::new(RX_TOP_BASE + 153, 0, 2, false);
323
324/// The proportional gain the timestamping bank uses while finding a packet.
325pub const RX_TIMING_GAIN_AUTO: Register = Register::new(RX_TOP_BASE + 154, 6, 2, false);
326
327/// The proportional gain it uses through the payload.
328pub const RX_TIMING_GAIN_PAYLOAD: Register = Register::new(RX_TOP_BASE + 154, 3, 3, false);
329
330/// The proportional gain it uses through the preamble.
331pub const RX_TIMING_GAIN_PREAMBLE: Register = Register::new(RX_TOP_BASE + 154, 0, 3, false);
332
333/// The integral gain it uses while finding a packet.
334pub const RX_TIMING_INTEGRAL_AUTO: Register = Register::new(RX_TOP_BASE + 155, 6, 2, false);
335
336/// The integral gain it uses through the payload.
337pub const RX_TIMING_INTEGRAL_PAYLOAD: Register = Register::new(RX_TOP_BASE + 155, 3, 3, false);
338
339/// The integral gain it uses through the preamble.
340pub const RX_TIMING_INTEGRAL_PREAMBLE: Register = Register::new(RX_TOP_BASE + 155, 0, 3, false);
341
342/// Whether the timestamping bank runs its integrator at SF11.
343pub const RX_TIMING_INTEGRATE_SF11: Register = Register::new(RX_TOP_BASE + 158, 4, 2, false);
344
345/// Whether it runs it at SF12.
346pub const RX_TIMING_INTEGRATE_SF12: Register = Register::new(RX_TOP_BASE + 158, 6, 2, false);
347
348/// The high bits of the drift that turns a frequency error into a timing one.
349///
350/// The field is four bits wide, not eight. The mantissa never reaches twelve bits, so the
351/// high half always fits, but a wider write would land in the register beside it.
352pub const RX_DRIFT_MANTISSA_MSB: Register = Register::new(RX_TOP_BASE + 160, 0, 4, false);
353
354/// The low bits of that drift.
355pub const RX_DRIFT_MANTISSA_LSB: Register = Register::new(RX_TOP_BASE + 161, 0, 8, false);
356
357/// How far the drift mantissa is shifted.
358pub const RX_DRIFT_EXPONENT: Register = Register::new(RX_TOP_BASE + 162, 0, 3, false);
359
360/// Whether the symbol time is taken with the opposite sign.
361pub const RX_DRIFT_INVERT_SYMBOL_TIME: Register = Register::new(RX_TOP_BASE + 163, 2, 1, false);
362
363/// How close a frequency has to be before the receiver calls it synchronized.
364pub const RX_FREQUENCY_SYNC_THRESHOLD: Register = Register::new(RX_TOP_BASE + 171, 0, 4, false);
365
366/// How far apart the correlators and the demodulators are allowed to be, high bits.
367pub const RX_MODEM_SYNC_DELTA_MSB: Register = Register::new(RX_TOP_BASE + 183, 0, 3, false);
368
369/// The low bits of that difference.
370pub const RX_MODEM_SYNC_DELTA_LSB: Register = Register::new(RX_TOP_BASE + 184, 0, 8, false);
371
372/// Which of the first eight demodulators are enabled.
373pub const MODEM_ENABLE_FULL: Register = Register::new(OTP_BASE + 8, 0, 8, false);
374
375/// Which of the second eight are.
376pub const MODEM_ENABLE_LIMITED: Register = Register::new(OTP_BASE + 9, 0, 8, false);
377
378/// Whether the receivers run at all.
379pub const COMMON_GLOBAL_ENABLE: Register = Register::new(COMMON_BASE + 5, 3, 1, false);
380
381/// Whether the frequency shift keying demodulator runs.
382pub const COMMON_FSK_MODEM_ENABLE: Register = Register::new(COMMON_BASE + 5, 2, 1, false);
383
384/// Whether the eight multi-spreading-factor demodulators run.
385pub const COMMON_MULTI_MODEM_ENABLE: Register = Register::new(COMMON_BASE + 5, 1, 1, false);
386
387/// Whether the single demodulator fixed to one spreading factor runs.
388pub const COMMON_SERVICE_MODEM_ENABLE: Register = Register::new(COMMON_BASE + 5, 0, 1, false);
389
390/// The high bits of the intermediate frequency the fixed demodulator listens on.
391pub const SERVICE_FREQUENCY_MSB: Register =
392    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE, 0, 5, false);
393
394/// The low bits of it.
395pub const SERVICE_FREQUENCY_LSB: Register =
396    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 1, 0, 8, false);
397
398/// Which radio that demodulator takes its samples from.
399pub const SERVICE_RADIO_SELECT: Register =
400    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 2, 0, 1, false);
401
402/// Where the first sync symbol sits for the fixed demodulator.
403pub const SERVICE_SYNC_PEAK1: Register =
404    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 46, 0, 5, false);
405
406/// Where the second one sits.
407pub const SERVICE_SYNC_PEAK2: Register =
408    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 47, 0, 5, false);
409
410/// The high bits of the intermediate frequency the keying demodulator listens on.
411pub const FSK_FREQUENCY_MSB: Register =
412    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 80, 0, 5, false);
413
414/// The low bits of it.
415pub const FSK_FREQUENCY_LSB: Register =
416    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 81, 0, 8, false);
417
418/// Which radio that demodulator takes its samples from.
419pub const FSK_RADIO_SELECT: Register =
420    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 84, 1, 1, false);
421/// How many bytes of the sync pattern the FSK receiver matches, less one.
422pub const FSK_PATTERN_SIZE: Register =
423    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 83, 3, 3, false);
424
425/// How wide the FSK receiver listens, as a power of two.
426pub const FSK_BANDWIDTH_EXPONENT: Register =
427    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 83, 0, 3, false);
428
429/// Whether the FSK receiver compares an address byte before taking a packet.
430pub const FSK_ADDRESS_COMPARISON: Register =
431    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 83, 6, 2, false);
432
433/// Whether a packet carries its own length, rather than every packet being one size.
434pub const FSK_PACKET_MODE: Register = Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 82, 0, 1, false);
435
436/// Whether the FSK receiver checks a packet's checksum.
437pub const FSK_CRC_ENABLE: Register = Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 82, 1, 1, false);
438
439/// How the bits are kept from settling at one level for too long.
440pub const FSK_DCFREE_ENCODING: Register =
441    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 82, 2, 2, false);
442
443/// Which of the two checksums a packet carries.
444pub const FSK_CRC_IBM: Register = Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 82, 4, 1, false);
445
446/// Whether the FSK receiver inverts what it hears.
447pub const FSK_INVERT_RX: Register = Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 84, 0, 1, false);
448
449/// Whether it swaps the two halves of the signal.
450pub const FSK_INVERT_IQ: Register = Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 84, 3, 1, false);
451
452/// Whether the FSK receiver corrects for a sender being off frequency.
453pub const FSK_AUTO_AFC: Register = Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 84, 2, 1, false);
454
455/// How long the FSK receiver measures a signal level over.
456pub const FSK_RSSI_LENGTH: Register = Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 85, 5, 3, false);
457
458/// How far the bit timing may drift before a packet is given up on.
459pub const FSK_ERROR_TOLERANCE: Register =
460    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 85, 0, 5, false);
461
462/// The address a packet has to carry, when the receiver is comparing one.
463pub const FSK_NODE_ADDRESS: Register =
464    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 86, 0, 8, false);
465
466/// The address every device takes.
467pub const FSK_BROADCAST_ADDRESS: Register =
468    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 87, 0, 8, false);
469
470/// How long a packet is when it does not carry its own length.
471pub const FSK_PAYLOAD_LENGTH: Register =
472    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 88, 0, 8, false);
473
474/// How long the FSK receiver waits for a packet, high bits.
475pub const FSK_TIMEOUT_MSB: Register = Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 89, 0, 2, false);
476
477/// How long it waits, low byte.
478pub const FSK_TIMEOUT_LSB: Register = Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 90, 0, 8, false);
479
480/// The bit rate the FSK receiver runs at, high byte.
481pub const FSK_BITRATE_MSB: Register = Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 91, 0, 8, false);
482
483/// The bit rate, low byte.
484pub const FSK_BITRATE_LSB: Register = Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 92, 0, 8, false);
485
486/// How many bytes of sync word the FSK receiver holds.
487pub const FSK_SYNC_WORD_BYTES: u8 = 8;
488
489/// One byte of the sync word the FSK receiver looks for.
490///
491/// # Arguments
492///
493/// * `byte` - which byte, counting from the least significant. Anything past the last is
494///   read as the last.
495///
496/// # Returns
497///
498/// The register holding it. They run backwards through the address space, so the least
499/// significant byte sits at the highest address.
500///
501/// # Examples
502///
503/// ```
504/// use pamoja_radios::sx1302::register::fsk_sync_word;
505///
506/// assert_eq!(fsk_sync_word(0).address, 0x5b00 + 100);
507/// assert_eq!(fsk_sync_word(7).address, 0x5b00 + 93, "and they count down");
508/// ```
509#[must_use]
510pub const fn fsk_sync_word(byte: u8) -> Register {
511    let byte = if byte >= FSK_SYNC_WORD_BYTES {
512        FSK_SYNC_WORD_BYTES - 1
513    } else {
514        byte
515    } as u16;
516    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 100 - byte, 0, 8, false)
517}
518
519/// Whether the service receiver runs its notch filter.
520pub const SERVICE_DC_NOTCH_ENABLE: Register =
521    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 3, 0, 1, false);
522
523/// Holds the service receiver to the default filter rather than one chosen for the rate.
524pub const SERVICE_FORCE_DEFAULT_FIR: Register =
525    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 24, 3, 1, false);
526
527/// Compensates the service receiver gain into its detector.
528pub const SERVICE_DAGC_IN_COMP: Register =
529    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 25, 6, 1, false);
530
531/// What signal level the service receiver gain aims for.
532pub const SERVICE_DAGC_TARGET_LEVEL: Register =
533    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 27, 6, 2, false);
534
535/// Whether a gain drop is compensated for in the service receiver.
536pub const SERVICE_DAGC_GAIN_DROP_COMP: Register =
537    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 27, 4, 1, false);
538
539/// The bandwidth the service receiver runs at.
540pub const SERVICE_BANDWIDTH: Register =
541    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 33, 4, 4, false);
542
543/// The one spreading factor the service receiver looks for.
544pub const SERVICE_SPREADING_FACTOR: Register =
545    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 33, 0, 4, false);
546
547/// Whether the service receiver expects a low data rate optimization.
548pub const SERVICE_PPM_OFFSET: Register =
549    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 34, 4, 2, false);
550
551/// Whether the service receiver is clocked at all.
552pub const SERVICE_MODEM_ENABLE: Register =
553    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 34, 3, 1, false);
554
555/// The coding rate the service receiver assumes when a header does not carry one.
556pub const SERVICE_CODING_RATE: Register =
557    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 34, 0, 3, false);
558
559/// Whether the service receiver runs the finer synchronization the fast rates need.
560pub const SERVICE_FINE_SYNC: Register =
561    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 35, 5, 1, false);
562
563/// Starts the service receiver once it is configured.
564pub const SERVICE_MODEM_START: Register =
565    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 35, 4, 1, false);
566
567/// Whether the service receiver listens, rather than checking for activity.
568pub const SERVICE_CAD_RX_TX: Register =
569    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 35, 2, 2, false);
570
571/// Whether the service receiver expects packets without a header.
572pub const SERVICE_IMPLICIT_HEADER: Register =
573    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 35, 1, 1, false);
574
575/// Whether the service receiver expects a checksum on a packet without a header.
576pub const SERVICE_CRC_ENABLE: Register =
577    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 35, 0, 1, false);
578
579/// How long a packet without a header is.
580pub const SERVICE_PAYLOAD_LENGTH: Register =
581    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 36, 0, 8, false);
582
583/// How many preamble symbols the service receiver expects, low byte.
584pub const SERVICE_PREAMBLE_LSB: Register =
585    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 39, 0, 8, false);
586
587/// How many preamble symbols the service receiver expects, high byte.
588pub const SERVICE_PREAMBLE_MSB: Register =
589    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 40, 0, 8, false);
590
591/// How the service receiver picks a peak out of its transform.
592pub const SERVICE_DFT_PEAK_MODE: Register =
593    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 42, 4, 2, false);
594
595/// How hard the service receiver corrects timing on its own.
596pub const SERVICE_TIMING_GAIN_AUTOMATIC: Register =
597    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 50, 6, 2, false);
598
599/// How hard the service receiver corrects timing through a preamble.
600pub const SERVICE_TIMING_GAIN_PREAMBLE: Register =
601    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 50, 0, 3, false);
602
603/// Whether the service receiver accumulates a timing correction, and over what.
604pub const SERVICE_TIMING_GAIN_INTEGRAL: Register =
605    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 51, 6, 2, false);
606
607/// How hard the service receiver corrects timing through a payload.
608pub const SERVICE_TIMING_GAIN_PAYLOAD: Register =
609    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 51, 3, 3, false);
610
611/// How far the service receiver expects a carrier to drift, high bits.
612pub const SERVICE_DRIFT_MANTISSA_MSB: Register =
613    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 54, 0, 4, false);
614
615/// How far the service receiver expects a carrier to drift, low byte.
616pub const SERVICE_DRIFT_MANTISSA_LSB: Register =
617    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 55, 0, 8, false);
618
619/// What the service receiver drift is scaled by.
620pub const SERVICE_DRIFT_EXPONENT: Register =
621    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 56, 0, 3, false);
622
623/// Which way the service receiver applies a drift over a symbol.
624pub const SERVICE_DRIFT_INVERT_SYMBOL_TIME: Register =
625    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 57, 2, 1, false);
626
627/// How many peaks the service receiver counts before it believes a preamble.
628pub const SERVICE_DETECT_PEAK_COUNT: Register =
629    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 64, 0, 3, false);
630
631/// How many peaks the service receiver counts on its second pass.
632pub const SERVICE_DETECT_PEAK_COUNT2: Register =
633    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 64, 4, 3, false);
634
635/// Whether the service receiver weighs a symbol gain into detection.
636pub const SERVICE_DETECT_USE_GAIN_SYMBOL: Register =
637    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 66, 7, 1, false);
638
639/// How far above the noise a peak has to be for the service receiver to take it.
640pub const SERVICE_DETECT_PEAK_TO_NOISE: Register =
641    Register::new(RX_TOP_LORA_SERVICE_FSK_BASE + 66, 0, 7, false);
642
643/// The settings that decide how hard a correlator looks for one spreading factor.
644#[derive(Clone, Copy, Debug, PartialEq, Eq)]
645pub struct Correlator {
646    /// The ratio the accumulated peak has to reach above the noise.
647    pub accumulated_ratio: Register,
648    /// The ratio a single peak has to reach.
649    pub peak_ratio: Register,
650    /// How many peaks are wanted.
651    pub peaks: Register,
652    /// How many are wanted on the second pass.
653    pub second_peaks: Register,
654}
655
656/// The pair of registers holding one channel intermediate frequency.
657///
658/// The eight pairs run from the start of the block, two bytes each, the high bits first.
659///
660/// # Arguments
661///
662/// * `channel` - which of the eight, counting from zero. Higher is clamped to seven.
663///
664/// # Returns
665///
666/// The high bits and then the low bits.
667///
668/// # Examples
669///
670/// ```
671/// use pamoja_radios::sx1302::register::channel_frequency;
672///
673/// let [high, low] = channel_frequency(0);
674/// assert_eq!((high.address, high.width), (0x5800, 5));
675/// assert_eq!((low.address, low.width), (0x5801, 8));
676///
677/// // The last channel is seven pairs along.
678/// assert_eq!(channel_frequency(7)[0].address, 0x580e);
679/// ```
680#[must_use]
681pub const fn channel_frequency(channel: u8) -> [Register; 2] {
682    let channel = if channel > 7 { 7 } else { channel } as u16;
683    [
684        Register::new(RX_TOP_BASE + channel * 2, 0, 5, false),
685        Register::new(RX_TOP_BASE + channel * 2 + 1, 0, 8, false),
686    ]
687}
688
689/// The correlator settings for one spreading factor.
690///
691/// The eight sets run seven bytes apart, starting at SF5.
692///
693/// # Arguments
694///
695/// * `spreading_factor` - from 5 to 12. Anything outside is clamped into it.
696///
697/// # Returns
698///
699/// The four registers that tune detection for it.
700///
701/// # Examples
702///
703/// ```
704/// use pamoja_radios::sx1302::register::correlator;
705///
706/// // SF7 is two sets along from SF5, so fourteen bytes.
707/// assert_eq!(correlator(5).accumulated_ratio.address + 14, correlator(7).accumulated_ratio.address);
708/// assert_eq!(correlator(7).peaks.width, 3);
709/// ```
710#[must_use]
711pub const fn correlator(spreading_factor: u8) -> Correlator {
712    let spreading_factor = if spreading_factor < 5 {
713        5
714    } else if spreading_factor > 12 {
715        12
716    } else {
717        spreading_factor
718    };
719    let base = RX_TOP_BASE + 38 + (spreading_factor as u16 - 5) * 7;
720    Correlator {
721        accumulated_ratio: Register::new(base, 0, 7, false),
722        peak_ratio: Register::new(base + 2, 0, 7, false),
723        peaks: Register::new(base + 4, 3, 3, false),
724        second_peaks: Register::new(base + 5, 2, 3, false),
725    }
726}
727
728/// Which bank of demodulator settings a register belongs to.
729///
730/// The chip keeps two: one tuned for reading a packet, one for timing it. Both are set, and
731/// the second only matters where a receiver is demodulating twice over.
732#[derive(Clone, Copy, Debug, PartialEq, Eq)]
733pub enum Bank {
734    /// The bank tuned for reading the packet.
735    Demodulation,
736    /// The bank tuned for timing it.
737    Timestamping,
738}
739
740/// Whether a bank tracks the frequency of one spreading factor.
741///
742/// Four spreading factors share a byte, two bits each, so the eight run across two.
743///
744/// # Arguments
745///
746/// * `bank` - which bank to set.
747/// * `spreading_factor` - from 5 to 12. Anything outside is clamped into it.
748///
749/// # Returns
750///
751/// The register.
752///
753/// # Examples
754///
755/// ```
756/// use pamoja_radios::sx1302::register::{frequency_tracking, Bank};
757///
758/// // SF5 starts a byte and SF8 ends it; SF9 starts the next.
759/// assert_eq!(frequency_tracking(Bank::Demodulation, 5).offset, 0);
760/// assert_eq!(frequency_tracking(Bank::Demodulation, 8).offset, 6);
761/// assert_eq!(
762///     frequency_tracking(Bank::Demodulation, 9).address,
763///     frequency_tracking(Bank::Demodulation, 5).address + 1
764/// );
765/// ```
766#[must_use]
767pub const fn frequency_tracking(bank: Bank, spreading_factor: u8) -> Register {
768    let spreading_factor = if spreading_factor < 5 {
769        5
770    } else if spreading_factor > 12 {
771        12
772    } else {
773        spreading_factor
774    };
775    let base = match bank {
776        Bank::Demodulation => RX_TOP_BASE + 165,
777        Bank::Timestamping => RX_TOP_BASE + 167,
778    };
779    let address = if spreading_factor <= 8 {
780        base
781    } else {
782        base + 1
783    };
784    Register::new(address, ((spreading_factor - 5) % 4) * 2, 2, false)
785}
786
787/// The drift correction applied at one spreading factor.
788///
789/// Four share a byte, two bits each, the same way the tracking settings do.
790///
791/// # Arguments
792///
793/// * `spreading_factor` - from 5 to 12. Anything outside is clamped into it.
794///
795/// # Returns
796///
797/// The register.
798///
799/// # Examples
800///
801/// ```
802/// use pamoja_radios::sx1302::register::drift_correction;
803///
804/// assert_eq!(drift_correction(5).offset, 0);
805/// assert_eq!(drift_correction(12).offset, 6);
806/// ```
807#[must_use]
808pub const fn drift_correction(spreading_factor: u8) -> Register {
809    let spreading_factor = if spreading_factor < 5 {
810        5
811    } else if spreading_factor > 12 {
812        12
813    } else {
814        spreading_factor
815    };
816    let address = if spreading_factor <= 8 {
817        RX_TOP_BASE + 185
818    } else {
819        RX_TOP_BASE + 186
820    };
821    Register::new(address, ((spreading_factor - 5) % 4) * 2, 2, false)
822}
823
824/// How far one channel is offset when the arbiter lines its receivers up.
825///
826/// Two channels share a byte, a nibble each, the even one low.
827///
828/// # Arguments
829///
830/// * `channel` - which of the eight, counting from zero. Higher is clamped to seven.
831///
832/// # Returns
833///
834/// The register.
835///
836/// # Examples
837///
838/// ```
839/// use pamoja_radios::sx1302::register::channel_sync_offset;
840///
841/// assert_eq!(channel_sync_offset(0).offset, 0);
842/// assert_eq!(channel_sync_offset(1).offset, 4);
843/// assert_eq!(
844///     channel_sync_offset(2).address,
845///     channel_sync_offset(0).address + 1
846/// );
847/// ```
848#[must_use]
849pub const fn channel_sync_offset(channel: u8) -> Register {
850    let channel = if channel > 7 { 7 } else { channel };
851    let address = ARB_MCU_BASE + 29 + (channel / 2) as u16;
852    let offset = if channel % 2 == 0 { 0 } else { 4 };
853    Register::new(address, offset, 4, false)
854}
855
856/// What the gain control microcontroller is doing.
857///
858/// It counts up as the microcontroller takes each group of settings, which is how a host
859/// knows a group was received rather than merely sent.
860pub const AGC_MCU_STATUS: Register = Register::new(AGC_MCU_BASE + 1, 0, 8, true);
861
862/// What the arbiter microcontroller is doing.
863pub const ARB_MCU_STATUS: Register = Register::new(ARB_MCU_BASE + 1, 0, 8, true);
864
865/// Whether the concentrator takes its clock from the front end on the first chain.
866pub const CLOCK_RADIO_A_SELECT: Register = Register::new(CLK_CTRL_BASE, 0, 1, false);
867
868/// Whether it takes it from the second.
869pub const CLOCK_RADIO_B_SELECT: Register = Register::new(CLK_CTRL_BASE, 1, 1, false);
870
871/// Whether the dividers that make the other clocks from it are running.
872pub const CLOCK_DIVIDER_ENABLE: Register = Register::new(CLK_CTRL_BASE, 2, 1, false);
873
874/// One of the four mailboxes the host writes settings into.
875///
876/// The four count downward: mailbox zero sits at the highest address and mailbox three, the
877/// one that says which group was just written, at the lowest. Reading them in address order
878/// would number them backward.
879///
880/// # Arguments
881///
882/// * `mailbox` - which of the four, from zero. Higher is clamped to three.
883///
884/// # Returns
885///
886/// The register.
887///
888/// # Examples
889///
890/// ```
891/// use pamoja_radios::sx1302::register::agc_mailbox_write;
892///
893/// // Mailbox three is the one the host announces a group with, and it is the lowest.
894/// assert!(agc_mailbox_write(3).address < agc_mailbox_write(0).address);
895/// assert_eq!(agc_mailbox_write(0).address - agc_mailbox_write(3).address, 3);
896/// ```
897#[must_use]
898pub const fn agc_mailbox_write(mailbox: u8) -> Register {
899    let mailbox = if mailbox > 3 { 3 } else { mailbox } as u16;
900    Register::new(AGC_MCU_BASE + 12 - mailbox, 0, 8, false)
901}
902
903/// One of the four mailboxes the microcontroller answers through.
904///
905/// These count downward as well, and sit above the ones the host writes.
906///
907/// # Arguments
908///
909/// * `mailbox` - which of the four, from zero. Higher is clamped to three.
910///
911/// # Returns
912///
913/// The register.
914///
915/// # Examples
916///
917/// ```
918/// use pamoja_radios::sx1302::register::{agc_mailbox_read, agc_mailbox_write};
919///
920/// // A setting is written to one mailbox and read back from another.
921/// assert!(agc_mailbox_read(0).address > agc_mailbox_write(0).address);
922/// assert!(agc_mailbox_read(0).read_only);
923/// ```
924#[must_use]
925pub const fn agc_mailbox_read(mailbox: u8) -> Register {
926    let mailbox = if mailbox > 3 { 3 } else { mailbox } as u16;
927    Register::new(AGC_MCU_BASE + 16 - mailbox, 0, 8, true)
928}
929
930/// One of the four registers the arbiter is configured through.
931///
932/// Unlike the mailboxes, these count upward.
933///
934/// # Arguments
935///
936/// * `register` - which of the four, from zero. Higher is clamped to three.
937///
938/// # Returns
939///
940/// The register.
941///
942/// # Examples
943///
944/// ```
945/// use pamoja_radios::sx1302::register::arbiter_config;
946///
947/// assert_eq!(arbiter_config(1).address - arbiter_config(0).address, 1);
948/// ```
949#[must_use]
950pub const fn arbiter_config(register: u8) -> Register {
951    let register = if register > 3 { 3 } else { register } as u16;
952    Register::new(ARB_MCU_BASE + 9 + register, 0, 8, false)
953}
954
955/// One of the sixteen registers the arbiter reports through.
956///
957/// # Arguments
958///
959/// * `register` - which of the sixteen, from zero. Higher is clamped to fifteen.
960///
961/// # Returns
962///
963/// The register.
964///
965/// # Examples
966///
967/// ```
968/// use pamoja_radios::sx1302::register::arbiter_status;
969///
970/// // The first carries the firmware version the arbiter is running.
971/// assert!(arbiter_status(0).read_only);
972/// assert_eq!(arbiter_status(15).address - arbiter_status(0).address, 15);
973/// ```
974#[must_use]
975pub const fn arbiter_status(register: u8) -> Register {
976    let register = if register > 15 { 15 } else { register } as u16;
977    Register::new(ARB_MCU_BASE + 13 + register, 0, 8, true)
978}
979
980/// Whether the counter listens to a pulse per second line.
981pub const TIMESTAMP_PPS_ENABLE: Register = Register::new(TIMESTAMP_BASE, 0, 1, false);
982
983/// Which edge of that line the counter takes.
984pub const TIMESTAMP_PPS_POLARITY: Register = Register::new(TIMESTAMP_BASE, 1, 1, false);
985
986#[cfg(test)]
987mod tests {
988    use super::*;
989
990    // The block addresses the reference implementation lists, which every register is an
991    // offset from.
992    #[test]
993    fn the_blocks_are_where_the_chip_puts_them() {
994        assert_eq!(EXTERNAL_MEMORY_BASE, 0x0000);
995        assert_eq!(RX_BUFFER_BASE, 0x4000);
996        assert_eq!(TX_TOP_A_BASE, 0x5200);
997        assert_eq!(TX_TOP_B_BASE, 0x5400);
998        assert_eq!(COMMON_BASE, 0x5600);
999        assert_eq!(GPIO_BASE, 0x5640);
1000        assert_eq!(MBIST_BASE, 0x56c0);
1001        assert_eq!(RADIO_FE_BASE, 0x5700);
1002        assert_eq!(AGC_MCU_BASE, 0x5780);
1003        assert_eq!(CLK_CTRL_BASE, 0x57c0);
1004        assert_eq!(RX_TOP_BASE, 0x5800);
1005        assert_eq!(RX_TOP_LORA_SERVICE_FSK_BASE, 0x5b00);
1006        assert_eq!(CAPTURE_RAM_BASE, 0x6000);
1007        assert_eq!(ARB_MCU_BASE, 0x6080);
1008        assert_eq!(TIMESTAMP_BASE, 0x6100);
1009        assert_eq!(OTP_BASE, 0x6180);
1010    }
1011
1012    #[test]
1013    fn the_registers_sit_where_the_table_puts_them() {
1014        assert_eq!(COMMON_PAGE, Register::new(0x5600, 0, 2, false));
1015        assert_eq!(COMMON_VERSION, Register::new(0x5606, 0, 8, true));
1016        assert_eq!(OTP_BYTE_ADDR, Register::new(0x6180, 0, 8, false));
1017        assert_eq!(OTP_RD_DATA, Register::new(0x6181, 0, 8, true));
1018        assert_eq!(OTP_FSM_READY, Register::new(0x6182, 0, 1, true));
1019        assert_eq!(OTP_CHECKSUM_STATUS, Register::new(0x6182, 4, 4, true));
1020    }
1021
1022    #[test]
1023    fn the_two_microcontrollers_share_one_control_byte_each() {
1024        // Every gain control bit is in the byte at the block base.
1025        for register in [
1026            AGC_MCU_CLK_EN,
1027            AGC_MCU_CLEAR,
1028            AGC_MCU_HOST_PROG,
1029            AGC_MCU_PARITY_ERROR,
1030        ] {
1031            assert_eq!(register.address, AGC_MCU_BASE);
1032            assert_eq!(register.width, 1);
1033        }
1034        for register in [
1035            ARB_MCU_CLK_EN,
1036            ARB_MCU_CLEAR,
1037            ARB_MCU_HOST_PROG,
1038            ARB_MCU_PARITY_ERROR,
1039        ] {
1040            assert_eq!(register.address, ARB_MCU_BASE);
1041            assert_eq!(register.width, 1);
1042        }
1043
1044        // The chip reports these; a host that writes one is writing to a wall.
1045        for register in [
1046            AGC_MCU_PARITY_ERROR,
1047            ARB_MCU_PARITY_ERROR,
1048            COMMON_VERSION,
1049            OTP_RD_DATA,
1050            OTP_FSM_READY,
1051            OTP_CHECKSUM_STATUS,
1052        ] {
1053            assert!(register.read_only, "{register:?} is reported, not set");
1054        }
1055
1056        // And these are the ones a host drives.
1057        for register in [
1058            AGC_MCU_HOST_PROG,
1059            ARB_MCU_HOST_PROG,
1060            COMMON_PAGE,
1061            OTP_BYTE_ADDR,
1062        ] {
1063            assert!(!register.read_only, "{register:?} is set by the host");
1064        }
1065    }
1066
1067    #[test]
1068    fn the_front_end_controls_sit_where_the_table_puts_them() {
1069        assert_eq!(COMMON_CLK32_RIF_CTRL, Register::new(0x5601, 4, 1, false));
1070        assert_eq!(COMMON_HOST_RADIO_CTRL, Register::new(0x5601, 3, 1, false));
1071        assert_eq!(RF_EN_A_RADIO_EN, Register::new(0x5783, 2, 1, false));
1072        assert_eq!(RF_EN_A_RADIO_RST, Register::new(0x5783, 3, 1, false));
1073        assert_eq!(RF_EN_B_RADIO_EN, Register::new(0x5784, 2, 1, false));
1074        assert_eq!(RF_EN_B_RADIO_RST, Register::new(0x5784, 3, 1, false));
1075
1076        // The two chains have controls of their own, one byte apart.
1077        assert_eq!(RF_EN_B_RADIO_EN.address - RF_EN_A_RADIO_EN.address, 1);
1078        assert_ne!(RF_EN_A_RADIO_RST, RF_EN_B_RADIO_RST);
1079
1080        // Enable and reset share a byte, so writing one must not disturb the other.
1081        let byte = RF_EN_A_RADIO_EN.encode(0, 1);
1082        let byte = RF_EN_A_RADIO_RST.encode(byte, 1);
1083        assert_eq!(
1084            RF_EN_A_RADIO_EN.decode(byte),
1085            1,
1086            "the front end stayed powered"
1087        );
1088        assert_eq!(RF_EN_A_RADIO_RST.decode(byte), 1);
1089    }
1090
1091    #[test]
1092    fn a_narrow_register_leaves_its_neighbors_alone() {
1093        // Taking the microcontroller for programming must not stop its clock.
1094        let byte = AGC_MCU_CLK_EN.encode(0x00, 1);
1095        assert_eq!(AGC_MCU_CLK_EN.decode(byte), 1);
1096
1097        let byte = AGC_MCU_HOST_PROG.encode(byte, 1);
1098        assert_eq!(AGC_MCU_HOST_PROG.decode(byte), 1);
1099        assert_eq!(AGC_MCU_CLK_EN.decode(byte), 1, "the clock stayed on");
1100
1101        let byte = AGC_MCU_HOST_PROG.encode(byte, 0);
1102        assert_eq!(AGC_MCU_HOST_PROG.decode(byte), 0);
1103        assert_eq!(
1104            AGC_MCU_CLK_EN.decode(byte),
1105            1,
1106            "and stayed on after release"
1107        );
1108    }
1109
1110    #[test]
1111    fn a_whole_byte_needs_no_read_first() {
1112        assert!(COMMON_VERSION.is_whole_byte());
1113        assert!(OTP_BYTE_ADDR.is_whole_byte());
1114        assert!(!COMMON_PAGE.is_whole_byte());
1115        assert!(!AGC_MCU_CLEAR.is_whole_byte());
1116
1117        // The status byte holds two registers, read from the same read.
1118        let status = 0b1010_0001;
1119        assert_eq!(OTP_FSM_READY.decode(status), 1);
1120        assert_eq!(OTP_CHECKSUM_STATUS.decode(status), 0b1010);
1121    }
1122}