📄 fmrxrds.c
字号:
// Decode the RDS AF data into an array of AF frequencies.
//-----------------------------------------------------------------------------
#define AF_COUNT_MIN 225
#define AF_COUNT_MAX (AF_COUNT_MIN + 25)
#define AF_FREQ_MIN 0
#define AF_FREQ_MAX 204
#define AF_FREQ_TO_U16F(freq) (8750+((freq-AF_FREQ_MIN)*10))
static void
update_alt_freq(u16 current_alt_freq)
{
// Currently this only works well for AF method A, though AF method B
// data will still be captured.
u8 dat;
u8 i;
u16 freq;
// the top 8 bits is either the AF Count or AF Data
dat = (u8)(current_alt_freq >> 8);
// look for the AF Count indicator
if ((dat >= AF_COUNT_MIN) && (dat <= AF_COUNT_MAX) && ((dat - AF_COUNT_MIN) != afCount))
{
init_alt_freq(); // clear the alternalte frequency list
afCount = (dat - AF_COUNT_MIN); // set the count
dat = (u8)current_alt_freq;
if (dat >= AF_FREQ_MIN && dat <= AF_FREQ_MAX)
{
freq = AF_FREQ_TO_U16F(dat);
afList[0]= freq;
}
}
// look for the AF Data
else if (afCount && dat >= AF_FREQ_MIN && dat <= AF_FREQ_MAX)
{
bit foundSlot = 0;
static xdata u8 clobber=1; // index to clobber if no empty slot is found
freq = AF_FREQ_TO_U16F(dat);
for (i=1; i < afCount; i+=2)
{
// look for either an empty slot or a match
if ((!afList[i]) || (afList[i] = freq))
{
afList[i] = freq;
dat = (u8)current_alt_freq;
freq = AF_FREQ_TO_U16F(dat);
afList[i+1] = freq;
foundSlot = 1;
break;
}
}
// If no empty slot or match was found, overwrite a 'random' slot.
if (!foundSlot)
{
clobber += (clobber&1) + 1; // this ensures that an odd slot is always chosen.
clobber %= (afCount); // keep from overshooting the array
afList[clobber] = freq;
dat = (u8)current_alt_freq;
freq = AF_FREQ_TO_U16F(dat);
afList[clobber+1] = freq;
}
}
}
//-----------------------------------------------------------------------------
// Decode the RDS time data into its individual parts.
//-----------------------------------------------------------------------------
static void
update_clock(u16 b, u16 c, u16 d)
{
if (BleB <= rdsBlerMax[1] &&
BleC <= rdsBlerMax[2] &&
BleD <= rdsBlerMax[3] &&
(BleB + BleC + BleD) <= rdsBlerMax[1]) {
ctDayHigh = (b >> 1) & 1;
ctDayLow = (b << 15) | (c >> 1);
ctHour = ((c&1) << 4) | (d >> 12);
ctMinute = (d>>6) & 0x3F;
ctOffset = d & 0x1F;
if (d & (1<<5))
{
ctOffset = -ctOffset;
}
}
}
//-----------------------------------------------------------------------------
// After an RDS interrupt, read back the RDS registers and process the data.
//-----------------------------------------------------------------------------
void
updateRds(void)
{
u8 idata rtblocks[4];
u8 group_type; // bits 4:1 = type, bit 0 = version
u8 addr;
u8 errorCount;
bit abflag;
RdsDataAvailable = 0;
// Get the RDS status from the part.
fmRdsStatus(1, 0);
// Loop until all the RDS information has been read from the part.
while(RdsFifoUsed)
{
u8 bler[4];
u8 field ;
if(GrpLost)
{
RdsDataLost++;
}
// Gather the latest BLER info
bler[0] = BleA;
bler[1] = BleB;
bler[2] = BleC;
bler[3] = BleD;
errorCount = 0;
RdsGroups++;
for (field = 0; field <= 3; field++)
{
if (bler[field] == UNCORRECTABLE)
{
errorCount++;
}
else
{
RdsValid[field]++;
}
}
if (errorCount < 4)
{
RdsBlocksValid += (4 - errorCount);
}
if (RdsIndicator)
{
LED = !LED;
}
RdsIndicator = 100; // Reset RdsIndicator
// Update pi code.
if (BleA < rdsBlerMax[0])
{
update_pi(BlockA);
}
if (BleB <= rdsBlerMax[1])
{
group_type = BlockB >> 11; // upper five bits are the group type and version
// Check for group counter overflow and divide all by 2
if((RdsGroupCounters[group_type] + 1) == 0)
{
u8 i;
for (i=0;i<32;i++)
{
RdsGroupCounters[i] >>= 1;
}
}
RdsGroupCounters[group_type] += 1;
}
else
{
// Drop the data if more than two errors were corrected in block B
return;
}
// Update pi code. Version B formats always have the pi code in words A and C
if (group_type & 0x01)
{
update_pi(BlockC);
}
// update pty code.
update_pty((BlockB >> 5) & 0x1f);
switch (group_type) {
case RDS_TYPE_0A:
if (BleC <= rdsBlerMax[2])
{
update_alt_freq(BlockC);
}
// fallthrough
case RDS_TYPE_0B:
addr = (BlockB & 0x3) * 2;
if (BleD <= rdsBlerMax[3])
{
if(rdsBasic)
{
update_ps_basic(addr+0, BlockD >> 8 );
update_ps_basic(addr+1, BlockD & 0xff);
}
else
{
update_ps(addr+0, BlockD >> 8 );
update_ps(addr+1, BlockD & 0xff);
}
}
break;
case RDS_TYPE_2A:
{
rtblocks[0] = (u8)(BlockC >> 8);
rtblocks[1] = (u8)(BlockC & 0xFF);
rtblocks[2] = (u8)(BlockD >> 8);
rtblocks[3] = (u8)(BlockD & 0xFF);
addr = (BlockB & 0xf) * 4;
abflag = (BlockB & 0x0010) >> 4;
update_rt_simple(abflag, 4, addr, rtblocks);
update_rt_advance(abflag, 4, addr, rtblocks);
break;
}
case RDS_TYPE_2B:
{
rtblocks[0] = (u8)(BlockD >> 8);
rtblocks[1] = (u8)(BlockD & 0xFF);
rtblocks[2] = 0;
rtblocks[3] = 0;
addr = (BlockB & 0xf) * 2;
abflag = (BlockB & 0x0010) >> 4;
// The last 32 bytes are unused in this format
rtSimple[32] = 0x0d;
rtTmp0[32] = 0x0d;
rtTmp1[32] = 0x0d;
rtCnt[32] = RT_VALIDATE_LIMIT;
update_rt_simple (abflag, 2, addr, rtblocks);
update_rt_advance(abflag, 2, addr, rtblocks);
break;
}
case RDS_TYPE_4A:
// Clock Time and Date
update_clock(BlockB, BlockC, BlockD);
break;
default:
break;
}
// Get the RDS status from the part.
fmRdsStatus(1, 0);
}
}
//-----------------------------------------------------------------------------
// Compute the block error rate.
// Returns a value between 0 and BLER_SCALE_MAX (200) which can be used
// to determine the % errors in 0.5% resolution.
//-----------------------------------------------------------------------------
void
si47_rdsGetBler(u16 *bler)
{
if (RdsBlocksTotal < RdsBlocksValid)
{
// The timer which generates the total block count is not synchronized
// to the RDS signal, so occasionally it looks like we received more
// valid blocks than we should have. In this case, just assume no
// errors.
*bler = 0;
}
else if (!RdsBlocksTotal)
{
// If the timer has not fired, we will assume 100% errors
*bler = BLER_SCALE_MAX;
}
else
{
// Calculate the block error rate
*bler = BLER_SCALE_MAX - ((RdsBlocksValid * BLER_SCALE_MAX) / RdsBlocksTotal);
}
}
//-----------------------------------------------------------------------------
// Interrupt service routine to estimate the number of RDS blocks that should
// have been received in a given amount of time. This routine fires
// approximately every 21.7ms
//-----------------------------------------------------------------------------
void RDS_TIMER_ISR(void) interrupt 5
{
static u8 ledTimer = 0;
// If RDS hasn't been detected recently, cause the LED to blink at a slow
// rate to indicate the board is alive.
if (!RdsIndicator)
{
ledTimer++;
LED = !!((ledTimer>>2) % 16); // Normally on
}
RdsBlocksTotal++;
// The Si47xx triggers 1 RDS interrupt for 4 RDS blocks. This conditional
// helps to track the theoretical expected number of groups.
if (!(RdsBlocksTotal%4))
{
RdsGroupsTotal++;
RdsSynchTotal++;
}
// To avoid the counters rolling over, adjust them occasionally
if (RdsBlocksTotal > (0xFFFF / BLER_SCALE_MAX))
{
// Drop about 6% blocks from totals
RdsBlocksTotal = (RdsBlocksTotal * 15) / 16;
RdsBlocksValid = (RdsBlocksValid * 15) / 16;
}
if (RdsIndicator)
{
// Make the RdsIndicator decay if no valid data has been seen for a
// while. This get reset to 100 every time RDS is retrieved successfully.
RdsIndicator--;
}
else
{
// If it drops all the way to zero, reset the counters to indicate
// RDS is gone entirely.
RdsBlocksValid = 0;
RdsBlocksTotal = 1;
}
TF2H = 0; // Clear overflow flag
TF2L = 0; // Clear overflow flag
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -