1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
use crate::{
    ic, Band, BitFlags, ChannelSpacing, DeEmphasis, Error, Gpio1Config, Gpio2Config, Gpio3Config,
    OperationState, OutputMode, Register, Si4703, SoftmuteAttenuation, SoftmuteRate,
    StereoToMonoBlendLevel, Volume,
};
use core::marker::PhantomData;
use embedded_hal::blocking::i2c;

impl<I2C, E> Si4703<I2C, ic::Si4703>
where
    I2C: i2c::Write<Error = E> + i2c::Read<Error = E>,
{
    /// Create new instance of a Si4703 device
    pub fn new(i2c: I2C) -> Self {
        Si4703 {
            i2c,
            seeking_state: OperationState::Idle,
            tuning_state: OperationState::Idle,
            _ic: PhantomData,
        }
    }
}

impl<I2C, E> Si4703<I2C, ic::Si4702>
where
    I2C: i2c::Write<Error = E> + i2c::Read<Error = E>,
{
    /// Create new instance of a Si4702 device
    pub fn new_si4702(i2c: I2C) -> Self {
        Si4703 {
            i2c,
            seeking_state: OperationState::Idle,
            tuning_state: OperationState::Idle,
            _ic: PhantomData,
        }
    }
}

impl<I2C, IC> Si4703<I2C, IC> {
    /// Destroy driver instance, return I²C bus instance.
    pub fn destroy(self) -> I2C {
        self.i2c
    }
}

impl<I2C, E, IC> Si4703<I2C, IC>
where
    I2C: i2c::Write<Error = E> + i2c::Read<Error = E>,
{
    /// Enable the oscillator.
    ///
    /// This must be called before enabling the device.
    /// After calling this, a minimum of 500ms must be waited in order
    /// for the oscillator to power up.
    pub fn enable_oscillator(&mut self) -> Result<(), Error<E>> {
        let mut regs = self.read_registers()?;
        regs[Register::TEST1] |= BitFlags::XOSCEN;
        self.write_registers(&regs[0..=Register::TEST1])
    }

    /// Enable the device.
    ///
    /// After calling this it must be waited for the device to power up.
    /// See: Powerup time in the datasheet.
    /// On the Si4703, this is a maximum of 110ms.
    pub fn enable(&mut self) -> Result<(), Error<E>> {
        let powercfg = self.read_powercfg()?;
        self.write_powercfg((powercfg | BitFlags::ENABLE) & !BitFlags::DISABLE)
    }

    /// Disable the device (power down).
    pub fn disable(&mut self) -> Result<(), Error<E>> {
        let powercfg = self.read_powercfg()?;
        self.write_powercfg(powercfg | BitFlags::ENABLE | BitFlags::DISABLE)
    }

    /// Unmute (disable mute)
    pub fn unmute(&mut self) -> Result<(), Error<E>> {
        let powercfg = self.read_powercfg()?;
        self.write_powercfg(powercfg | BitFlags::DMUTE)
    }

    /// Mute (enable mute)
    pub fn mute(&mut self) -> Result<(), Error<E>> {
        let powercfg = self.read_powercfg()?;
        self.write_powercfg(powercfg & !BitFlags::DMUTE)
    }

    /// Enable softmute
    pub fn enable_softmute(
        &mut self,
        rate: SoftmuteRate,
        attenuation: SoftmuteAttenuation,
    ) -> Result<(), Error<E>> {
        let rate_mask = match rate {
            SoftmuteRate::Fastest => 0,
            SoftmuteRate::Fast => 1,
            SoftmuteRate::Slow => 2,
            SoftmuteRate::Slowest => 3,
        };
        let attenuation_mask = match attenuation {
            SoftmuteAttenuation::Db16 => 0,
            SoftmuteAttenuation::Db14 => 1,
            SoftmuteAttenuation::Db12 => 2,
            SoftmuteAttenuation::Db10 => 3,
        };

        let mut regs = self.read_registers()?;
        regs[Register::POWERCFG] &= !BitFlags::DSMUTE;
        regs[Register::SYSCONFIG3] &= 0x0FFF;
        regs[Register::SYSCONFIG3] |= (rate_mask << 14) | (attenuation_mask << 12);
        self.write_registers(&regs[0..=Register::SYSCONFIG3])
    }

    /// Disable softmute
    pub fn disable_softmute(&mut self) -> Result<(), Error<E>> {
        let powercfg = self.read_powercfg()?;
        self.write_powercfg(powercfg | BitFlags::DSMUTE)
    }

    /// Get output mode: Stereo/Mono
    pub fn output_mode(&mut self) -> Result<OutputMode, Error<E>> {
        let status = self.read_status()?;
        if (status & BitFlags::ST) != 0 {
            Ok(OutputMode::Stereo)
        } else {
            Ok(OutputMode::Mono)
        }
    }

    /// Set output mode: Stereo/Mono
    pub fn set_output_mode(&mut self, mode: OutputMode) -> Result<(), Error<E>> {
        let powercfg = self.read_powercfg()?;
        let powercfg = match mode {
            OutputMode::Stereo => powercfg & !BitFlags::MONO,
            OutputMode::Mono => powercfg | BitFlags::MONO,
        };
        self.write_powercfg(powercfg)
    }

    /// Set de-emphasis
    pub fn set_deemphasis(&mut self, de: DeEmphasis) -> Result<(), Error<E>> {
        let mut regs = self.read_registers()?;
        match de {
            DeEmphasis::Us75 => regs[Register::SYSCONFIG1] &= !BitFlags::DE,
            DeEmphasis::Us50 => regs[Register::SYSCONFIG1] |= BitFlags::DE,
        }
        self.write_registers(&regs[0..=Register::SYSCONFIG1])
    }

    /// Set the volume
    ///
    /// This will automatically activate or deactivate the extended volume
    /// range as appropriate.
    pub fn set_volume(&mut self, volume: Volume) -> Result<(), Error<E>> {
        let (volume_mask, volext) = match volume {
            Volume::Mute => (0_u16, false),
            Volume::Dbfsm58 => (1, true),
            Volume::Dbfsm56 => (2, true),
            Volume::Dbfsm54 => (3, true),
            Volume::Dbfsm52 => (4, true),
            Volume::Dbfsm50 => (5, true),
            Volume::Dbfsm48 => (6, true),
            Volume::Dbfsm46 => (7, true),
            Volume::Dbfsm44 => (8, true),
            Volume::Dbfsm42 => (9, true),
            Volume::Dbfsm40 => (10, true),
            Volume::Dbfsm38 => (11, true),
            Volume::Dbfsm36 => (12, true),
            Volume::Dbfsm34 => (13, true),
            Volume::Dbfsm32 => (14, true),
            Volume::Dbfsm30 => (15, true),
            Volume::Dbfsm28 => (1, false),
            Volume::Dbfsm26 => (2, false),
            Volume::Dbfsm24 => (3, false),
            Volume::Dbfsm22 => (4, false),
            Volume::Dbfsm20 => (5, false),
            Volume::Dbfsm18 => (6, false),
            Volume::Dbfsm16 => (7, false),
            Volume::Dbfsm14 => (8, false),
            Volume::Dbfsm12 => (9, false),
            Volume::Dbfsm10 => (10, false),
            Volume::Dbfsm8 => (11, false),
            Volume::Dbfsm6 => (12, false),
            Volume::Dbfsm4 => (13, false),
            Volume::Dbfsm2 => (14, false),
            Volume::Dbfs0 => (15, false),
        };
        let mut regs = self.read_registers()?;
        regs[Register::SYSCONFIG2] &= 0xFFF0;
        regs[Register::SYSCONFIG2] |= volume_mask;
        if volume_mask == 0 {
            self.write_registers(&regs[0..=Register::SYSCONFIG2])
        } else {
            if volext {
                regs[Register::SYSCONFIG3] |= BitFlags::VOLEXT
            } else {
                regs[Register::SYSCONFIG3] &= !BitFlags::VOLEXT
            }
            self.write_registers(&regs[0..=Register::SYSCONFIG3])
        }
    }

    /// Set band
    pub fn set_band(&mut self, band: Band) -> Result<(), Error<E>> {
        let mut regs = self.read_registers()?;
        let mask = match band {
            Band::Mhz875_108 => 0,
            Band::Mhz76_108 => 1,
            Band::Mhz76_90 => 2,
        };
        regs[Register::SYSCONFIG2] &= !(0b11 << 6);
        regs[Register::SYSCONFIG2] |= mask << 6;
        self.write_registers(&regs[..=Register::SYSCONFIG2])
    }

    /// Set channel spacing
    pub fn set_channel_spacing(&mut self, spacing: ChannelSpacing) -> Result<(), Error<E>> {
        let mut regs = self.read_registers()?;
        let mask = match spacing {
            ChannelSpacing::Khz200 => 0,
            ChannelSpacing::Khz100 => 1,
            ChannelSpacing::Khz50 => 2,
        };
        regs[Register::SYSCONFIG2] &= !(0b11 << 4);
        regs[Register::SYSCONFIG2] |= mask << 4;
        self.write_registers(&regs[..=Register::SYSCONFIG2])
    }

    /// Enable generating STC interrupts.
    ///
    /// For this to be useful, gpio2 pin must be configured to be
    /// used as STC/RDS interrupt.
    pub fn enable_stc_interrupts(&mut self) -> Result<(), Error<E>> {
        let mut regs = self.read_registers()?;
        regs[Register::SYSCONFIG1] |= BitFlags::STCIEN;
        self.write_registers(&regs[0..=Register::SYSCONFIG1])
    }

    /// Disable generating STC interrupts.
    pub fn disable_stc_interrupts(&mut self) -> Result<(), Error<E>> {
        let mut regs = self.read_registers()?;
        regs[Register::SYSCONFIG1] &= !BitFlags::STCIEN;
        self.write_registers(&regs[0..=Register::SYSCONFIG1])
    }

    /// Set the GPIO1
    pub fn set_gpio1(&mut self, config: Gpio1Config) -> Result<(), Error<E>> {
        let mut regs = self.read_registers()?;
        let mask = match config {
            Gpio1Config::HighImpedance => 0,
            Gpio1Config::Low => 2,
            Gpio1Config::High => 3,
        };
        regs[Register::SYSCONFIG1] &= 0xFFFC;
        regs[Register::SYSCONFIG1] |= mask;
        self.write_registers(&regs[0..=Register::SYSCONFIG1])
    }

    /// Set GPIO2 function / status
    pub fn set_gpio2(&mut self, config: Gpio2Config) -> Result<(), Error<E>> {
        let mut regs = self.read_registers()?;
        let mask = match config {
            Gpio2Config::HighImpedance => 0,
            Gpio2Config::StcRdsInterrupt => 1,
            Gpio2Config::Low => 2,
            Gpio2Config::High => 3,
        };
        regs[Register::SYSCONFIG1] &= 0xFFF3;
        regs[Register::SYSCONFIG1] |= mask << 2;
        self.write_registers(&regs[0..=Register::SYSCONFIG1])
    }

    /// Set the GPIO3
    pub fn set_gpio3(&mut self, config: Gpio3Config) -> Result<(), Error<E>> {
        let mut regs = self.read_registers()?;
        let mask = match config {
            Gpio3Config::HighImpedance => 0,
            Gpio3Config::MonoStereoIndicator => 1,
            Gpio3Config::Low => 2,
            Gpio3Config::High => 3,
        };
        regs[Register::SYSCONFIG1] &= 0xFFCF;
        regs[Register::SYSCONFIG1] |= mask << 4;
        self.write_registers(&regs[0..=Register::SYSCONFIG1])
    }

    /// Enable automatic gain control (default).
    pub fn enable_auto_gain_control(&mut self) -> Result<(), Error<E>> {
        let mut regs = self.read_registers()?;
        regs[Register::SYSCONFIG1] &= !BitFlags::AGCD;
        self.write_registers(&regs[0..=Register::SYSCONFIG1])
    }

    /// Disable automatic gain control.
    pub fn disable_auto_gain_control(&mut self) -> Result<(), Error<E>> {
        let mut regs = self.read_registers()?;
        regs[Register::SYSCONFIG1] |= BitFlags::AGCD;
        self.write_registers(&regs[0..=Register::SYSCONFIG1])
    }

    /// Set the stereo to mono blend level
    pub fn set_stereo_to_mono_blend_level(
        &mut self,
        level: StereoToMonoBlendLevel,
    ) -> Result<(), Error<E>> {
        let mut regs = self.read_registers()?;
        let mask = match level {
            StereoToMonoBlendLevel::Dbuv31_49 => 0,
            StereoToMonoBlendLevel::Dbuv37_55 => 1,
            StereoToMonoBlendLevel::Dbuv19_37 => 2,
            StereoToMonoBlendLevel::Dbuv25_43 => 3,
        };
        regs[Register::SYSCONFIG1] &= 0xFF3F;
        regs[Register::SYSCONFIG1] |= mask << 6;
        self.write_registers(&regs[0..=Register::SYSCONFIG1])
    }

    /// Enable the audio High-Z.
    ///
    /// This must be called before enabling the device.
    pub fn enable_audio_high_z(&mut self) -> Result<(), Error<E>> {
        let mut regs = self.read_registers()?;
        regs[Register::TEST1] |= BitFlags::AHIZEN;
        self.write_registers(&regs[0..=Register::TEST1])
    }

    /// Disable the audio High-Z.
    ///
    /// This must be called before enabling the device.
    pub fn disable_audio_high_z(&mut self) -> Result<(), Error<E>> {
        let mut regs = self.read_registers()?;
        regs[Register::TEST1] &= !BitFlags::AHIZEN;
        self.write_registers(&regs[0..=Register::TEST1])
    }

    /// Read the channel
    pub fn channel(&mut self) -> Result<f32, Error<E>> {
        let regs = self.read_registers()?;
        let spacing = (regs[Register::SYSCONFIG2] & (0b11 << 4)) >> 4;
        let spacing = match spacing {
            0 => 0.2,
            1 => 0.1,
            _ => 0.05,
        };
        let base = regs[Register::SYSCONFIG2] & (0b11 << 6);
        let base = if base == 0 { 87.5 } else { 76.0 };
        let channel = f32::from(regs[Register::READCHAN] & 0x3FF);
        Ok(channel * spacing + base)
    }

    /// Get the device ID
    ///
    /// Returns the (part number, manufacturer ID) as a tuple
    pub fn device_id(&mut self) -> Result<(u8, u16), Error<E>> {
        let regs = self.read_registers()?;
        let device_id = regs[Register::DEVICE_ID];
        let pn = ((device_id & 0xF000) >> 12) as u8;
        let mfid = device_id & 0xFFF;
        Ok((pn, mfid))
    }

    /// Get the chip ID
    ///
    /// Returns the (revision, device, firmware) as a tuple
    pub fn chip_id(&mut self) -> Result<(u8, u8, u8), Error<E>> {
        let regs = self.read_registers()?;
        let chip_id = regs[Register::CHIP_ID];
        let rev = ((chip_id & 0xFC00) >> 10) as u8;
        let dev = ((chip_id & 0x3C0) >> 6) as u8;
        let firmware = (chip_id & 0x3F) as u8;
        Ok((rev, dev, firmware))
    }
}