summaryrefslogtreecommitdiff
path: root/firmware/drivers/tuner/ipod_remote_tuner.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/tuner/ipod_remote_tuner.c')
-rw-r--r--firmware/drivers/tuner/ipod_remote_tuner.c444
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
33static bool powered = false;
34
35static unsigned char tuner_param = 0x00, old_tuner_param = 0xFF;
36/* temp var for tests to avoid looping execution in submenus settings*/
37int mono_mode = -1, old_region = -1;
38
39int radio_present = 0;
40int tuner_frequency = 0;
41int tuner_signal_power = 0;
42int radio_tuned = 0;
43int rds_event = 0;
44
45char rds_radioname[9];
46char rds_radioinfo[70]; /* do we need more? */
47
48union FRQ {
49 unsigned long int frequency_radio;
50 char data_frequency[4];
51}Frequency;
52
53void 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
67void 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
96void rmt_tuner_signal_power(unsigned char value)
97{
98 tuner_signal_power = (int)(value);
99}
100
101void 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
132void 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
155void 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
167void 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... */
187void 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
199void 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
226void 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
244void 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
257bool 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
275void 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 */
289int 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 */
378int 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
422char* 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
439bool tuner_power(bool status)
440{
441 bool oldstatus = powered;
442 powered = status;
443 return oldstatus;
444}