summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2011-12-29 12:02:49 +0000
committerMichael Sevakis <jethead71@rockbox.org>2011-12-29 12:02:49 +0000
commit7b596416bf2cf533a514b4d1f7b95c6de6efa7d5 (patch)
treee1a0031a93591424eacdf943796680880077a3a4 /firmware
parent20d81d979a22403c16c1f1c576de63af07b2ea99 (diff)
downloadrockbox-7b596416bf2cf533a514b4d1f7b95c6de6efa7d5.zip
rockbox-7b596416bf2cf533a514b4d1f7b95c6de6efa7d5.tar.gz
rockbox-7b596416bf2cf533a514b4d1f7b95c6de6efa7d5.tar.bz2
rockbox-7b596416bf2cf533a514b4d1f7b95c6de6efa7d5.tar.xz
Gigabeat S: Update RDS processing to use asynchronous I2C rather than thread.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31462 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r--firmware/drivers/rds.c39
-rw-r--r--firmware/drivers/tuner/si4700.c29
-rw-r--r--firmware/export/config/gigabeats.h3
-rw-r--r--firmware/export/si4700.h12
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c63
5 files changed, 119 insertions, 27 deletions
diff --git a/firmware/drivers/rds.c b/firmware/drivers/rds.c
index 09bc338..828c28b 100644
--- a/firmware/drivers/rds.c
+++ b/firmware/drivers/rds.c
@@ -36,14 +36,46 @@ static char rt_copy[65];
static int rt_segment;
static int rt_abflag;
+#ifdef SI4700_RDS_ASYNC
+/* Functions are called in ISR context */
+#define rds_disable_irq_save() disable_irq_save()
+#define rds_restore_irq(old) restore_irq(old)
+/* Need triple buffer so string isn't clobbered while caller is using it */
+static inline char * get_ps(void)
+{
+ static char ps_out[9];
+ int oldlevel = rds_disable_irq_save();
+ strcpy(ps_out, ps_copy);
+ rds_restore_irq(oldlevel);
+ return ps_out;
+}
+static inline char * get_rt(void)
+{
+ static char rt_out[65];
+ int oldlevel = rds_disable_irq_save();
+ strcpy(rt_out, rt_copy);
+ rds_restore_irq(oldlevel);
+ return rt_out;
+}
+#else /* ndef SI4700_RDS_ASYNC */
+#define rds_disable_irq_save() 0
+#define rds_restore_irq(old) ((void)(old))
+static inline char * get_ps(void) { return ps_copy; }
+static inline char * get_rt(void) { return rt_copy; }
+#endif /* SI4700_RDS_ASYNC */
+
/* resets the rds parser */
void rds_reset(void)
{
+ int oldlevel = rds_disable_irq_save();
+
ps_copy[0] = '\0';
ps_segment = 0;
rt_copy[0] = '\0';
rt_segment = 0;
pi = 0;
+
+ rds_restore_irq(oldlevel);
}
/* initialises the rds parser */
@@ -172,6 +204,9 @@ bool rds_process(uint16_t data[4])
return false;
}
+/* TODO: The caller really should provide the buffer in order to regulate
+ access */
+
/* returns the programme identification code */
uint16_t rds_get_pi(void)
{
@@ -181,12 +216,12 @@ uint16_t rds_get_pi(void)
/* returns the most recent valid programme service name */
char* rds_get_ps(void)
{
- return ps_copy;
+ return get_ps();
}
/* returns the most recent valid RadioText message */
char* rds_get_rt(void)
{
- return rt_copy;
+ return get_rt();
}
diff --git a/firmware/drivers/tuner/si4700.c b/firmware/drivers/tuner/si4700.c
index bebbd0c..0684d20 100644
--- a/firmware/drivers/tuner/si4700.c
+++ b/firmware/drivers/tuner/si4700.c
@@ -556,6 +556,34 @@ void si4700_dbg_info(struct si4700_dbg_info *nfo)
}
#ifdef HAVE_RDS_CAP
+
+#ifdef SI4700_RDS_ASYNC
+/* Read raw RDS info for processing - asynchronously */
+
+/* Assumes regbuf is 32 bytes */
+void si4700_rds_read_raw_async(void)
+{
+ si4700_read_raw_async((RDSD - STATUSRSSI + 1) * 2);
+}
+
+void si4700_rds_read_raw_async_complete(unsigned char *regbuf,
+ uint16_t data[4])
+{
+ const int index = (RDSA - STATUSRSSI) * 2;
+
+ for (int i = 0; i < 4; i++) {
+ data[i] = regbuf[index] << 8 | regbuf[index + 1];
+ regbuf += 2;
+ }
+}
+
+/* Set the event flag */
+void si4700_rds_set_event(void)
+{
+ rds_event = 1;
+}
+
+#else
/* Read raw RDS info for processing */
bool si4700_rds_read_raw(uint16_t data[4])
{
@@ -582,6 +610,7 @@ void si4700_rds_set_event(void)
rds_event = 1;
mutex_unlock(&fmr_mutex);
}
+#endif /* SI4700_RDS_ASYNC */
char * si4700_get_rds_info(int setting)
{
diff --git a/firmware/export/config/gigabeats.h b/firmware/export/config/gigabeats.h
index 04e7b15..9a34791 100644
--- a/firmware/export/config/gigabeats.h
+++ b/firmware/export/config/gigabeats.h
@@ -90,6 +90,7 @@
#define CONFIG_TUNER SI4700
#define HAVE_RDS_CAP
+#define SI4700_RDS_ASYNC
/* Define this if you have the WM8978 audio codec */
#define HAVE_WM8978
@@ -163,7 +164,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 3
+#define TARGET_EXTRA_THREADS 2
/* Type of mobile power - check this out */
#define BATTERY_CAPACITY_DEFAULT 700 /* default battery capacity */
diff --git a/firmware/export/si4700.h b/firmware/export/si4700.h
index 761ad1c..fe55dd3 100644
--- a/firmware/export/si4700.h
+++ b/firmware/export/si4700.h
@@ -44,10 +44,18 @@ 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);
+#ifdef SI4700_RDS_ASYNC
+/* Read raw RDS info for processing - asynchronously */
+void si4700_read_raw_async(int count);
+void si4700_rds_read_raw_async(void);
+void si4700_rds_read_raw_async_complete(unsigned char *regbuf,
+ uint16_t data[4]);
+#else
+/* Read raw RDS info for processing */
+bool si4700_rds_read_raw(uint16_t data[4]);
+#endif
/* Obtain specified string */
char* si4700_get_rds_info(int setting);
/* Set the event flag */
diff --git a/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c
index e0457e3..a7b9bc2 100644
--- a/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c
+++ b/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c
@@ -128,15 +128,52 @@ bool si4700_st(void)
/* Low-level RDS Support */
-static struct semaphore rds_sema;
-static uint32_t rds_stack[DEFAULT_STACK_SIZE/sizeof(uint32_t)];
-/* RDS GPIO interrupt handler */
+/* Transfer descriptor for RDS async operations */
+struct si4700_i2c_transfer_desc
+{
+ struct i2c_transfer_desc xfer;
+ unsigned char regbuf[32];
+} si4700_xfer =
+{
+ .xfer = { .node = &si4700_i2c_node }
+};
+
+static void si4700_rds_read_raw_callback(struct i2c_transfer_desc *xfer)
+{
+ struct si4700_i2c_transfer_desc *xf =
+ (struct si4700_i2c_transfer_desc *)xfer;
+
+ if (xfer->rxcount != 0)
+ return; /* Read didn't finish */
+
+ uint16_t rds_data[4];
+
+ si4700_rds_read_raw_async_complete(xf->regbuf, rds_data);
+
+ if (rds_process(rds_data))
+ si4700_rds_set_event();
+}
+
+/* Callback from si4700_rds_read_raw to execute the read */
+void si4700_read_raw_async(int count)
+{
+ si4700_xfer.xfer.txdata = NULL;
+ si4700_xfer.xfer.txcount = 0;
+ si4700_xfer.xfer.rxdata = si4700_xfer.regbuf;
+ si4700_xfer.xfer.rxcount = count;
+ si4700_xfer.xfer.callback = si4700_rds_read_raw_callback;
+ si4700_xfer.xfer.next = NULL;
+
+ i2c_transfer(&si4700_xfer.xfer);
+}
+
+/* RDS GPIO interrupt handler - start RDS data read */
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);
+ si4700_rds_read_raw_async();
}
/* Called with on=true after full radio power up, and with on=false before
@@ -152,26 +189,8 @@ void si4700_rds_powerup(bool on)
}
}
-/* 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));
}