libbladerf_rs/bladerf1/hardware/lms6002d/
loopback.rs1use crate::bladerf1::Band;
2use crate::bladerf1::hardware::lms6002d::bandwidth::BLADERF1_BAND_HIGH;
3use crate::bladerf1::hardware::lms6002d::filters::LpfMode;
4use crate::bladerf1::hardware::lms6002d::gain::LmsLowNoiseAmplifier;
5use crate::bladerf1::hardware::lms6002d::{LMS6002D, LmsPowerAmplifier};
6use crate::{Channel, Error};
7pub const LBEN_OPIN: u8 = 1 << 4;
8pub const LBEN_VGA2IN: u8 = 1 << 5;
9pub const LBEN_LPFIN: u8 = 1 << 6;
10pub const LBEN_MASK: u8 = LBEN_OPIN | LBEN_VGA2IN | LBEN_LPFIN;
11pub const LBRFEN_LNA1: u8 = 1;
12pub const LBRFEN_LNA2: u8 = 2;
13pub const LBRFEN_LNA3: u8 = 3;
14pub const LBRFEN_MASK: u8 = 0xf;
15pub const LOOPBBEN_TXLPF: u8 = 1 << 2;
16pub const LOOPBBEN_TXVGA: u8 = 2 << 2;
17pub const LOOPBBEN_ENVPK: u8 = 3 << 2;
18pub const LOOBBBEN_MASK: u8 = 3 << 2;
19pub enum LmsLoopbackPath {
20 LbpBb,
21 LbpRf,
22}
23#[derive(PartialEq, Debug, Clone)]
24#[repr(u8)]
25pub enum Loopback {
26 None = 0,
27 Firmware,
28 BbTxlpfRxvga2,
29 BbTxvga1Rxvga2,
30 BbTxlpfRxlpf,
31 BbTxvga1Rxlpf,
32 Lna1,
33 Lna2,
34 Lna3,
35 RficBist,
36}
37pub struct BladeRf1LoopbackModes {
38 _name: String,
39 _mode: Loopback,
40}
41impl LMS6002D {
42 pub fn loopback_path(&self, mode: &Loopback) -> crate::Result<()> {
43 let mut loopbben = self.read(0x46)?;
44 let mut lben_lbrf = self.read(0x08)?;
45 loopbben &= !LOOBBBEN_MASK;
46 lben_lbrf &= !(LBRFEN_MASK | LBEN_MASK);
47 match mode {
48 Loopback::None => {}
49 Loopback::BbTxlpfRxvga2 => {
50 loopbben |= LOOPBBEN_TXLPF;
51 lben_lbrf |= LBEN_VGA2IN;
52 }
53 Loopback::BbTxvga1Rxvga2 => {
54 loopbben |= LOOPBBEN_TXVGA;
55 lben_lbrf |= LBEN_VGA2IN;
56 }
57 Loopback::BbTxlpfRxlpf => {
58 loopbben |= LOOPBBEN_TXLPF;
59 lben_lbrf |= LBEN_LPFIN;
60 }
61 Loopback::BbTxvga1Rxlpf => {
62 loopbben |= LOOPBBEN_TXVGA;
63 lben_lbrf |= LBEN_LPFIN;
64 }
65 Loopback::Lna1 => {
66 lben_lbrf |= LBRFEN_LNA1;
67 }
68 Loopback::Lna2 => {
69 lben_lbrf |= LBRFEN_LNA2;
70 }
71 Loopback::Lna3 => {
72 lben_lbrf |= LBRFEN_LNA3;
73 }
74 _ => Err(Error::Argument("Loopback mode not supported"))?,
75 }
76 self.write(0x46, loopbben)?;
77 self.write(0x08, lben_lbrf)
78 }
79 pub fn enable_rf_loopback_switch(&self, enable: bool) -> crate::Result<()> {
80 let mut regval = self.read(0x0b)?;
81 if enable {
82 regval |= 1;
83 } else {
84 regval &= !1;
85 }
86 self.write(0x0b, regval)
87 }
88 pub fn loopback_rx(&self, mode: &Loopback) -> crate::Result<()> {
89 let lpf_mode = self.lpf_get_mode(Channel::Rx)?;
90 match mode {
91 Loopback::None => {
92 self.rxvga1_enable(true)?;
93 self.rxvga2_enable(true)?;
94 self.enable_rf_loopback_switch(false)?;
95 self.enable_lna_power(true)?;
96 let f = &self.get_frequency(Channel::Rx)?;
97 self.set_frequency(Channel::Rx, f.into())?;
98 let f_hz: u64 = f.into();
99 let band = if f_hz < BLADERF1_BAND_HIGH as u64 {
100 Band::Low
101 } else {
102 Band::High
103 };
104 self.select_band(Channel::Rx, band)
105 }
106 Loopback::BbTxvga1Rxvga2 | Loopback::BbTxlpfRxvga2 => {
107 self.rxvga2_enable(true)?;
108 self.lpf_set_mode(Channel::Rx, LpfMode::Disabled)
109 }
110 Loopback::BbTxlpfRxlpf | Loopback::BbTxvga1Rxlpf => {
111 self.rxvga1_enable(false)?;
112 if lpf_mode == LpfMode::Disabled {
113 self.lpf_set_mode(Channel::Rx, LpfMode::Normal)?;
114 }
115 self.rxvga2_enable(true)
116 }
117 Loopback::Lna1 | Loopback::Lna2 | Loopback::Lna3 => {
118 let lms_lna = match mode {
119 Loopback::Lna1 => LmsLowNoiseAmplifier::Lna1,
120 Loopback::Lna2 => LmsLowNoiseAmplifier::Lna2,
121 Loopback::Lna3 => LmsLowNoiseAmplifier::Lna3,
122 _ => return Err(Error::Argument("Could not convert LNA mode.")),
123 };
124 self.enable_lna_power(false)?;
125 self.rxvga1_enable(true)?;
126 if lpf_mode == LpfMode::Disabled {
127 self.lpf_set_mode(Channel::Rx, LpfMode::Normal)?;
128 }
129 self.rxvga2_enable(true)?;
130 let mut regval = self.read(0x25)?;
131 regval &= !0x03;
132 regval |= u8::from(lms_lna);
133 self.write(0x25, regval)?;
134 self.select_lna(lms_lna)?;
135 self.enable_rf_loopback_switch(true)
136 }
137 _ => Err(Error::Argument("Could not convert LNA mode.")),
138 }
139 }
140 pub fn loopback_tx(&self, mode: &Loopback) -> crate::Result<()> {
141 match mode {
142 Loopback::None => {
143 let f = &self.get_frequency(Channel::Tx)?;
144 self.set_frequency(Channel::Tx, f.into())?;
145 let f_hz: u64 = f.into();
146 let band = if f_hz < BLADERF1_BAND_HIGH as u64 {
147 Band::Low
148 } else {
149 Band::High
150 };
151 self.select_band(Channel::Tx, band)
152 }
153 Loopback::BbTxlpfRxvga2
154 | Loopback::BbTxvga1Rxvga2
155 | Loopback::BbTxlpfRxlpf
156 | Loopback::BbTxvga1Rxlpf => Ok(()),
157 Loopback::Lna1 | Loopback::Lna2 | Loopback::Lna3 => {
158 self.select_pa(LmsPowerAmplifier::PaAux)
159 }
160 _ => Err(Error::Argument("Invalid loopback mode encountered")),
161 }
162 }
163 pub fn set_loopback_mode(&self, mode: Loopback) -> crate::Result<()> {
164 match mode {
165 Loopback::None => {}
166 Loopback::BbTxlpfRxvga2 => {}
167 Loopback::BbTxvga1Rxvga2 => {}
168 Loopback::BbTxlpfRxlpf => {}
169 Loopback::BbTxvga1Rxlpf => {}
170 Loopback::Lna1 => {}
171 Loopback::Lna2 => {}
172 Loopback::Lna3 => {}
173 _ => return Err(Error::Argument("Unsupported loopback mode")),
174 }
175 self.select_pa(LmsPowerAmplifier::PaNone)?;
176 self.select_lna(LmsLowNoiseAmplifier::LnaNone)?;
177 self.loopback_path(&Loopback::None)?;
178 self.loopback_rx(&mode)?;
179 self.loopback_tx(&mode)?;
180 self.loopback_path(&mode)
181 }
182 pub fn get_loopback_mode(&self) -> crate::Result<Loopback> {
183 let mut loopback = Loopback::None;
184 let lben_lbrfen = self.read(0x08)?;
185 let loopbben = self.read(0x46)?;
186 match lben_lbrfen & 0x7 {
187 LBRFEN_LNA1 => {
188 loopback = Loopback::Lna1;
189 }
190 LBRFEN_LNA2 => {
191 loopback = Loopback::Lna2;
192 }
193 LBRFEN_LNA3 => {
194 loopback = Loopback::Lna3;
195 }
196 _ => {}
197 }
198 match lben_lbrfen & LBEN_MASK {
199 LBEN_VGA2IN => {
200 if (loopbben & LOOPBBEN_TXLPF) != 0 {
201 loopback = Loopback::BbTxlpfRxvga2;
202 } else if (loopbben & LOOPBBEN_TXVGA) != 0 {
203 loopback = Loopback::BbTxvga1Rxvga2;
204 }
205 }
206 LBEN_LPFIN => {
207 if (loopbben & LOOPBBEN_TXLPF) != 0 {
208 loopback = Loopback::BbTxlpfRxlpf;
209 } else if (loopbben & LOOPBBEN_TXVGA) != 0 {
210 loopback = Loopback::BbTxvga1Rxlpf;
211 }
212 }
213 _ => {}
214 }
215 Ok(loopback)
216 }
217 pub fn is_loopback_enabled(&self) -> crate::Result<bool> {
218 let loopback = self.get_loopback_mode()?;
219 Ok(loopback != Loopback::None)
220 }
221}