Skip to main content

libbladerf_rs/bladerf1/hardware/lms6002d/
loopback.rs

1use 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}