summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
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 09bc33807c..828c28b672 100644
--- a/firmware/drivers/rds.c
+++ b/firmware/drivers/rds.c
@@ -36,14 +36,46 @@ static char rt_copy[65];
36static int rt_segment; 36static int rt_segment;
37static int rt_abflag; 37static int rt_abflag;
38 38
39#ifdef SI4700_RDS_ASYNC
40/* Functions are called in ISR context */
41#define rds_disable_irq_save() disable_irq_save()
42#define rds_restore_irq(old) restore_irq(old)
43/* Need triple buffer so string isn't clobbered while caller is using it */
44static inline char * get_ps(void)
45{
46 static char ps_out[9];
47 int oldlevel = rds_disable_irq_save();
48 strcpy(ps_out, ps_copy);
49 rds_restore_irq(oldlevel);
50 return ps_out;
51}
52static inline char * get_rt(void)
53{
54 static char rt_out[65];
55 int oldlevel = rds_disable_irq_save();
56 strcpy(rt_out, rt_copy);
57 rds_restore_irq(oldlevel);
58 return rt_out;
59}
60#else /* ndef SI4700_RDS_ASYNC */
61#define rds_disable_irq_save() 0
62#define rds_restore_irq(old) ((void)(old))
63static inline char * get_ps(void) { return ps_copy; }
64static inline char * get_rt(void) { return rt_copy; }
65#endif /* SI4700_RDS_ASYNC */
66
39/* resets the rds parser */ 67/* resets the rds parser */
40void rds_reset(void) 68void rds_reset(void)
41{ 69{
70 int oldlevel = rds_disable_irq_save();
71
42 ps_copy[0] = '\0'; 72 ps_copy[0] = '\0';
43 ps_segment = 0; 73 ps_segment = 0;
44 rt_copy[0] = '\0'; 74 rt_copy[0] = '\0';
45 rt_segment = 0; 75 rt_segment = 0;
46 pi = 0; 76 pi = 0;
77
78 rds_restore_irq(oldlevel);
47} 79}
48 80
49/* initialises the rds parser */ 81/* initialises the rds parser */
@@ -172,6 +204,9 @@ bool rds_process(uint16_t data[4])
172 return false; 204 return false;
173} 205}
174 206
207/* TODO: The caller really should provide the buffer in order to regulate
208 access */
209
175/* returns the programme identification code */ 210/* returns the programme identification code */
176uint16_t rds_get_pi(void) 211uint16_t rds_get_pi(void)
177{ 212{
@@ -181,12 +216,12 @@ uint16_t rds_get_pi(void)
181/* returns the most recent valid programme service name */ 216/* returns the most recent valid programme service name */
182char* rds_get_ps(void) 217char* rds_get_ps(void)
183{ 218{
184 return ps_copy; 219 return get_ps();
185} 220}
186 221
187/* returns the most recent valid RadioText message */ 222/* returns the most recent valid RadioText message */
188char* rds_get_rt(void) 223char* rds_get_rt(void)
189{ 224{
190 return rt_copy; 225 return get_rt();
191} 226}
192 227
diff --git a/firmware/drivers/tuner/si4700.c b/firmware/drivers/tuner/si4700.c
index bebbd0c881..0684d2042f 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)
556} 556}
557 557
558#ifdef HAVE_RDS_CAP 558#ifdef HAVE_RDS_CAP
559
560#ifdef SI4700_RDS_ASYNC
561/* Read raw RDS info for processing - asynchronously */
562
563/* Assumes regbuf is 32 bytes */
564void si4700_rds_read_raw_async(void)
565{
566 si4700_read_raw_async((RDSD - STATUSRSSI + 1) * 2);
567}
568
569void si4700_rds_read_raw_async_complete(unsigned char *regbuf,
570 uint16_t data[4])
571{
572 const int index = (RDSA - STATUSRSSI) * 2;
573
574 for (int i = 0; i < 4; i++) {
575 data[i] = regbuf[index] << 8 | regbuf[index + 1];
576 regbuf += 2;
577 }
578}
579
580/* Set the event flag */
581void si4700_rds_set_event(void)
582{
583 rds_event = 1;
584}
585
586#else
559/* Read raw RDS info for processing */ 587/* Read raw RDS info for processing */
560bool si4700_rds_read_raw(uint16_t data[4]) 588bool si4700_rds_read_raw(uint16_t data[4])
561{ 589{
@@ -582,6 +610,7 @@ void si4700_rds_set_event(void)
582 rds_event = 1; 610 rds_event = 1;
583 mutex_unlock(&fmr_mutex); 611 mutex_unlock(&fmr_mutex);
584} 612}
613#endif /* SI4700_RDS_ASYNC */
585 614
586char * si4700_get_rds_info(int setting) 615char * si4700_get_rds_info(int setting)
587{ 616{
diff --git a/firmware/export/config/gigabeats.h b/firmware/export/config/gigabeats.h
index 04e7b156b6..9a34791ab1 100644
--- a/firmware/export/config/gigabeats.h
+++ b/firmware/export/config/gigabeats.h
@@ -90,6 +90,7 @@
90#define CONFIG_TUNER SI4700 90#define CONFIG_TUNER SI4700
91 91
92#define HAVE_RDS_CAP 92#define HAVE_RDS_CAP
93#define SI4700_RDS_ASYNC
93 94
94/* Define this if you have the WM8978 audio codec */ 95/* Define this if you have the WM8978 audio codec */
95#define HAVE_WM8978 96#define HAVE_WM8978
@@ -163,7 +164,7 @@
163#define GPIO_EVENT_MASK (USE_GPIO1_EVENTS) 164#define GPIO_EVENT_MASK (USE_GPIO1_EVENTS)
164 165
165/* Define this if target has an additional number of threads specific to it */ 166/* Define this if target has an additional number of threads specific to it */
166#define TARGET_EXTRA_THREADS 3 167#define TARGET_EXTRA_THREADS 2
167 168
168/* Type of mobile power - check this out */ 169/* Type of mobile power - check this out */
169#define BATTERY_CAPACITY_DEFAULT 700 /* default battery capacity */ 170#define BATTERY_CAPACITY_DEFAULT 700 /* default battery capacity */
diff --git a/firmware/export/si4700.h b/firmware/export/si4700.h
index 761ad1ca24..fe55dd3853 100644
--- a/firmware/export/si4700.h
+++ b/firmware/export/si4700.h
@@ -44,10 +44,18 @@ bool si4700_st(void);
44 44
45/** RDS support **/ 45/** RDS support **/
46void si4700_rds_init(void); 46void si4700_rds_init(void);
47/* Read raw RDS info for processing */
48bool si4700_rds_read_raw(uint16_t data[4]);
49/* Radio is fully powered up or about to be powered down */ 47/* Radio is fully powered up or about to be powered down */
50void si4700_rds_powerup(bool on); 48void si4700_rds_powerup(bool on);
49#ifdef SI4700_RDS_ASYNC
50/* Read raw RDS info for processing - asynchronously */
51void si4700_read_raw_async(int count);
52void si4700_rds_read_raw_async(void);
53void si4700_rds_read_raw_async_complete(unsigned char *regbuf,
54 uint16_t data[4]);
55#else
56/* Read raw RDS info for processing */
57bool si4700_rds_read_raw(uint16_t data[4]);
58#endif
51/* Obtain specified string */ 59/* Obtain specified string */
52char* si4700_get_rds_info(int setting); 60char* si4700_get_rds_info(int setting);
53/* Set the event flag */ 61/* 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 e0457e367a..a7b9bc21da 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)
128 128
129 129
130/* Low-level RDS Support */ 130/* Low-level RDS Support */
131static struct semaphore rds_sema;
132static uint32_t rds_stack[DEFAULT_STACK_SIZE/sizeof(uint32_t)];
133 131
134/* RDS GPIO interrupt handler */ 132/* Transfer descriptor for RDS async operations */
133struct si4700_i2c_transfer_desc
134{
135 struct i2c_transfer_desc xfer;
136 unsigned char regbuf[32];
137} si4700_xfer =
138{
139 .xfer = { .node = &si4700_i2c_node }
140};
141
142static void si4700_rds_read_raw_callback(struct i2c_transfer_desc *xfer)
143{
144 struct si4700_i2c_transfer_desc *xf =
145 (struct si4700_i2c_transfer_desc *)xfer;
146
147 if (xfer->rxcount != 0)
148 return; /* Read didn't finish */
149
150 uint16_t rds_data[4];
151
152 si4700_rds_read_raw_async_complete(xf->regbuf, rds_data);
153
154 if (rds_process(rds_data))
155 si4700_rds_set_event();
156}
157
158/* Callback from si4700_rds_read_raw to execute the read */
159void si4700_read_raw_async(int count)
160{
161 si4700_xfer.xfer.txdata = NULL;
162 si4700_xfer.xfer.txcount = 0;
163 si4700_xfer.xfer.rxdata = si4700_xfer.regbuf;
164 si4700_xfer.xfer.rxcount = count;
165 si4700_xfer.xfer.callback = si4700_rds_read_raw_callback;
166 si4700_xfer.xfer.next = NULL;
167
168 i2c_transfer(&si4700_xfer.xfer);
169}
170
171/* RDS GPIO interrupt handler - start RDS data read */
135void si4700_stc_rds_event(void) 172void si4700_stc_rds_event(void)
136{ 173{
137 /* read and clear the interrupt */ 174 /* read and clear the interrupt */
138 SI4700_GPIO_STC_RDS_ISR = (1ul << SI4700_GPIO_STC_RDS_LINE); 175 SI4700_GPIO_STC_RDS_ISR = (1ul << SI4700_GPIO_STC_RDS_LINE);
139 semaphore_release(&rds_sema); 176 si4700_rds_read_raw_async();
140} 177}
141 178
142/* Called with on=true after full radio power up, and with on=false before 179/* Called with on=true after full radio power up, and with on=false before
@@ -152,26 +189,8 @@ void si4700_rds_powerup(bool on)
152 } 189 }
153} 190}
154 191
155/* Captures RDS data and processes it */
156/* Use of a thread here is likely temporary */
157static void NORETURN_ATTR rds_thread(void)
158{
159 uint16_t rds_data[4];
160
161 while (1)
162 {
163 semaphore_wait(&rds_sema, TIMEOUT_BLOCK);
164
165 if (si4700_rds_read_raw(rds_data) && rds_process(rds_data))
166 si4700_rds_set_event();
167 }
168}
169
170/* One-time RDS init at startup */ 192/* One-time RDS init at startup */
171void si4700_rds_init(void) 193void si4700_rds_init(void)
172{ 194{
173 semaphore_init(&rds_sema, 1, 0);
174 rds_init(); 195 rds_init();
175 create_thread(rds_thread, rds_stack, sizeof(rds_stack), 0, "rds"
176 IF_PRIO(, PRIORITY_REALTIME) IF_COP(, CPU));
177} 196}