si4703/
seek.rs

1use crate::{
2    BitFlags, Error, ErrorWithPin, OperationState, Register, SeekDirection, SeekFmImpulseThreshold,
3    SeekMode, SeekSnrThreshold, Si4703,
4};
5use embedded_hal::{blocking::i2c, digital::v2::InputPin};
6
7impl<I2C, E, IC> Si4703<I2C, IC>
8where
9    I2C: i2c::Write<Error = E> + i2c::Read<Error = E>,
10{
11    fn get_powercfg_for_seek_config(
12        powercfg: u16,
13        mode: SeekMode,
14        direction: SeekDirection,
15    ) -> u16 {
16        let powercfg = match mode {
17            SeekMode::Wrap => powercfg | BitFlags::SKMODE,
18            SeekMode::NoWrap => powercfg & !BitFlags::SKMODE,
19        };
20        match direction {
21            SeekDirection::Up => powercfg | BitFlags::SEEKUP,
22            SeekDirection::Down => powercfg & !BitFlags::SEEKUP,
23        }
24    }
25
26    /// Configure seek RSSI, SNR and FM impulse detection thresholds
27    pub fn configure_seek(
28        &mut self,
29        rssi_threshold: u8,
30        snr_threshold: SeekSnrThreshold,
31        fm_impulse_threshold: SeekFmImpulseThreshold,
32    ) -> Result<(), Error<E>> {
33        let snr_mask = match snr_threshold {
34            SeekSnrThreshold::Disabled => 0,
35            SeekSnrThreshold::Enabled(v) if v > 7 || v == 0 => return Err(Error::InvalidInputData),
36            SeekSnrThreshold::Enabled(v) => v << 4,
37        };
38        let cnt_mask = match fm_impulse_threshold {
39            SeekFmImpulseThreshold::Disabled => 0,
40            SeekFmImpulseThreshold::Enabled(v) if v > 15 || v == 0 => {
41                return Err(Error::InvalidInputData)
42            }
43            SeekFmImpulseThreshold::Enabled(v) => v,
44        };
45        let mut regs = self.read_registers()?;
46        regs[Register::SYSCONFIG2] &= 0xFF00;
47        regs[Register::SYSCONFIG2] |= u16::from(rssi_threshold) << 8;
48        regs[Register::SYSCONFIG3] &= 0xFF00;
49        regs[Register::SYSCONFIG3] |= u16::from(snr_mask | cnt_mask);
50        self.write_registers(&regs[..=Register::SYSCONFIG3])
51    }
52
53    /// Seek
54    ///
55    /// It is not recommended to call this again this while the seeking
56    /// is not finished. It should be waited on the STC interrupt pin.
57    pub fn seek(&mut self, mode: SeekMode, direction: SeekDirection) -> nb::Result<(), Error<E>> {
58        let set_initial_value = |regs: &mut [u16; 16]| {
59            let powercfg = regs[Register::POWERCFG] | BitFlags::SEEK;
60            regs[Register::POWERCFG] =
61                Self::get_powercfg_for_seek_config(powercfg, mode, direction);
62            Ok(Register::POWERCFG)
63        };
64        let mut state = self.seeking_state;
65        let result = self.tune_seek(
66            Register::POWERCFG,
67            BitFlags::SEEK,
68            &mut state,
69            &set_initial_value,
70        );
71        self.seeking_state = state;
72        result
73    }
74
75    /// Seek using GPIO2 as STC interrupt pin (recommended)
76    ///
77    /// This will configure GPIO2 as STC interrupt pin and enable
78    /// STC interrupts if appropriate.
79    pub fn seek_with_stc_int_pin<PinE, P: InputPin<Error = PinE>>(
80        &mut self,
81        mode: SeekMode,
82        direction: SeekDirection,
83        stc_int_pin: &P,
84    ) -> nb::Result<(), ErrorWithPin<E, PinE>> {
85        if self.seeking_state == OperationState::Busy
86            && stc_int_pin
87                .is_high()
88                .map_err(ErrorWithPin::Pin)
89                .map_err(nb::Error::Other)?
90        {
91            Err(nb::Error::WouldBlock)
92        } else {
93            let set_initial_value = |regs: &mut [u16; 16]| {
94                let powercfg = regs[Register::POWERCFG] | BitFlags::SEEK;
95                regs[Register::POWERCFG] =
96                    Self::get_powercfg_for_seek_config(powercfg, mode, direction);
97                let previous_sysconfig1 = regs[Register::SYSCONFIG1];
98                regs[Register::SYSCONFIG1] &= 0xFFF3;
99                regs[Register::SYSCONFIG1] |= 1 << 2;
100                regs[Register::SYSCONFIG1] |= BitFlags::STCIEN;
101                if previous_sysconfig1 != regs[Register::SYSCONFIG1] {
102                    Ok(Register::SYSCONFIG1)
103                } else {
104                    Ok(Register::POWERCFG)
105                }
106            };
107            let mut state = self.seeking_state;
108            let result = self.tune_seek(
109                Register::POWERCFG,
110                BitFlags::SEEK,
111                &mut state,
112                &set_initial_value,
113            );
114            self.seeking_state = state;
115            result.map_err(|e| match e {
116                nb::Error::Other(e) => nb::Error::Other(e.into()),
117                nb::Error::WouldBlock => nb::Error::WouldBlock,
118            })
119        }
120    }
121
122    pub(crate) fn tune_seek(
123        &mut self,
124        register: usize,
125        bitflag: u16,
126        state: &mut OperationState,
127        set_start_value: &dyn Fn(&mut [u16; 16]) -> Result<usize, Error<E>>,
128    ) -> nb::Result<(), Error<E>> {
129        let mut regs = self.read_registers()?;
130        let flag = (regs[register] & bitflag) != 0;
131        let stc = (regs[Register::STATUSRSSI] & BitFlags::STC) != 0;
132        let failed = (regs[Register::STATUSRSSI] & BitFlags::SF_BL) != 0;
133        let afcrl = (regs[Register::STATUSRSSI] & BitFlags::AFCRL) != 0;
134
135        match (*state, flag, stc) {
136            (OperationState::Idle, false, false) => {
137                let register = set_start_value(&mut regs)?;
138                self.write_registers(&regs[..=register])?;
139                *state = OperationState::Busy;
140                Err(nb::Error::WouldBlock)
141            }
142            (OperationState::Busy, true, true) => {
143                regs[register] &= !bitflag;
144                self.write_registers(&regs[..=register])?;
145                *state = OperationState::WaitingForStcToClear(!failed && !afcrl);
146                Err(nb::Error::WouldBlock)
147            }
148            (OperationState::WaitingForStcToClear(success), false, false) => {
149                *state = OperationState::Idle;
150                if success {
151                    Ok(())
152                } else {
153                    Err(nb::Error::Other(Error::SeekFailed))
154                }
155            }
156            (_, _, _) => Err(nb::Error::WouldBlock),
157        }
158    }
159}