OSDN Git Service

[AKC6955] Add set/get freq-resolution of FM-Tuning.
[openi2cradio/OpenI2CRadio.git] / akc6955.c
1 /*
2  * OpenI2CRADIO
3  * RADIO CHIP AKC6955 Handler
4  * Copyright (C) 2013-06-10 K.Ohta <whatisthis.sowhat ai gmail.com>
5  * License: GPL2+LE
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2,
10  *  or (at your option) any later version.
11  *  This library / program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  *  See the GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this library; see the file COPYING. If not, write to the
18  *  Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
19  *  MA 02110-1301, USA.
20  *
21  *  As a special exception, if you link this(includeed from sdcc) library
22  *  with other files, some of which are compiled with SDCC,
23  *  to produce an executable, this library does not by itself cause
24  *  the resulting executable to be covered by the GNU General Public License.
25  *  This exception does not however invalidate any other reasons why
26  *  the executable file might be covered by the GNU General Public License.
27  */
28
29 #include <stdarg.h>
30 #include <stdio.h>
31 #ifdef __SDCC
32 #include <delay.h>
33 #else
34 #include <xc.h>
35 #endif
36 #include <string.h>
37 #include "akc6955.h"
38 #include "i2c_io.h"
39 #include "idle.h"
40 #include "power.h"
41 #include "commondef.h"
42 #include "menu.h"
43
44
45 void akc6955_chg_fm(unsigned char f, unsigned int freq)
46 {
47     __bitops_t b;
48     b.byte = akc6955_readcmd(AKC6955_POWER);
49     b.b6 = 0;
50     if(f != 0){
51         b.b6 = 1;
52         akc6955_set_fmband(setup.fmband);
53         akc6955_writecmd(AKC6955_POWER, b.byte);
54         akc6955_set_freq(freq);
55         return;
56     }
57     akc6955_writecmd(AKC6955_POWER, b.byte);
58     akc6955_set_amband(setup.amband);
59     akc6955_set_freq(freq);
60
61 }
62
63 unsigned char akc6955_get_fm(void)
64 {
65     __bitops_t b;
66     b.byte = akc6955_readcmd(AKC6955_POWER);
67     if(b.b6){
68         return 0xff;
69     }
70     return 0;
71 }
72
73
74 void akc6955_set_amband(unsigned char band)
75 {
76     unsigned char b;
77     unsigned char c;
78
79     c = RFAMP_SW;
80     if((band < AKC6955_BAND_SW1) || (band == AKC6955_BAND_MW4)) {
81         c = RFAMP_MWLW;
82     }
83     rfamp_power(c);
84     b = akc6955_readcmd(AKC6955_BAND);
85     b &= 0x07; // extract FM
86     b = b | ((band & 0x1f) << 3);
87     akc6955_writecmd(AKC6955_BAND, b);
88     akc6955_do_tune();
89 }
90
91 void akc6955_set_fmband(unsigned char band)
92 {
93     unsigned char b;
94     rfamp_power(RFAMP_FM);
95     b = akc6955_readcmd(AKC6955_BAND);
96     b &= 0xf8; // extract AM
97     b = b | (band & 0x07);
98     akc6955_writecmd(AKC6955_BAND, b);
99     akc6955_do_tune();
100 }
101
102 unsigned char akc6955_get_band(void)
103 {
104     return akc6955_readcmd(AKC6955_BAND);
105 }
106
107
108 void akc6955_set_power(unsigned char on)
109 {
110     __bitops_t b;
111     b.byte = akc6955_readcmd(AKC6955_POWER);
112     b.b7 = 0;
113     if(on != 0){
114         b.b7 = 1;
115     }
116     akc6955_writecmd(AKC6955_POWER, b.byte);
117 }
118
119 void akc6955_do_tune(void)
120 {
121     __bitops_t b;
122     b.byte = akc6955_readcmd(AKC6955_POWER);
123     b.b5 = 0; // Tun = '0'
124     b.b4 = 0; // Force abort scan.
125     akc6955_writecmd(AKC6955_POWER, b.byte);
126     idle_time_ms(1);
127     // Need sleep?-> Need! this sequence re                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 fer from reference code.
128     b.b5= 1; // Tun = '1'
129     akc6955_writecmd(AKC6955_POWER, b.byte);
130     idle_time_ms(1);
131     b.b5 = 0;
132     akc6955_writecmd(AKC6955_POWER, b.byte);
133     idle_time_ms(8);
134 }
135
136 unsigned char akc6955_tune(void)
137 {
138     __bitops_t b;
139     b.byte = akc6955_readcmd(AKC6955_RCH_HI);
140     if(b.b5) {
141         return 0xff;
142     }
143     return 0;
144 }
145
146
147 void akc6955_mode3k(unsigned char flag)
148 {
149     __bitops_t b;
150     b.byte = akc6955_readcmd(AKC6955_CH_LO);
151     akc6955_writecmd(AKC6955_CH_LO, b.byte);
152
153     b.byte = akc6955_readcmd(AKC6955_CH_HI);
154     b.b5 = 0;
155     if(flag != 0){
156         b.b5 = 1;
157     }
158     akc6955_writecmd(AKC6955_CH_HI, b.byte);
159     akc6955_do_tune();
160 }
161
162 void akc6955_set_tune(unsigned char mode_3k, unsigned int ch)
163 {
164     unsigned char band;
165     __bitops_t f;
166     __bitops_t b;
167     unsigned int i = ch;
168     unsigned char comp;
169
170     do { // Wait for before completed
171         comp = akc6955_chk_donescan();
172         idle_time_35ms();
173     } while(comp == 0x00);
174     f.byte = akc6955_readcmd(AKC6955_POWER);
175     band = 0;
176     if(!f.b6){
177         akc6955_get_amband(band);
178     }
179
180     if(band == AKC6955_BAND_MW2){
181         // BAND=AM && MW2
182         i = ch / 3; // On MW2, Channnel must be multiple of 3.
183         i = i * 3; // i = (i/3) * 3
184     }
185     if(i > 0x1fff) i = 0x1fff;
186     //i = ch & 0x1fff;
187
188     b.byte = i & 0xff;
189     akc6955_writecmd(AKC6955_CH_LO, b.byte);
190
191     b.byte = i >> 8;
192     b.b6 = 1;
193     if(mode_3k != 0){
194         b.b5 = 1; // Mode 3K ON
195     }
196     akc6955_writecmd(AKC6955_CH_HI, b.byte);
197
198     akc6955_do_tune();
199 }
200
201 void akc6955_do_scan(unsigned char up)
202 {
203     __bitops_t b;
204
205     //20130823 Need wait for scan/tune completed w/o SDCC 3.3.x.
206 #ifndef __SDCC
207     while(akc6955_chk_donescan() == 0)
208     {
209         idle_time_ms(5);
210     }
211 #endif
212     b.byte = akc6955_readcmd(AKC6955_POWER);
213     b.b3 = 0;
214     b.b4 = 0;
215 // 20130823 : Is this collect?
216 #ifdef __SDCC
217      b.b5 = 0;
218     akc6955_writecmd(AKC6955_POWER, b.byte);
219     idle_time_ms(35);
220 #endif
221
222     b.b5 = 1; // Tune 0->1.
223     akc6955_writecmd(AKC6955_POWER, b.byte);
224     idle_time_ms(35);
225
226     b.b4 = 1;
227     if(up != 0) {
228         b.b3= 1;
229     }
230     akc6955_writecmd(AKC6955_POWER, b.byte); // Raise seek bit to '1'.
231     idle_time_ms(35);
232 }
233
234 void akc6955_abort_scan(void)
235 {
236     unsigned char b;
237     b = akc6955_readcmd(AKC6955_POWER);
238     b &= 0xef;
239     akc6955_writecmd(AKC6955_POWER, b); // Falldown seek bit to '0'.
240 }
241
242 void akc6955_set_scanrate_fm(unsigned char rate)
243 {
244     unsigned char c;
245     c = akc6955_readcmd(AKC6955_SPACE);
246     c = (c & 0xcf) | ((rate & 0x03) << 4);
247     akc6955_writecmd(AKC6955_SPACE, c);
248 }
249
250 unsigned char akc6955_get_scanrate_fm(void)
251 {
252     unsigned char c;
253     c = akc6955_readcmd(AKC6955_SPACE);
254     c = (c & 0x30) >> 4;
255    return c;
256 }
257
258 unsigned char akc6955_chk_donescan(void)
259 {
260     __bitops_t b;
261     b.byte = akc6955_readcmd(AKC6955_RCH_HI);
262     if(b.b6){
263         return 0xff;
264     }
265     return 0;
266 }
267
268 unsigned int akc6955_get_channel(void)
269 {
270     unsigned char h, l;
271     unsigned int u;
272     l = akc6955_readcmd(AKC6955_RCH_LO) ;
273     h = akc6955_readcmd(AKC6955_RCH_HI) & 0x1f;
274     u = (h << 8) | l;
275     return u;
276 }
277
278 /*
279  * Get AM/FM Frequency: ret = KHz at AM, 10KHz @FM.
280  */
281 unsigned int akc6955_get_freq(void)
282 {
283     __bitops_t f, b;
284     unsigned int i;
285     unsigned int freq;
286     unsigned char band;
287
288     f.byte = akc6955_readcmd(AKC6955_POWER);
289     i = akc6955_get_channel();
290     if(f.b6){ // 25KHz
291         freq = (i * 5) / 2 + 3000; // freq' = 25*i[KHz] = (25 / 10) *i [10KHz]
292     } else { // 5K
293        b.byte = akc6955_readcmd(AKC6955_CH_HI);
294        akc6955_get_amband(band);
295        freq = i * 5;
296        if((band == AKC6955_BAND_MW2) || (b.b5)){
297            freq = i * 3;
298        }
299     }
300     return freq;
301 }
302
303 void akc6955_set_freq(unsigned int freq)
304 {
305     unsigned int ch;
306     __bitops_t f;
307     __bitops_t mode3k;
308     unsigned char band;
309     unsigned int start, stop;
310
311     f.byte = akc6955_readcmd(AKC6955_POWER);
312     if(f.b6) { // FM
313         akc6955_get_fmband(band);
314 //        band &= 7;
315         if(band == AKC6955_BAND_FMUSER){
316             start = setup.fm_usrbands[setup.fm_userbandnum].start * 32;
317             stop = setup.fm_usrbands[setup.fm_userbandnum].stop * 32;
318         } else {
319             start = fmbands[band].start;
320             stop = fmbands[band].end;
321         }
322         ch = freq - 3000;
323         ch = (ch << 2) / 10;
324     } else {
325         akc6955_get_amband(band);
326 //        if(band >= AKC6955_BAND_AMEND) band = AKC6955_BAND_AMEND - 1;
327         if(band == AKC6955_BAND_AMUSER){
328             start = setup.am_usrbands[setup.am_userbandnum].start * 32;
329             stop = setup.am_usrbands[setup.am_userbandnum].stop * 32;
330         } else {
331             start = ambands[band].start;
332             stop = ambands[band].end;
333         }
334         mode3k.byte = akc6955_readcmd(AKC6955_CNR_AM);
335         if(band == AKC6955_BAND_MW2) {
336             ch = (freq / 9) * 3; // See datasheet.
337         } else if(band == AKC6955_BAND_MW3) {
338             ch = freq / 5;
339         } else  if(mode3k.b7){
340             ch = freq / 3;
341         } else {
342             ch = freq / 5;
343         }
344     }
345     if(freq <  start) freq = start;
346     if(freq >= stop)   freq = stop - 1;
347     akc6955_set_tune(mode3k.b7, ch);
348 }
349
350 void akc6955_set_userband(unsigned char start, unsigned char stop, unsigned int ch, unsigned char mode3k)
351 {
352     __bitops_t f;
353
354     f.byte = akc6955_readcmd(AKC6955_POWER);
355     akc6955_writecmd(AKC6955_UCH_ST, start);
356     akc6955_writecmd(AKC6955_UCH_EN, stop);
357     if(f.b6){
358         akc6955_set_fmband(AKC6955_BAND_FMUSER);
359     } else {
360         akc6955_set_amband(AKC6955_BAND_AMUSER);
361     }
362     akc6955_set_tune(mode3k, ch);
363 }
364
365
366 unsigned char akc6955_get_cnr(void)
367 {
368     __bitops_t f;
369     __bitops_t b;
370     f.byte = akc6955_readcmd(AKC6955_POWER);
371     if(f.b6) { // FM
372         b.byte = akc6955_readcmd(AKC6955_CNR_FM);
373     } else { // AM
374         b.byte = akc6955_readcmd(AKC6955_CNR_AM);
375     }
376     b.b7 = 0;
377     return b.byte;
378 }
379
380 int akc6955_read_level(void)
381 {
382     __bitops_t f;
383     unsigned char rflevel, iflevel;
384     unsigned char b;
385     int rssi;
386     unsigned int freq;
387     int totallevel;
388     int level;
389
390     f.byte = akc6955_readcmd(AKC6955_POWER);
391     b =  akc6955_readcmd(AKC6955_PGALEVEL);
392     rflevel = (b & 0xe0) >> 5;
393     iflevel = (b & 0x1c) >> 2;
394     totallevel = rflevel + iflevel;
395
396     rssi = (int)(akc6955_readcmd(AKC6955_RSSI) & 0x7f);
397     // totallevel = rssi + 6*totallevel;
398     level = (int)(totallevel * 6 + rssi);
399     if(f.b6){
400         level = 103 - level; // totallevel * 6
401     } else {
402         freq = akc6955_get_freq();
403         if(freq > 2560) { // ASSUME SW
404             level = 103 - level;
405         } else { // ASSUME MW,LW
406             level = 123 - level;
407         }
408     }
409     return level;
410 }
411
412
413 // Get diff. unit = 100Hz.
414 int akc6955_get_diff(void)
415 {
416     __bitops_t diff;
417     __bitops_t f;
418     int n;
419
420     diff.byte = akc6955_readcmd(AKC6955_FDNUM);
421     if(diff.b7) {
422         diff.b7 = 0;
423         n = -((int) diff.byte);
424     } else {
425         diff.b7 = 0;
426         n = (int)diff.byte;
427     }
428
429     f.byte = akc6955_readcmd(AKC6955_POWER);
430     if(f.b6) { // FM
431         return n * 10;
432     }
433     return n; // 10n
434 }
435
436 void akc6955_up_freq(unsigned int step)
437 {
438     unsigned int freq;
439     __bitops_t mode3k;
440
441     freq = akc6955_get_channel();
442     freq += step;
443 //    mode3k.byte = akc6955_readcmd(AKC6955_CNR_AM);
444 //    akc6955_set_tune(mode3k.b7, freq);
445     akc6955_set_tune(setup.am_mode3k, freq);
446 }
447
448
449 void akc6955_down_freq(unsigned int step)
450 {
451     unsigned int freq;
452     __bitops_t mode3k;
453
454     freq = akc6955_get_channel();
455     if(freq <= step) return;
456     freq -= step;
457 //    mode3k.byte = akc6955_readcmd(AKC6955_CNR_AM);
458 //    akc6955_set_tune(mode3k.b7, freq);
459     akc6955_set_tune(setup.am_mode3k, freq);
460 }
461
462 void akc6955_setvolumemode(unsigned char flag)
463 {
464     __bitops_t c;
465     c.byte = akc6955_readcmd(AKC6955_ENABLE);
466     c.b3 = 0;
467     if(flag != 0x00){
468         c.b3 = 1;
469     }
470     akc6955_writecmd(AKC6955_ENABLE, c.byte);
471 }
472
473 unsigned char akc6955_getvolumemode(void)
474 {
475     __bitops_t c;
476     c.byte = akc6955_readcmd(AKC6955_ENABLE);
477     if(c.b3){
478         return 0xff;
479     }
480     return 0;
481 }
482
483 void akc6955_setvolume(unsigned char level)
484 {
485 //    unsigned char c;
486 //    c = akc6955_readcmd(AKC6955_VOLUME) & 0x03;
487     if(level > 63) level = 63;
488     akc6955_writecmd(AKC6955_VOLUME, ((akc6955_readcmd(AKC6955_VOLUME) & 0x03) | (level << 2)));
489 }
490
491 unsigned char akc6955_getvolume(void)
492 {
493     unsigned char c;
494     c = akc6955_readcmd(AKC6955_VOLUME) >> 2;
495     return c;
496 }
497
498 void akc6955_set_prevolume(unsigned char level)
499 {
500     unsigned char c;
501     c = akc6955_readcmd(AKC6955_PRE) & 0xf3;
502     c |= ((level & 0x03) << 2);
503     akc6955_writecmd(AKC6955_PRE, c);
504 }
505
506 unsigned char akc6955_get_prevolume(void)
507 {
508     unsigned char c;
509     c = akc6955_readcmd(AKC6955_PRE) & 0x0c;
510     c >>= 2;
511     return c;
512 }
513
514
515 void akc6955_setphase(unsigned char flag)
516 {
517     __bitops_t c;
518     c.byte = akc6955_readcmd(AKC6955_VOLUME);
519
520     c.b0 = 1;
521     if(flag == 0) {
522         c.b0 = 0; //
523     }
524     akc6955_writecmd(AKC6955_VOLUME, c.byte);
525 }
526
527 void akc6955_setline(unsigned char flag)
528 {
529     __bitops_t c;
530     c.byte = akc6955_readcmd(AKC6955_VOLUME);
531     c.b1 = 1;
532     if(flag == 0) {
533         c.b1 = 0;
534     }
535     akc6955_writecmd(AKC6955_VOLUME, c.byte);
536 }
537
538 void akc6955_set_lowboost(unsigned char flag)
539 {
540     __bitops_t c;
541     c.byte = akc6955_readcmd(AKC6955_STEREO);
542     c.b3 = 1;
543     if(flag == 0) {
544         c.b3 = 0;
545     }
546     akc6955_writecmd(AKC6955_STEREO, c.byte);
547 }
548
549 void akc6955_set_stereomode(unsigned char mode)
550 {
551     unsigned char c;
552     c = akc6955_readcmd(AKC6955_STEREO);
553     mode = (mode & 0x03) << 2;
554     c = (c & 0xf3) | mode;
555     akc6955_writecmd(AKC6955_STEREO, c);
556 }
557
558 unsigned char akc6955_get_stereo(void)
559 {
560     unsigned char c;
561     c = akc6955_readcmd(AKC6955_RCH_HI) & 0x80;
562     return c;
563 }
564
565 /*
566  * Get battery level.
567  * Unit = 0.01V
568  */
569
570 unsigned int akc6955_get_battery(void)
571 {
572     unsigned int batt;
573     unsigned char c;
574     c = akc6955_readcmd(AKC6955_VBAT) & 0x3f;
575     batt = 180 + c * 5;
576     return batt;
577 }
578
579 void akc6955_set_thresh_fmstereo(unsigned char a)
580 {
581     unsigned char b;
582     a = a & 0x03;
583     setup.threshold_fmstereo = a;
584     b = akc6955_readcmd(AKC6955_THRESH) & 0xfc;
585     akc6955_writecmd(AKC6955_THRESH, a | b);
586 }
587
588 void akc6955_set_thresh_width(unsigned char a)
589 {
590     unsigned char b;
591     a = a & 0x03;
592     setup.threshold_width = a;
593     a = a << 2; // << 2
594     b = akc6955_readcmd(AKC6955_THRESH) & 0xf3;;
595     akc6955_writecmd(AKC6955_THRESH, a | b);
596 }
597
598 void akc6955_set_thresh_amcnr(unsigned char a)
599 {
600     unsigned char b;
601     a = a & 0x03;
602     setup.threshold_amcnr = a;
603     a = a << 4; // << 4
604     b = akc6955_readcmd(AKC6955_THRESH) & 0xcf;
605     akc6955_writecmd(AKC6955_THRESH, a | b);
606 }
607
608 void akc6955_set_thresh_fmcnr(unsigned char a)
609 {
610     unsigned char b;
611     a = a & 0x03;
612     setup.threshold_fmcnr = a;
613     a = a << 6; // << 4
614     b = akc6955_readcmd(AKC6955_THRESH) & 0x3f;
615     akc6955_writecmd(AKC6955_THRESH, a | b);
616 }