Fix FM RDS: station name/RadioText never decoded, three stacked bugs
GET /api/tuner/status and the full FM band scan always returned an
empty station_name, on every frequency, regardless of signal quality
-- confirmed live on multiple >35 dB SNR channels before this fix.
Three independent problems, found by reading the Si4684 datasheet
(AN649 Rev.2.0) instead of guessing further:
1. FM_RDS_CONFIG (property 0x3C02) was enabled (RDSEN=1) but with both
block-error thresholds at 0 ("no block errors"), so almost any
real-world RDS group -- routine with ordinary multipath/noise, even
on a strong signal -- got rejected from the FIFO outright. Raised
to the datasheet's most tolerant recommended setting (2, "3-5 bit
errors detected and corrected").
2. FM_RDS_INTERRUPT_FIFO_COUNT (property 0x3C01) was never set at all,
defaulting to 0 -- which the datasheet states disables RDSFIFOINT
permanently. Si4684Driver::readFmRds()'s "received" flag reads
exactly that bit (FM_RDS_STATUS RESP4 bit 0), so it could never be
true, and Si4684Tuner::refreshStatus()'s RDS poll loop broke out on
its first iteration every single time, before ever touching the
accumulator. Set to 1 (fire as soon as one group is queued).
3. The real bug, once groups actually started arriving:
RdsMetadataAccumulator::applyGroup() read the two Program Service
name characters from Block C and computed the segment index as
(blockB >> 1) & 0x3. Per ETSI EN 62106 §3.1.5, PS characters for
group type 0 (both 0A and 0B) are always in Block D -- Block C
holds alternate-frequency codes (0A) or a repeated PI code (0B),
never text -- and the segment address is blockB bits[1:0] with no
shift. This function had no dedicated test before now, which is
how a wrong block/bit pair could ship unnoticed: the old test
fixture encoded the same bug in its "expected" input.
Confirmed live after all three fixes: station_name and radiotext both
populate with stable, plausible content across repeated reads (not
noise) on a real broadcast signal.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -66,6 +66,11 @@ constexpr std::uint16_t kSi4684I2sOutEnable = 0x8002U;
|
||||
/** Si4684 volume: 0=mute, 63=max (AN649 AUDIO_ANALOG_VOLUME). */
|
||||
constexpr std::uint8_t kSi4684VolumeMax = 63U;
|
||||
constexpr std::uint16_t kPropFmRdsConfig = 0x3C02U;
|
||||
/** AN649 §0x3C01 FM_RDS_INTERRUPT_FIFO_COUNT: DEPTH[7:0], groups needed
|
||||
* before RDSFIFOINT (FM_RDS_STATUS RESP4 bit0, our readFmRds() "received"
|
||||
* bit) ever sets. Default 0 disables it permanently regardless of
|
||||
* FM_RDS_CONFIG -- must be nonzero for any RDS group to ever be seen. */
|
||||
constexpr std::uint16_t kPropFmRdsInterruptFifoCount = 0x3C01U;
|
||||
/** AN649 FM_AUDIO_DE_EMPHASIS (0x3900): 0=75us/US (chip default), 1=50us/
|
||||
* Europe, 2=disabled. FM seek band/spacing above is already the European
|
||||
* 87.5-107.9 MHz/100 kHz plan, so the chip must not stay on its 75us/US
|
||||
@@ -557,9 +562,22 @@ std::expected<void, Si4684Error> Si4684Driver::configureAfterBoot(
|
||||
return set;
|
||||
}
|
||||
}
|
||||
if (auto rds = setProperty(kPropFmRdsConfig, 0x0001U); !rds) {
|
||||
// AN649 §0x3C02 FM_RDS_CONFIG: BLETHB[7:6]/BLETHCD[5:4] block-error
|
||||
// thresholds, RDSEN[0]. 0x0001 (thresholds at 0, "no block errors")
|
||||
// rejected almost every real-world group -- any bit error at all
|
||||
// (routine with multipath/noise, even on a strong signal) dropped
|
||||
// the group from the FIFO, so accumulated station names/RadioText
|
||||
// never completed. 0x00A1 keeps both thresholds at the datasheet's
|
||||
// most tolerant recommended setting (2 = "3-5 bit errors detected
|
||||
// and corrected"), still discarding uncorrectable (3) groups.
|
||||
if (auto rds = setProperty(kPropFmRdsConfig, 0x00A1U); !rds) {
|
||||
return rds;
|
||||
}
|
||||
if (auto rdsFifo =
|
||||
setProperty(kPropFmRdsInterruptFifoCount, 0x0001U);
|
||||
!rdsFifo) {
|
||||
return rdsFifo;
|
||||
}
|
||||
if (auto deEmph = setProperty(kPropFmAudioDeEmphasis,
|
||||
kFmAudioDeEmphasisEurope);
|
||||
!deEmph) {
|
||||
|
||||
Reference in New Issue
Block a user