⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fmrxrds.c

📁 this is Si47xx Example Code
💻 C
📖 第 1 页 / 共 3 页
字号:
// 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 + -