From de0346065b415e03efad5746ffdee99d607a0d3c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 15 Nov 2021 20:46:28 +0100 Subject: Sansa Clip+: add RDS support Based on a patch by Amaury Pouly which was based on a patch from Ryan Hitchman. I mainly moved the code for polling into the tuner driver so it can be reused by other targets. I added the CONFIG parameter for the polling frequency (in ticks) to save energy. Also, I did some minor cleanups. Change-Id: I95a62e7e1e42c62dbf47ecb27a3b312a42be62aa --- firmware/drivers/tuner/si4700.c | 55 +++++++++++++++++++++++++ firmware/export/config.h | 1 + firmware/export/config/sansaclipplus.h | 6 +++ firmware/export/si4700.h | 8 +++- firmware/target/arm/as3525/fmradio-i2c-as3525.c | 6 +++ firmware/target/arm/as3525/system-as3525.c | 2 +- 6 files changed, 76 insertions(+), 2 deletions(-) diff --git a/firmware/drivers/tuner/si4700.c b/firmware/drivers/tuner/si4700.c index 88ff6c69f7..57006b4e3c 100644 --- a/firmware/drivers/tuner/si4700.c +++ b/firmware/drivers/tuner/si4700.c @@ -587,12 +587,67 @@ void si4700_rds_process(void) if (tuner_powered()) { si4700_read_reg(RDSD); +#if (CONFIG_RDS & RDS_CFG_POLL) + /* we need to keep track of the ready bit because it stays set for 80ms + * and we must avoid processing it twice */ + + static bool old_rdsr = false; + bool rdsr = (cache[STATUSRSSI] & STATUSRSSI_RDSR); + if (rdsr && !old_rdsr) + rds_process(&cache[RDSA]); + old_rdsr = rdsr; +#else rds_process(&cache[RDSA]); +#endif /* !(CONFIG_RDS & RDS_CFG_POLL) */ } mutex_unlock(&fmr_mutex); } #endif /* (CONFIG_RDS & RDS_CFG_ISR) */ +#if (CONFIG_RDS & RDS_CFG_POLL) +static struct event_queue rds_queue; +static uint32_t rds_stack[DEFAULT_STACK_SIZE / sizeof(uint32_t)]; + +enum { + Q_POWERUP, +}; + +static void NORETURN_ATTR rds_thread(void) +{ + /* start up frozen */ + int timeout = TIMEOUT_BLOCK; + struct queue_event ev; + + while (true) { + queue_wait_w_tmo(&rds_queue, &ev, timeout); + switch (ev.id) { + case Q_POWERUP: + /* power up: timeout after 1 tick, else block indefinitely */ + timeout = ev.data ? CONFIG_RDS_POLL_TICKS : TIMEOUT_BLOCK; + break; + case SYS_TIMEOUT:; + /* Captures RDS data and processes it */ + si4700_rds_process(); + break; + } + } +} + +/* true after full radio power up, and false before powering down */ +void si4700_rds_powerup(bool on) +{ + queue_post(&rds_queue, Q_POWERUP, on); +} + +/* One-time RDS init at startup */ +void si4700_rds_init(void) +{ + queue_init(&rds_queue, false); + create_thread(rds_thread, rds_stack, sizeof(rds_stack), 0, "rds" + IF_PRIO(, PRIORITY_PLAYBACK) IF_COP(, CPU)); +} +#endif /* !(CONFIG_RDS & RDS_CFG_POLL) */ + #endif /* HAVE_RDS_CAP */ diff --git a/firmware/export/config.h b/firmware/export/config.h index e887796acc..52f647f2fa 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -718,6 +718,7 @@ Lyre prototype 1 */ #define RDS_CFG_ISR 0x1 /* uses ISR to process packets */ #define RDS_CFG_PROCESS 0x2 /* uses raw packet processing */ #define RDS_CFG_PUSH 0x4 /* pushes processed information */ +#define RDS_CFG_POLL 0x8 /* tuner driver provides a polling function */ #ifndef CONFIG_RDS #define CONFIG_RDS RDS_CFG_PROCESS /* thread processing+raw processing */ #endif /* CONFIG_RDS */ diff --git a/firmware/export/config/sansaclipplus.h b/firmware/export/config/sansaclipplus.h index 3108bace61..e0df0c28c3 100644 --- a/firmware/export/config/sansaclipplus.h +++ b/firmware/export/config/sansaclipplus.h @@ -17,6 +17,9 @@ #ifndef BOOTLOADER #define HAVE_HOTSWAP +#define HAVE_RDS_CAP +#define CONFIG_RDS (RDS_CFG_POLL | RDS_CFG_PROCESS) +#define CONFIG_RDS_POLL_TICKS 4 #endif #define HW_SAMPR_CAPS SAMPR_CAP_ALL_96 @@ -146,6 +149,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 290 /* default battery capacity */ #define BATTERY_CAPACITY_MIN 290 /* min. capacity selectable */ #define BATTERY_CAPACITY_MAX 290 /* max. capacity selectable */ diff --git a/firmware/export/si4700.h b/firmware/export/si4700.h index bd75bf0817..033b435f2a 100644 --- a/firmware/export/si4700.h +++ b/firmware/export/si4700.h @@ -55,7 +55,13 @@ void si4700_rds_read_raw_async(unsigned char *buf, int count); /* implemented by void si4700_rds_interrupt(void); #endif /* (CONFIG_RDS & RDS_CFG_ISR) */ -/* Read raw RDS info for processing */ +/* Read raw RDS info for processing. + * - If RDS_CFG_ISR is set, the tuner driver will call si4700_rds_read_raw_async() which should + * perform an asynchronous read and call this function when the data has been read. + * - If RDS_CFG_POLL is set, this function will read status and RDS data and process it if a new + * packet is available. + * - Otherwise this function will read a RDS packet and process it under the assumption that it is + * new. */ void si4700_rds_process(void); #endif /* HAVE_RDS_CAP */ diff --git a/firmware/target/arm/as3525/fmradio-i2c-as3525.c b/firmware/target/arm/as3525/fmradio-i2c-as3525.c index 5b629f5ad4..7f6cb8366b 100644 --- a/firmware/target/arm/as3525/fmradio-i2c-as3525.c +++ b/firmware/target/arm/as3525/fmradio-i2c-as3525.c @@ -185,6 +185,11 @@ int fmradio_i2c_read(unsigned char address, unsigned char* buf, int count) } #ifdef HAVE_RDS_CAP +/* On the Sansa Clip Zip, the tuner interrupt line is routed to the SoC so we + * can use to detect when a RDS packet is ready. On the Clip+, we have to + * regularly poll. */ + +#if !(CONFIG_RDS & RDS_CFG_POLL) /* Low-level RDS Support */ static struct semaphore rds_sema; static uint32_t rds_stack[DEFAULT_STACK_SIZE/sizeof(uint32_t)]; @@ -231,4 +236,5 @@ void si4700_rds_init(void) create_thread(rds_thread, rds_stack, sizeof(rds_stack), 0, "rds" IF_PRIO(, PRIORITY_REALTIME) IF_COP(, CPU)); } +#endif /* !(CONFIG_RDS & RDS_CFG_POLL) */ #endif /* HAVE_RDS_CAP */ diff --git a/firmware/target/arm/as3525/system-as3525.c b/firmware/target/arm/as3525/system-as3525.c index 83ccb55f79..0450c8b410 100644 --- a/firmware/target/arm/as3525/system-as3525.c +++ b/firmware/target/arm/as3525/system-as3525.c @@ -180,7 +180,7 @@ void INT_GPIOA(void) void button_gpioa_isr(void); button_gpioa_isr(); #endif -#ifdef HAVE_RDS_CAP +#if defined(HAVE_RDS_CAP) && !(CONFIG_RDS & RDS_CFG_POLL) void tuner_isr(void); tuner_isr(); #endif -- cgit v1.2.3