mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-14 02:27:39 -04:00
FS#12370: Initial RDS support for Si4701/Si4703 tuner (beast and clip zip)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31346 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
17ed3253fc
commit
8c19dcd598
13 changed files with 525 additions and 37 deletions
|
@ -1735,6 +1735,15 @@ static int radio_callback(int btn, struct gui_synclist *lists)
|
|||
simplelist_addline(SIMPLELIST_ADD_LINE,"%02X: %04X %04X %04X %04X",
|
||||
i, nfo.regs[i], nfo.regs[i+1], nfo.regs[i+2], nfo.regs[i+3]);
|
||||
}
|
||||
#ifdef HAVE_RDS_CAP
|
||||
simplelist_addline(SIMPLELIST_ADD_LINE, "");
|
||||
simplelist_addline(SIMPLELIST_ADD_LINE, "RDS Info:");
|
||||
simplelist_addline(SIMPLELIST_ADD_LINE,
|
||||
si4700_get_rds_info(RADIO_RDS_NAME));
|
||||
|
||||
simplelist_addline(SIMPLELIST_ADD_LINE,
|
||||
si4700_get_rds_info(RADIO_RDS_TEXT));
|
||||
#endif
|
||||
}
|
||||
#endif /* SI4700 */
|
||||
#if (CONFIG_TUNER & RDA5802)
|
||||
|
|
|
@ -302,6 +302,9 @@ drivers/tuner/ipod_remote_tuner.c
|
|||
#if (CONFIG_TUNER & RDA5802)
|
||||
drivers/tuner/rda5802.c
|
||||
#endif /* (CONFIG_TUNER & RDA5802) */
|
||||
#if defined(HAVE_RDS_CAP)
|
||||
drivers/rds.c
|
||||
#endif /* HAVE_RDS_CAP */
|
||||
#endif /* PLATFORM_NATIVE */
|
||||
#endif /* CONFIG_TUNER */
|
||||
#endif /* BOOTLOADER */
|
||||
|
|
192
firmware/drivers/rds.c
Normal file
192
firmware/drivers/rds.c
Normal file
|
@ -0,0 +1,192 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2011 by Bertrik Sikken
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <strlcpy.h>
|
||||
#include "rds.h"
|
||||
|
||||
/* programme identification */
|
||||
static uint16_t pi;
|
||||
/* program service name */
|
||||
static char ps_data[9];
|
||||
static char ps_copy[9];
|
||||
static int ps_segment;
|
||||
/* radio text */
|
||||
static char rt_data[65];
|
||||
static char rt_copy[65];
|
||||
static int rt_segment;
|
||||
static int rt_abflag;
|
||||
|
||||
/* resets the rds parser */
|
||||
void rds_reset(void)
|
||||
{
|
||||
ps_copy[0] = '\0';
|
||||
ps_segment = 0;
|
||||
rt_copy[0] = '\0';
|
||||
rt_segment = 0;
|
||||
pi = 0;
|
||||
}
|
||||
|
||||
/* initialises the rds parser */
|
||||
void rds_init(void)
|
||||
{
|
||||
rds_reset();
|
||||
}
|
||||
|
||||
/* handles a group 0 packet, returns true if a new message was received */
|
||||
static bool handle_group0(uint16_t data[4])
|
||||
{
|
||||
int segment, pos;
|
||||
|
||||
segment = data[1] & 3;
|
||||
|
||||
/* reset parsing if not in expected order */
|
||||
if (segment != ps_segment) {
|
||||
ps_segment = 0;
|
||||
if (segment != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* store data */
|
||||
pos = segment * 2;
|
||||
ps_data[pos++] = (data[3] >> 8) & 0xFF;
|
||||
ps_data[pos++] = (data[3] >> 0) & 0xFF;
|
||||
if (++ps_segment == 4) {
|
||||
ps_data[pos] = '\0';
|
||||
if (strcmp(ps_copy, ps_data) != 0) {
|
||||
/* we got an updated message */
|
||||
strcpy(ps_copy, ps_data);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* handles a radio text characters, returns true if end-of-line found */
|
||||
static bool handle_rt(int pos, char c)
|
||||
{
|
||||
switch (c) {
|
||||
case 0x0A:
|
||||
/* line break hint */
|
||||
rt_data[pos] = ' ';
|
||||
return false;
|
||||
case 0x0D:
|
||||
/* end of line */
|
||||
rt_data[pos] = '\0';
|
||||
return true;
|
||||
default:
|
||||
rt_data[pos] = c;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* handles a group 2 packet, returns true if a new message was received */
|
||||
static bool handle_group2(uint16_t data[4])
|
||||
{
|
||||
int abflag, segment, version, pos;
|
||||
bool done;
|
||||
|
||||
/* reset parsing if not in expected order */
|
||||
abflag = (data[1] >> 4) & 1;
|
||||
segment = data[1] & 0xF;
|
||||
if ((abflag != rt_abflag) || (segment != rt_segment)) {
|
||||
rt_abflag = abflag;
|
||||
rt_segment = 0;
|
||||
if (segment != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* store data */
|
||||
version = (data[1] >> 11) & 1;
|
||||
done = false;
|
||||
if (version == 0) {
|
||||
pos = segment * 4;
|
||||
done = done || handle_rt(pos++, (data[2] >> 8) & 0xFF);
|
||||
done = done || handle_rt(pos++, (data[2] >> 0) & 0xFF);
|
||||
done = done || handle_rt(pos++, (data[3] >> 8) & 0xFF);
|
||||
done = done || handle_rt(pos++, (data[3] >> 0) & 0xFF);
|
||||
} else {
|
||||
pos = segment * 2;
|
||||
done = done || handle_rt(pos++, (data[3] >> 8) & 0xFF);
|
||||
done = done || handle_rt(pos++, (data[3] >> 0) & 0xFF);
|
||||
}
|
||||
if ((++rt_segment == 16) || done) {
|
||||
rt_data[pos] = '\0';
|
||||
if (strcmp(rt_copy, rt_data) != 0) {
|
||||
/* we got an updated message */
|
||||
strcpy(rt_copy, rt_data);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* processes one rds packet, returns true if a new message was received */
|
||||
bool rds_process(uint16_t data[4])
|
||||
{
|
||||
int group;
|
||||
|
||||
/* get programme identification */
|
||||
if (pi == 0) {
|
||||
pi = data[0];
|
||||
}
|
||||
|
||||
/* handle rds data based on group */
|
||||
group = (data[1] >> 11) & 0x1F;
|
||||
switch (group) {
|
||||
|
||||
case 0: /* group 0A: basic info */
|
||||
case 1: /* group 0B: basic info */
|
||||
return handle_group0(data);
|
||||
|
||||
case 4: /* group 2A: radio text */
|
||||
case 5: /* group 2B: radio text */
|
||||
return handle_group2(data);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* returns the programme identification code */
|
||||
uint16_t rds_get_pi(void)
|
||||
{
|
||||
return pi;
|
||||
}
|
||||
|
||||
/* returns the most recent valid programme service name */
|
||||
char* rds_get_ps(void)
|
||||
{
|
||||
return ps_copy;
|
||||
}
|
||||
|
||||
/* returns the most recent valid RadioText message */
|
||||
char* rds_get_rt(void)
|
||||
{
|
||||
return rt_copy;
|
||||
}
|
||||
|
|
@ -29,21 +29,15 @@
|
|||
#include "tuner.h" /* tuner abstraction interface */
|
||||
#include "fmradio.h"
|
||||
#include "fmradio_i2c.h" /* physical interface driver */
|
||||
#include "rds.h"
|
||||
|
||||
/* some models use the internal 32 kHz oscillator which needs special attention
|
||||
during initialisation, power-up and power-down.
|
||||
*/
|
||||
#if defined(SANSA_CLIP) || defined(SANSA_E200V2) || defined(SANSA_FUZE) || defined(SANSA_C200V2)
|
||||
#define USE_INTERNAL_OSCILLATOR
|
||||
/* some models use the internal 32 kHz oscillator which needs special attention
|
||||
during initialisation, power-up and power-down. */
|
||||
#define SI4700_USE_INTERNAL_OSCILLATOR
|
||||
#elif defined(TOSHIBA_GIGABEAT_S)
|
||||
#define SI4700_GPIO_SETUP (SYSCONFIG1_GPIO1_HI_Z | \
|
||||
SYSCONFIG1_GPIO2_HI_Z | \
|
||||
SYSCONFIG1_GPIO3_MO_ST_I)
|
||||
extern int si4700_st(void);
|
||||
#endif
|
||||
|
||||
#ifndef SI4700_GPIO_SETUP
|
||||
#define SI4700_GPIO_SETUP 0
|
||||
/* gigabeat S uses the GPIO for stereo/mono detection */
|
||||
#define SI4700_USE_MO_ST_I
|
||||
#endif
|
||||
|
||||
#define SEEK_THRESHOLD 0x16
|
||||
|
@ -81,7 +75,8 @@ extern int si4700_st(void);
|
|||
|
||||
/* CHIPID (0x1) */
|
||||
|
||||
#if 0 /* Informational */
|
||||
#if 0
|
||||
/* Informational */
|
||||
/* Si4700/01 */
|
||||
#define CHIPID_REV (0x3f << 10)
|
||||
#define CHIPID_DEV (0x1 << 9)
|
||||
|
@ -98,7 +93,10 @@ extern int si4700_st(void);
|
|||
/* 1000 before PU = Si4703 */
|
||||
/* 1001 after PU = Si4703 */
|
||||
#define CHIPID_FIRMWARE (0x3f << 0)
|
||||
#endif /* 0 */
|
||||
#endif
|
||||
|
||||
/* Indicates Si4701/2/3 after powerup */
|
||||
#define CHIPID_DEV_0 (0x1 << 9)
|
||||
|
||||
/* POWERCFG (0x2) */
|
||||
#define POWERCFG_DSMUTE (0x1 << 15)
|
||||
|
@ -214,6 +212,10 @@ extern int si4700_st(void);
|
|||
|
||||
static bool tuner_present = false;
|
||||
static uint16_t cache[16];
|
||||
static struct mutex fmr_mutex SHAREDBSS_ATTR;
|
||||
#ifdef HAVE_RDS_CAP
|
||||
static int rds_event = 0;
|
||||
#endif
|
||||
|
||||
/* reads <len> registers from radio at offset 0x0A into cache */
|
||||
static void si4700_read(int len)
|
||||
|
@ -277,19 +279,26 @@ static void si4700_write_clear(int reg, uint16_t mask)
|
|||
si4700_write_reg(reg, cache[reg] & ~mask);
|
||||
}
|
||||
|
||||
#if (SI4700_GPIO_SETUP & SYSCONFIG1_GPIO3) != SYSCONFIG1_GPIO3_MO_ST_I
|
||||
#ifndef SI4700_USE_MO_ST_I
|
||||
/* Poll i2c for the stereo status */
|
||||
static inline int si4700_st(void)
|
||||
bool si4700_st(void)
|
||||
{
|
||||
return (si4700_read_reg(STATUSRSSI) & STATUSRSSI_ST) >> 8;
|
||||
}
|
||||
#endif
|
||||
#endif /* ndef SI4700_USE_MO_ST_I */
|
||||
|
||||
static void si4700_sleep(int snooze)
|
||||
{
|
||||
if (snooze)
|
||||
{
|
||||
/** power down **/
|
||||
#ifdef HAVE_RDS_CAP
|
||||
if (cache[CHIPID] & CHIPID_DEV_0) {
|
||||
si4700_rds_powerup(false);
|
||||
si4700_write_clear(SYSCONFIG1, SYSCONFIG1_RDS | SYSCONFIG1_RDSIEN);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ENABLE high, DISABLE high */
|
||||
si4700_write_set(POWERCFG,
|
||||
POWERCFG_DISABLE | POWERCFG_ENABLE);
|
||||
|
@ -307,9 +316,8 @@ static void si4700_sleep(int snooze)
|
|||
/* init register cache */
|
||||
si4700_read(16);
|
||||
|
||||
#if SI4700_GPIO_SETUP != 0
|
||||
si4700_write_masked(SYSCONFIG1, SI4700_GPIO_SETUP,
|
||||
SYSCONFIG1_GPIO1 | SYSCONFIG1_GPIO2 |
|
||||
#ifdef SI4700_USE_MO_ST_I
|
||||
si4700_write_masked(SYSCONFIG1, SYSCONFIG1_GPIO3_MO_ST_I,
|
||||
SYSCONFIG1_GPIO3);
|
||||
#endif
|
||||
/* set mono->stereo switching RSSI range to lowest setting */
|
||||
|
@ -320,25 +328,35 @@ static void si4700_sleep(int snooze)
|
|||
SYSCONFIG2_SKEETHw(SEEK_THRESHOLD) |
|
||||
SYSCONFIG2_VOLUMEw(0xF),
|
||||
SYSCONFIG2_VOLUME | SYSCONFIG2_SEEKTH);
|
||||
|
||||
#ifdef HAVE_RDS_CAP
|
||||
/* enable RDS and RDS interrupt if supported (bit 9 of CHIPID) */
|
||||
if (cache[CHIPID] & CHIPID_DEV_0) {
|
||||
/* Is Si4701/2/3 - Enable RDS and interrupt */
|
||||
si4700_write_set(SYSCONFIG1, SYSCONFIG1_RDS | SYSCONFIG1_RDSIEN);
|
||||
si4700_write_masked(SYSCONFIG1, SYSCONFIG1_GPIO2_STC_RDS_I,
|
||||
SYSCONFIG1_GPIO2);
|
||||
si4700_rds_powerup(true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool si4700_detect(void)
|
||||
{
|
||||
bool detected;
|
||||
|
||||
tuner_power(true);
|
||||
detected = (si4700_read_reg(DEVICEID) == 0x1242);
|
||||
tuner_power(false);
|
||||
|
||||
return detected;
|
||||
if (!tuner_present) {
|
||||
tuner_power(true);
|
||||
tuner_present = (si4700_read_reg(DEVICEID) == 0x1242);
|
||||
tuner_power(false);
|
||||
}
|
||||
return tuner_present;
|
||||
}
|
||||
|
||||
void si4700_init(void)
|
||||
{
|
||||
/* check device id */
|
||||
if (si4700_detect()) {
|
||||
tuner_present = true;
|
||||
mutex_init(&fmr_mutex);
|
||||
|
||||
tuner_power(true);
|
||||
|
||||
|
@ -346,7 +364,7 @@ void si4700_init(void)
|
|||
si4700_read(16);
|
||||
si4700_sleep(0);
|
||||
|
||||
#ifdef USE_INTERNAL_OSCILLATOR
|
||||
#ifdef SI4700_USE_INTERNAL_OSCILLATOR
|
||||
/* Enable the internal oscillator
|
||||
(Si4702-16 needs this register to be initialised to 0x100) */
|
||||
si4700_write_set(TEST1, TEST1_XOSCEN | 0x100);
|
||||
|
@ -355,6 +373,10 @@ void si4700_init(void)
|
|||
|
||||
si4700_sleep(1);
|
||||
tuner_power(false);
|
||||
|
||||
#ifdef HAVE_RDS_CAP
|
||||
si4700_rds_init();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -421,6 +443,10 @@ static void si4700_set_region(int region)
|
|||
/* tuner abstraction layer: set something to the tuner */
|
||||
int si4700_set(int setting, int value)
|
||||
{
|
||||
int val = 1;
|
||||
|
||||
mutex_lock(&fmr_mutex);
|
||||
|
||||
switch(setting)
|
||||
{
|
||||
case RADIO_SLEEP:
|
||||
|
@ -430,12 +456,19 @@ int si4700_set(int setting, int value)
|
|||
break;
|
||||
|
||||
case RADIO_FREQUENCY:
|
||||
#ifdef HAVE_RDS_CAP
|
||||
rds_reset();
|
||||
#endif
|
||||
si4700_set_frequency(value);
|
||||
break;
|
||||
|
||||
case RADIO_SCAN_FREQUENCY:
|
||||
#ifdef HAVE_RDS_CAP
|
||||
rds_reset();
|
||||
#endif
|
||||
si4700_set_frequency(value);
|
||||
return si4700_tuned();
|
||||
val = si4700_tuned();
|
||||
break;
|
||||
|
||||
case RADIO_MUTE:
|
||||
si4700_write_masked(POWERCFG, value ? 0 : POWERCFG_DMUTE,
|
||||
|
@ -452,10 +485,13 @@ int si4700_set(int setting, int value)
|
|||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
val = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
mutex_unlock(&fmr_mutex);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* tuner abstraction layer: read something from the tuner */
|
||||
|
@ -463,6 +499,8 @@ int si4700_get(int setting)
|
|||
{
|
||||
int val = -1; /* default for unsupported query */
|
||||
|
||||
mutex_lock(&fmr_mutex);
|
||||
|
||||
switch(setting)
|
||||
{
|
||||
case RADIO_PRESENT:
|
||||
|
@ -488,8 +526,17 @@ int si4700_get(int setting)
|
|||
case RADIO_RSSI_MAX:
|
||||
val = RSSI_MAX;
|
||||
break;
|
||||
|
||||
#ifdef HAVE_RDS_CAP
|
||||
case RADIO_EVENT:
|
||||
val = rds_event;
|
||||
rds_event = 0;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
mutex_unlock(&fmr_mutex);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
@ -497,10 +544,61 @@ void si4700_dbg_info(struct si4700_dbg_info *nfo)
|
|||
{
|
||||
memset(nfo->regs, 0, sizeof (nfo->regs));
|
||||
|
||||
mutex_lock(&fmr_mutex);
|
||||
|
||||
if (tuner_powered())
|
||||
{
|
||||
si4700_read(16);
|
||||
memcpy(nfo->regs, cache, sizeof (nfo->regs));
|
||||
}
|
||||
|
||||
mutex_unlock(&fmr_mutex);
|
||||
}
|
||||
|
||||
#ifdef HAVE_RDS_CAP
|
||||
/* Read raw RDS info for processing */
|
||||
bool si4700_rds_read_raw(uint16_t data[4])
|
||||
{
|
||||
bool retval = false;
|
||||
|
||||
mutex_lock(&fmr_mutex);
|
||||
|
||||
if (tuner_powered())
|
||||
{
|
||||
si4700_read_reg(RDSD);
|
||||
memcpy(data, &cache[RDSA], 4 * sizeof (uint16_t));
|
||||
retval = true;
|
||||
}
|
||||
|
||||
mutex_unlock(&fmr_mutex);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Set the event flag */
|
||||
void si4700_rds_set_event(void)
|
||||
{
|
||||
mutex_lock(&fmr_mutex);
|
||||
rds_event = 1;
|
||||
mutex_unlock(&fmr_mutex);
|
||||
}
|
||||
|
||||
char * si4700_get_rds_info(int setting)
|
||||
{
|
||||
char *text = NULL;
|
||||
|
||||
switch(setting)
|
||||
{
|
||||
case RADIO_RDS_NAME:
|
||||
text = rds_get_ps();
|
||||
break;
|
||||
|
||||
case RADIO_RDS_TEXT:
|
||||
text = rds_get_rt();
|
||||
break;
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
#endif /* HAVE_RDS_CAP */
|
||||
|
||||
|
|
|
@ -89,6 +89,8 @@
|
|||
/* Define this if you have a SI4700 fm radio tuner */
|
||||
#define CONFIG_TUNER SI4700
|
||||
|
||||
#define HAVE_RDS_CAP
|
||||
|
||||
/* Define this if you have the WM8978 audio codec */
|
||||
#define HAVE_WM8978
|
||||
|
||||
|
@ -161,7 +163,7 @@
|
|||
#define GPIO_EVENT_MASK (USE_GPIO1_EVENTS)
|
||||
|
||||
/* Define this if target has an additional number of threads specific to it */
|
||||
#define TARGET_EXTRA_THREADS 2
|
||||
#define TARGET_EXTRA_THREADS 3
|
||||
|
||||
/* Type of mobile power - check this out */
|
||||
#define BATTERY_CAPACITY_DEFAULT 700 /* default battery capacity */
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
explicitly if different */
|
||||
#define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO)
|
||||
|
||||
#define HAVE_RDS_CAP
|
||||
|
||||
/* define this if you have a bitmap LCD display */
|
||||
#define HAVE_LCD_BITMAP
|
||||
/* define this if you have a colour LCD */
|
||||
|
@ -138,6 +140,9 @@
|
|||
/* define this if the flash memory uses the SecureDigital Memory Card protocol */
|
||||
#define CONFIG_STORAGE STORAGE_SD
|
||||
|
||||
/* Define this if target has an additional number of threads specific to it */
|
||||
#define TARGET_EXTRA_THREADS 1 /* RDS thread */
|
||||
|
||||
#define BATTERY_CAPACITY_DEFAULT 300 /* default battery capacity */
|
||||
#define BATTERY_CAPACITY_MIN 300 /* min. capacity selectable */
|
||||
#define BATTERY_CAPACITY_MAX 300 /* max. capacity selectable */
|
||||
|
|
33
firmware/export/rds.h
Normal file
33
firmware/export/rds.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2011 by Bertrik Sikken
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void rds_init(void);
|
||||
|
||||
void rds_reset(void);
|
||||
bool rds_process(uint16_t data[4]);
|
||||
|
||||
uint16_t rds_get_pi(void);
|
||||
char* rds_get_ps(void);
|
||||
char* rds_get_rt(void);
|
||||
|
||||
|
|
@ -39,10 +39,24 @@ void si4700_init(void);
|
|||
int si4700_set(int setting, int value);
|
||||
int si4700_get(int setting);
|
||||
void si4700_dbg_info(struct si4700_dbg_info *nfo);
|
||||
/* For interrupt-based mono/stereo indicator */
|
||||
bool si4700_st(void);
|
||||
|
||||
/** RDS support **/
|
||||
void si4700_rds_init(void);
|
||||
/* Read raw RDS info for processing */
|
||||
bool si4700_rds_read_raw(uint16_t data[4]);
|
||||
/* Radio is fully powered up or about to be powered down */
|
||||
void si4700_rds_powerup(bool on);
|
||||
/* Obtain specified string */
|
||||
char* si4700_get_rds_info(int setting);
|
||||
/* Set the event flag */
|
||||
void si4700_rds_set_event(void);
|
||||
|
||||
#ifndef CONFIG_TUNER_MULTI
|
||||
#define tuner_set si4700_set
|
||||
#define tuner_get si4700_get
|
||||
#define tuner_get_rds_info si4700_get_rds_info
|
||||
#endif
|
||||
|
||||
#endif /* _SI4700_H_ */
|
||||
|
|
|
@ -27,10 +27,14 @@
|
|||
I2C with a couple of GPIO pins.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "as3525.h"
|
||||
#include "system.h"
|
||||
#include "tuner.h"
|
||||
#include "generic_i2c.h"
|
||||
#include "fmradio_i2c.h"
|
||||
#include "thread.h"
|
||||
#include "rds.h"
|
||||
|
||||
#if defined(SANSA_CLIP) || defined(SANSA_C200V2)
|
||||
#define I2C_SCL_GPIO(x) GPIOB_PIN(x)
|
||||
|
@ -179,3 +183,58 @@ int fmradio_i2c_read(unsigned char address, unsigned char* buf, int count)
|
|||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_RDS_CAP
|
||||
/* Low-level RDS Support */
|
||||
static struct semaphore rds_sema;
|
||||
static uint32_t rds_stack[DEFAULT_STACK_SIZE/sizeof(uint32_t)];
|
||||
|
||||
/* RDS GPIO interrupt handler */
|
||||
void tuner_isr(void)
|
||||
{
|
||||
/* read and clear the interrupt */
|
||||
if (GPIOA_MIS & (1<<4)) {
|
||||
semaphore_release(&rds_sema);
|
||||
}
|
||||
GPIOA_IC = (1<<4);
|
||||
}
|
||||
|
||||
/* Captures RDS data and processes it */
|
||||
static void NORETURN_ATTR rds_thread(void)
|
||||
{
|
||||
uint16_t rds_data[4];
|
||||
|
||||
while (true) {
|
||||
semaphore_wait(&rds_sema, TIMEOUT_BLOCK);
|
||||
if (si4700_rds_read_raw(rds_data) && rds_process(rds_data)) {
|
||||
si4700_rds_set_event();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Called with on=true after full radio power up, and with on=false before
|
||||
powering down */
|
||||
void si4700_rds_powerup(bool on)
|
||||
{
|
||||
GPIOA_IE &= ~(1<<4); /* disable GPIO interrupt */
|
||||
|
||||
if (on) {
|
||||
GPIOA_DIR &= ~(1<<4); /* input */
|
||||
GPIOA_IS &= ~(1<<4); /* edge detect */
|
||||
GPIOA_IBE &= ~(1<<4); /* only one edge */
|
||||
GPIOA_IEV &= ~(1<<4); /* falling edge */
|
||||
GPIOA_IC = (1<<4); /* clear any pending interrupt */
|
||||
GPIOA_IE |= (1<<4); /* enable GPIO interrupt */
|
||||
}
|
||||
}
|
||||
|
||||
/* One-time RDS init at startup */
|
||||
void si4700_rds_init(void)
|
||||
{
|
||||
semaphore_init(&rds_sema, 1, 0);
|
||||
rds_init();
|
||||
create_thread(rds_thread, rds_stack, sizeof(rds_stack), 0, "rds"
|
||||
IF_PRIO(, PRIORITY_REALTIME) IF_COP(, CPU));
|
||||
}
|
||||
#endif /* HAVE_RDS_CAP */
|
||||
|
||||
|
|
|
@ -155,6 +155,10 @@ void INT_GPIOA(void)
|
|||
void button_gpioa_isr(void);
|
||||
button_gpioa_isr();
|
||||
#endif
|
||||
#ifdef HAVE_RDS_CAP
|
||||
void tuner_isr(void);
|
||||
tuner_isr();
|
||||
#endif
|
||||
}
|
||||
|
||||
void irq_handler(void)
|
||||
|
|
|
@ -23,8 +23,12 @@
|
|||
#include "system.h"
|
||||
#include "mc13783.h"
|
||||
#include "iomuxc-imx31.h"
|
||||
#include "gpio-imx31.h"
|
||||
#include "i2c-imx31.h"
|
||||
#include "fmradio_i2c.h"
|
||||
#include "thread.h"
|
||||
#include "rds.h"
|
||||
#include "tuner.h"
|
||||
|
||||
static struct i2c_node si4700_i2c_node =
|
||||
{
|
||||
|
@ -117,7 +121,57 @@ int fmradio_i2c_read(unsigned char address, unsigned char* buf, int count)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int si4700_st(void)
|
||||
bool si4700_st(void)
|
||||
{
|
||||
return (GPIO1_DR & (1 << 28)) >> 28;
|
||||
}
|
||||
|
||||
|
||||
/* Low-level RDS Support */
|
||||
static struct semaphore rds_sema;
|
||||
static uint32_t rds_stack[DEFAULT_STACK_SIZE/sizeof(uint32_t)];
|
||||
|
||||
/* RDS GPIO interrupt handler */
|
||||
void si4700_stc_rds_event(void)
|
||||
{
|
||||
/* read and clear the interrupt */
|
||||
SI4700_GPIO_STC_RDS_ISR = (1ul << SI4700_GPIO_STC_RDS_LINE);
|
||||
semaphore_release(&rds_sema);
|
||||
}
|
||||
|
||||
/* Called with on=true after full radio power up, and with on=false before
|
||||
powering down */
|
||||
void si4700_rds_powerup(bool on)
|
||||
{
|
||||
gpio_disable_event(SI4700_STC_RDS_EVENT_ID);
|
||||
|
||||
if (on)
|
||||
{
|
||||
SI4700_GPIO_STC_RDS_ISR = (1ul << SI4700_GPIO_STC_RDS_LINE);
|
||||
gpio_enable_event(SI4700_STC_RDS_EVENT_ID);
|
||||
}
|
||||
}
|
||||
|
||||
/* Captures RDS data and processes it */
|
||||
/* Use of a thread here is likely temporary */
|
||||
static void NORETURN_ATTR rds_thread(void)
|
||||
{
|
||||
uint16_t rds_data[4];
|
||||
|
||||
while (1)
|
||||
{
|
||||
semaphore_wait(&rds_sema, TIMEOUT_BLOCK);
|
||||
|
||||
if (si4700_rds_read_raw(rds_data) && rds_process(rds_data))
|
||||
si4700_rds_set_event();
|
||||
}
|
||||
}
|
||||
|
||||
/* One-time RDS init at startup */
|
||||
void si4700_rds_init(void)
|
||||
{
|
||||
semaphore_init(&rds_sema, 1, 0);
|
||||
rds_init();
|
||||
create_thread(rds_thread, rds_stack, sizeof(rds_stack), 0, "rds"
|
||||
IF_PRIO(, PRIORITY_REALTIME) IF_COP(, CPU));
|
||||
}
|
||||
|
|
|
@ -39,5 +39,12 @@ const struct gpio_event gpio1_events[] =
|
|||
.mask = 1 << MC13783_GPIO_LINE,
|
||||
.sense = GPIO_SENSE_HIGH_LEVEL,
|
||||
.callback = mc13783_event,
|
||||
}
|
||||
},
|
||||
/* Generates a 5ms low pulse on the line - detect the falling edge */
|
||||
[SI4700_STC_RDS_EVENT_ID] =
|
||||
{
|
||||
.mask = 1 << SI4700_GPIO_STC_RDS_LINE,
|
||||
.sense = GPIO_SENSE_FALLING,
|
||||
.callback = si4700_stc_rds_event,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -29,6 +29,12 @@
|
|||
#define MC13783_GPIO_ISR GPIO1_ISR
|
||||
#define MC13783_GPIO_LINE 31
|
||||
|
||||
/* SI4700 GPIO STC/RDS pin info for this target */
|
||||
#define SI4700_GPIO_STC_RDS_IMR GPIO1_IMR
|
||||
#define SI4700_GPIO_STC_RDS_NUM GPIO1_NUM
|
||||
#define SI4700_GPIO_STC_RDS_ISR GPIO1_ISR
|
||||
#define SI4700_GPIO_STC_RDS_LINE 27
|
||||
|
||||
#define GPIO1_INT_PRIO INT_PRIO_DEFAULT
|
||||
|
||||
/* Declare event indexes in priority order in a packed array */
|
||||
|
@ -36,7 +42,8 @@ enum gpio_event_ids
|
|||
{
|
||||
/* GPIO1 event IDs */
|
||||
MC13783_EVENT_ID = GPIO1_EVENT_FIRST,
|
||||
GPIO1_NUM_EVENTS = 1,
|
||||
SI4700_STC_RDS_EVENT_ID,
|
||||
GPIO1_NUM_EVENTS = 2,
|
||||
/* GPIO2 event IDs */
|
||||
/* none defined */
|
||||
/* GPIO3 event IDs */
|
||||
|
@ -44,5 +51,6 @@ enum gpio_event_ids
|
|||
};
|
||||
|
||||
void mc13783_event(void);
|
||||
void si4700_stc_rds_event(void);
|
||||
|
||||
#endif /* GPIO_TARGET_H */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue