diff options
Diffstat (limited to 'firmware/drivers/tuner/ipod_remote_tuner.c')
-rw-r--r-- | firmware/drivers/tuner/ipod_remote_tuner.c | 444 |
1 files changed, 444 insertions, 0 deletions
diff --git a/firmware/drivers/tuner/ipod_remote_tuner.c b/firmware/drivers/tuner/ipod_remote_tuner.c new file mode 100644 index 0000000000..07a5eeb9a6 --- /dev/null +++ b/firmware/drivers/tuner/ipod_remote_tuner.c | |||
@@ -0,0 +1,444 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * tuner for the ipod fm remote and other ipod remote tuners | ||
10 | * | ||
11 | * Copyright (C) 2009 Laurent Gautier | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | #include "config.h" | ||
23 | #include <stdio.h> | ||
24 | #include <stdbool.h> | ||
25 | #include <string.h> | ||
26 | #include <stdlib.h> | ||
27 | #include "kernel.h" | ||
28 | #include "iap.h" | ||
29 | #include "tuner.h" /* tuner abstraction interface */ | ||
30 | #include "adc.h" | ||
31 | #include "settings.h" | ||
32 | |||
33 | static bool powered = false; | ||
34 | |||
35 | static unsigned char tuner_param = 0x00, old_tuner_param = 0xFF; | ||
36 | /* temp var for tests to avoid looping execution in submenus settings*/ | ||
37 | int mono_mode = -1, old_region = -1; | ||
38 | |||
39 | int radio_present = 0; | ||
40 | int tuner_frequency = 0; | ||
41 | int tuner_signal_power = 0; | ||
42 | int radio_tuned = 0; | ||
43 | int rds_event = 0; | ||
44 | |||
45 | char rds_radioname[9]; | ||
46 | char rds_radioinfo[70]; /* do we need more? */ | ||
47 | |||
48 | union FRQ { | ||
49 | unsigned long int frequency_radio; | ||
50 | char data_frequency[4]; | ||
51 | }Frequency; | ||
52 | |||
53 | void rmt_tuner_freq(void) | ||
54 | { | ||
55 | char tempdata[4]; | ||
56 | tempdata[0] = serbuf[6]; | ||
57 | tempdata[1] = serbuf[5]; | ||
58 | tempdata[2] = serbuf[4]; | ||
59 | tempdata[3] = serbuf[3]; | ||
60 | |||
61 | memcpy(Frequency.data_frequency,tempdata,4); | ||
62 | tuner_frequency = (Frequency.frequency_radio*1000); | ||
63 | radio_tuned = 1; | ||
64 | rmt_tuner_signal_power(serbuf[7]); | ||
65 | } | ||
66 | |||
67 | void rmt_tuner_set_freq(int curr_freq) | ||
68 | { | ||
69 | if (curr_freq != tuner_frequency) | ||
70 | { | ||
71 | radio_tuned = 0; | ||
72 | tuner_signal_power = 0; | ||
73 | /* clear rds name and info */ | ||
74 | memset(rds_radioname,' ',sizeof(rds_radioname)); | ||
75 | memset(rds_radioinfo,' ',sizeof(rds_radioinfo)); | ||
76 | /* ex: 00 01 63 14 = 90.9MHz */ | ||
77 | unsigned char data[] = {0x07, 0x0B, 0x00, 0x01, 0x63, 0x14}; | ||
78 | |||
79 | if (curr_freq != 0) | ||
80 | { | ||
81 | curr_freq = curr_freq / 1000; | ||
82 | char tempdata[4]; | ||
83 | |||
84 | Frequency.frequency_radio = curr_freq; | ||
85 | tempdata[0] = Frequency.data_frequency[3]; | ||
86 | tempdata[1] = Frequency.data_frequency[2]; | ||
87 | tempdata[2] = Frequency.data_frequency[1]; | ||
88 | tempdata[3] = Frequency.data_frequency[0]; | ||
89 | |||
90 | memcpy(data+2,tempdata,4); | ||
91 | iap_send_pkt(data, sizeof(data)); | ||
92 | } | ||
93 | } | ||
94 | } | ||
95 | |||
96 | void rmt_tuner_signal_power(unsigned char value) | ||
97 | { | ||
98 | tuner_signal_power = (int)(value); | ||
99 | } | ||
100 | |||
101 | void rmt_tuner_sleep(int state) | ||
102 | { | ||
103 | if (state == 0) | ||
104 | { | ||
105 | /* tuner HW on */ | ||
106 | unsigned char data[] = {0x07, 0x05, 0x01}; | ||
107 | iap_send_pkt(data, sizeof(data)); | ||
108 | /* boost gain */ | ||
109 | unsigned char data1[] = {0x07, 0x24, 0x06 }; | ||
110 | iap_send_pkt(data1, sizeof(data1)); | ||
111 | /* set volume */ | ||
112 | unsigned char data2[] = {0x03, 0x09, 0x04, 0x00, 0x77 }; | ||
113 | iap_send_pkt(data2, sizeof(data2)); | ||
114 | /* set rds on */ | ||
115 | unsigned char data3[] = {0x07, 0x20, 0x40, 0x00, 0x00, 0x10 }; | ||
116 | iap_send_pkt(data3, sizeof(data3)); | ||
117 | } | ||
118 | else | ||
119 | { | ||
120 | /* unbooste gain */ | ||
121 | unsigned char data[] = {0x07, 0x24, 0x00}; | ||
122 | iap_send_pkt(data, sizeof(data)); | ||
123 | /* set rds off */ | ||
124 | unsigned char data1[] = {0x07, 0x20, 0x00, 0x00, 0x00, 0x00 }; | ||
125 | iap_send_pkt(data1, sizeof(data1)); | ||
126 | /* stop tuner HW */ | ||
127 | unsigned char data2[] = {0x07, 0x05, 0x00}; | ||
128 | iap_send_pkt(data2, sizeof(data2)); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | void rmt_tuner_scan(int param) | ||
133 | { | ||
134 | unsigned char data[] = {0x07, 0x11, 0x08}; /* RSSI level */ | ||
135 | unsigned char updown = 0x00; | ||
136 | radio_tuned = 0; | ||
137 | iap_send_pkt(data, sizeof(data)); | ||
138 | |||
139 | if (param == 1) | ||
140 | { | ||
141 | updown = 0x07; /* scan up */ | ||
142 | } | ||
143 | else if (param == -1) | ||
144 | { | ||
145 | updown = 0x08; /* scan down */ | ||
146 | } | ||
147 | else if (param == 10) | ||
148 | { | ||
149 | updown = 0x01; /* scan up starting from beginning of the band */ | ||
150 | } | ||
151 | unsigned char data1[] = {0x07, 0x12, updown}; | ||
152 | iap_send_pkt(data1, sizeof(data1)); | ||
153 | } | ||
154 | |||
155 | void rmt_tuner_mute(int value) | ||
156 | { | ||
157 | /* mute flag off (play) */ | ||
158 | unsigned char data[] = {0x03, 0x09, 0x03, 0x01}; | ||
159 | if (value) | ||
160 | { | ||
161 | /* mute flag on (pause) */ | ||
162 | data[3] = 0x02; | ||
163 | } | ||
164 | iap_send_pkt(data, sizeof(data)); | ||
165 | } | ||
166 | |||
167 | void rmt_tuner_region(int region) | ||
168 | { | ||
169 | if (region != old_region) | ||
170 | { | ||
171 | unsigned char data[] = {0x07, 0x08, 0x00}; | ||
172 | if (region == 2) | ||
173 | { | ||
174 | data[2] = 0x02; /* japan band */ | ||
175 | } | ||
176 | else | ||
177 | { | ||
178 | data[2] = 0x01; /* us eur band */ | ||
179 | } | ||
180 | iap_send_pkt(data, sizeof(data)); | ||
181 | sleep(HZ/100); | ||
182 | old_region = region; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | /* set stereo/mono, deemphasis, delta freq... */ | ||
187 | void rmt_tuner_set_param(unsigned char tuner_param) | ||
188 | { | ||
189 | if(tuner_param != old_tuner_param) | ||
190 | { | ||
191 | unsigned char data[] = {0x07, 0x0E, 0x00}; | ||
192 | |||
193 | data[2] = tuner_param; | ||
194 | iap_send_pkt(data, sizeof(data)); | ||
195 | old_tuner_param = tuner_param; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | void set_deltafreq(int delta) | ||
200 | { | ||
201 | tuner_param &= 0xFC; | ||
202 | switch (delta) | ||
203 | { | ||
204 | case 1: | ||
205 | { | ||
206 | /* 100KHz */ | ||
207 | tuner_param |= 0x01; | ||
208 | break; | ||
209 | } | ||
210 | case 2: | ||
211 | { | ||
212 | /* 50KHz */ | ||
213 | tuner_param |= 0x02; | ||
214 | break; | ||
215 | } | ||
216 | |||
217 | default: | ||
218 | { | ||
219 | /* 200KHz */ | ||
220 | tuner_param |= 0x00; | ||
221 | break; | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | |||
226 | void set_deemphasis(int deemphasis) | ||
227 | { | ||
228 | tuner_param &= 0xBF; | ||
229 | switch (deemphasis) | ||
230 | { | ||
231 | case 1: | ||
232 | { | ||
233 | tuner_param |= 0x40; | ||
234 | break; | ||
235 | } | ||
236 | default: | ||
237 | { | ||
238 | tuner_param |= 0x00; | ||
239 | break; | ||
240 | } | ||
241 | } | ||
242 | } | ||
243 | |||
244 | void set_mono(int value) | ||
245 | { | ||
246 | tuner_param &= 0xEF; | ||
247 | |||
248 | if (value != mono_mode) | ||
249 | { | ||
250 | tuner_param |= 0x10; | ||
251 | rmt_tuner_set_param(tuner_param); | ||
252 | sleep(HZ/100); | ||
253 | mono_mode = value; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | bool reply_timeout(void) | ||
258 | { | ||
259 | int timeout = 0; | ||
260 | |||
261 | sleep(HZ/50); | ||
262 | do | ||
263 | { | ||
264 | iap_handlepkt(); | ||
265 | sleep(HZ/50); | ||
266 | timeout++; | ||
267 | } | ||
268 | while((ipod_rmt_tuner_get(RADIO_TUNED) == 0) && (timeout < TIMEOUT_VALUE)); | ||
269 | |||
270 | if (timeout >= TIMEOUT_VALUE) | ||
271 | return true; | ||
272 | else return false; | ||
273 | } | ||
274 | |||
275 | void rmt_tuner_rds_data(void) | ||
276 | { | ||
277 | if (serbuf[3] == 0x1E) | ||
278 | { | ||
279 | strlcpy(rds_radioname,serbuf+5,8); | ||
280 | } | ||
281 | else if(serbuf[3] == 0x04) | ||
282 | { | ||
283 | strlcpy(rds_radioinfo,serbuf+5,(serbuf[0]-4)); | ||
284 | } | ||
285 | rds_event = 1; | ||
286 | } | ||
287 | |||
288 | /* tuner abstraction layer: set something to the tuner */ | ||
289 | int ipod_rmt_tuner_set(int setting, int value) | ||
290 | { | ||
291 | switch(setting) | ||
292 | { | ||
293 | case RADIO_SLEEP: | ||
294 | { | ||
295 | rmt_tuner_sleep(value); | ||
296 | sleep(HZ/2); | ||
297 | break; | ||
298 | } | ||
299 | |||
300 | case RADIO_FREQUENCY: | ||
301 | { | ||
302 | rmt_tuner_set_freq(value); | ||
303 | if (reply_timeout() == true) | ||
304 | return 0; | ||
305 | break; | ||
306 | } | ||
307 | |||
308 | case RADIO_SCAN_FREQUENCY: | ||
309 | { | ||
310 | const struct fm_region_data * const fmr = | ||
311 | &fm_region_data[global_settings.fm_region]; | ||
312 | |||
313 | /* case: scan for presets, back to beginning of the band */ | ||
314 | if ((radio_tuned == 1) && (value == fmr->freq_min)) | ||
315 | { | ||
316 | tuner_set(RADIO_FREQUENCY,value); | ||
317 | } | ||
318 | |||
319 | /* scan through frequencies */ | ||
320 | if (radio_tuned == 1) | ||
321 | { | ||
322 | /* scan down */ | ||
323 | if(value < tuner_frequency) | ||
324 | rmt_tuner_scan(-1); | ||
325 | /* scan up */ | ||
326 | else | ||
327 | rmt_tuner_scan(1); | ||
328 | |||
329 | if (reply_timeout() == true) | ||
330 | return 0; | ||
331 | radio_tuned = 0; | ||
332 | } | ||
333 | |||
334 | if (tuner_frequency == value) | ||
335 | { | ||
336 | radio_tuned = 1; | ||
337 | return 1; | ||
338 | } | ||
339 | else | ||
340 | { | ||
341 | radio_tuned = 0; | ||
342 | return 0; | ||
343 | } | ||
344 | } | ||
345 | |||
346 | case RADIO_MUTE: | ||
347 | { | ||
348 | /* mute flag sent to accessory */ | ||
349 | /* rmt_tuner_mute(value); */ | ||
350 | break; | ||
351 | } | ||
352 | |||
353 | case RADIO_REGION: | ||
354 | { | ||
355 | const struct rmt_tuner_region_data *rd = | ||
356 | &rmt_tuner_region_data[value]; | ||
357 | |||
358 | rmt_tuner_region(rd->band); | ||
359 | set_deltafreq(rd->spacing); | ||
360 | set_deemphasis(rd->deemphasis); | ||
361 | rmt_tuner_set_param(tuner_param); | ||
362 | break; | ||
363 | } | ||
364 | |||
365 | case RADIO_FORCE_MONO: | ||
366 | { | ||
367 | set_mono(value); | ||
368 | break; | ||
369 | } | ||
370 | |||
371 | default: | ||
372 | return -1; | ||
373 | } | ||
374 | return 1; | ||
375 | } | ||
376 | |||
377 | /* tuner abstraction layer: read something from the tuner */ | ||
378 | int ipod_rmt_tuner_get(int setting) | ||
379 | { | ||
380 | int val = -1; /* default for unsupported query */ | ||
381 | |||
382 | switch(setting) | ||
383 | { | ||
384 | case RADIO_PRESENT: | ||
385 | val = radio_present; | ||
386 | if (val) | ||
387 | { | ||
388 | /* if accessory disconnected */ | ||
389 | if(adc_read(ADC_ACCESSORY) >= 10) | ||
390 | { | ||
391 | radio_present = 0; | ||
392 | val = 0; | ||
393 | } | ||
394 | } | ||
395 | break; | ||
396 | |||
397 | /* radio tuned: yes no */ | ||
398 | case RADIO_TUNED: | ||
399 | val = 0; | ||
400 | if (radio_tuned == 1) | ||
401 | val = 1; | ||
402 | break; | ||
403 | |||
404 | /* radio is always stereo */ | ||
405 | /* we can't know when it's in mono mode, depending of signal quality */ | ||
406 | /* except if it is forced in mono mode */ | ||
407 | case RADIO_STEREO: | ||
408 | val = true; | ||
409 | break; | ||
410 | |||
411 | case RADIO_EVENT: | ||
412 | if (rds_event) | ||
413 | { | ||
414 | val = 1; | ||
415 | rds_event = 0; | ||
416 | } | ||
417 | break; | ||
418 | } | ||
419 | return val; | ||
420 | } | ||
421 | |||
422 | char* ipod_get_rds_info(int setting) | ||
423 | { | ||
424 | char *text = NULL; | ||
425 | |||
426 | switch(setting) | ||
427 | { | ||
428 | case RADIO_RDS_NAME: | ||
429 | text = rds_radioname; | ||
430 | break; | ||
431 | |||
432 | case RADIO_RDS_TEXT: | ||
433 | text = rds_radioinfo; | ||
434 | break; | ||
435 | } | ||
436 | return text; | ||
437 | } | ||
438 | |||
439 | bool tuner_power(bool status) | ||
440 | { | ||
441 | bool oldstatus = powered; | ||
442 | powered = status; | ||
443 | return oldstatus; | ||
444 | } | ||