diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2011-12-29 12:02:49 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2011-12-29 12:02:49 +0000 |
commit | 7b596416bf2cf533a514b4d1f7b95c6de6efa7d5 (patch) | |
tree | e1a0031a93591424eacdf943796680880077a3a4 | |
parent | 20d81d979a22403c16c1f1c576de63af07b2ea99 (diff) | |
download | rockbox-7b596416bf2cf533a514b4d1f7b95c6de6efa7d5.tar.gz rockbox-7b596416bf2cf533a514b4d1f7b95c6de6efa7d5.zip |
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
-rw-r--r-- | firmware/drivers/rds.c | 39 | ||||
-rw-r--r-- | firmware/drivers/tuner/si4700.c | 29 | ||||
-rw-r--r-- | firmware/export/config/gigabeats.h | 3 | ||||
-rw-r--r-- | firmware/export/si4700.h | 12 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c | 63 |
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]; | |||
36 | static int rt_segment; | 36 | static int rt_segment; |
37 | static int rt_abflag; | 37 | static 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 */ | ||
44 | static 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 | } | ||
52 | static 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)) | ||
63 | static inline char * get_ps(void) { return ps_copy; } | ||
64 | static inline char * get_rt(void) { return rt_copy; } | ||
65 | #endif /* SI4700_RDS_ASYNC */ | ||
66 | |||
39 | /* resets the rds parser */ | 67 | /* resets the rds parser */ |
40 | void rds_reset(void) | 68 | void 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 */ |
176 | uint16_t rds_get_pi(void) | 211 | uint16_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 */ |
182 | char* rds_get_ps(void) | 217 | char* 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 */ |
188 | char* rds_get_rt(void) | 223 | char* 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 */ | ||
564 | void si4700_rds_read_raw_async(void) | ||
565 | { | ||
566 | si4700_read_raw_async((RDSD - STATUSRSSI + 1) * 2); | ||
567 | } | ||
568 | |||
569 | void 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 */ | ||
581 | void 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 */ |
560 | bool si4700_rds_read_raw(uint16_t data[4]) | 588 | bool 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 | ||
586 | char * si4700_get_rds_info(int setting) | 615 | char * 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 **/ |
46 | void si4700_rds_init(void); | 46 | void si4700_rds_init(void); |
47 | /* Read raw RDS info for processing */ | ||
48 | bool 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 */ |
50 | void si4700_rds_powerup(bool on); | 48 | void si4700_rds_powerup(bool on); |
49 | #ifdef SI4700_RDS_ASYNC | ||
50 | /* Read raw RDS info for processing - asynchronously */ | ||
51 | void si4700_read_raw_async(int count); | ||
52 | void si4700_rds_read_raw_async(void); | ||
53 | void si4700_rds_read_raw_async_complete(unsigned char *regbuf, | ||
54 | uint16_t data[4]); | ||
55 | #else | ||
56 | /* Read raw RDS info for processing */ | ||
57 | bool si4700_rds_read_raw(uint16_t data[4]); | ||
58 | #endif | ||
51 | /* Obtain specified string */ | 59 | /* Obtain specified string */ |
52 | char* si4700_get_rds_info(int setting); | 60 | char* 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 */ |
131 | static struct semaphore rds_sema; | ||
132 | static uint32_t rds_stack[DEFAULT_STACK_SIZE/sizeof(uint32_t)]; | ||
133 | 131 | ||
134 | /* RDS GPIO interrupt handler */ | 132 | /* Transfer descriptor for RDS async operations */ |
133 | struct 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 | |||
142 | static 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 */ | ||
159 | void 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 */ | ||
135 | void si4700_stc_rds_event(void) | 172 | void 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 */ | ||
157 | static 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 */ |
171 | void si4700_rds_init(void) | 193 | void 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 | } |