OSDN Git Service

6bba528e3ecb13c60e60578d8c54d3cd63699c54
[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 unsigned char akc6955_get_amband(void)
46 {
47    return akc6955_get_band() >> 3;
48 }
49
50 unsigned char akc6955_get_fmband(void)
51 {
52    return akc6955_get_band() & 0x07;
53 }
54
55 void akc6955_chg_fm(unsigned char f, unsigned int freq)
56 {
57     __bitops_t b;
58     b.byte = akc6955_readcmd(AKC6955_POWER);
59     b.b6 = 0;
60     if(f != 0){
61         b.b6 = 1;
62         akc6955_set_fmband(setup.fmband);
63         akc6955_writecmd(AKC6955_POWER, b.byte);
64         akc6955_set_freq(freq);
65         return;
66     }
67     akc6955_writecmd(AKC6955_POWER, b.byte);
68     akc6955_set_amband(setup.amband);
69     akc6955_set_freq(freq);
70
71 }
72
73 unsigned char akc6955_get_fm(void)
74 {
75     __bitops_t b;
76     b.byte = akc6955_readcmd(AKC6955_POWER);
77     if(b.b6){
78         return 0xff;
79     }
80     return 0;
81 }
82
83
84 void akc6955_set_amband(unsigned char band)
85 {
86     unsigned char b;
87     unsigned char c;
88
89     c = RFAMP_SW;
90     if((band < AKC6955_BAND_SW1) || (band == AKC6955_BAND_MW4)) {
91         c = RFAMP_MWLW;
92     }
93     rfamp_power(c);
94     b = akc6955_readcmd(AKC6955_BAND);
95     b &= 0x07; // extract FM
96     b = b | ((band & 0x1f) << 3);
97     akc6955_writecmd(AKC6955_BAND, b);
98     akc6955_do_tune();
99 }
100
101 void akc6955_set_fmband(unsigned char band)
102 {
103     unsigned char b;
104     rfamp_power(RFAMP_FM);
105     b = akc6955_readcmd(AKC6955_BAND);
106     b &= 0xf8; // extract AM
107     b = b | (band & 0x07);
108     akc6955_writecmd(AKC6955_BAND, b);
109     akc6955_do_tune();
110 }
111
112 unsigned char akc6955_get_band(void)
113 {
114     return akc6955_readcmd(AKC6955_BAND);
115 }
116
117
118 void akc6955_set_power(unsigned char on)
119 {
120     __bitops_t b;
121     b.byte = akc6955_readcmd(AKC6955_POWER);
122     b.b7 = 0;
123     if(on != 0){
124         b.b7 = 1;
125     }
126     akc6955_writecmd(AKC6955_POWER, b.byte);
127 }
128
129 void akc6955_do_tune(void)
130 {
131     __bitops_t b;
132     b.byte = akc6955_readcmd(AKC6955_POWER);
133     b.b5 = 0; // Tun = '0'
134     b.b4 = 0; // Force abort scan.
135     akc6955_writecmd(AKC6955_POWER, b.byte);
136     idle_time_ms(1);
137     // Need sleep?-> Need! this sequence re                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 fer from reference code.
138     b.b5= 1; // Tun = '1'
139     akc6955_writecmd(AKC6955_POWER, b.byte);
140     idle_time_ms(1);
141     b.b5 = 0;
142     akc6955_writecmd(AKC6955_POWER, b.byte);
143     idle_time_ms(8);
144 }
145
146 unsigned char akc6955_tune(void)
147 {
148     __bitops_t b;
149     b.byte = akc6955_readcmd(AKC6955_RCH_HI);
150     if(b.b5) {
151         return 0xff;
152     }
153     return 0;
154 }
155
156 unsigned char akc6955_get_mode3k(void)
157 {
158     __bitops_t c;
159     c.byte = akc6955_readcmd(AKC6955_CNR_AM);
160     if(c.b7) {
161         return 0xff;
162     }
163     return 0;
164 }
165
166
167 void akc6955_mode3k(unsigned char flag)
168 {
169     __bitops_t b;
170     b.byte = akc6955_readcmd(AKC6955_CH_LO);
171     akc6955_writecmd(AKC6955_CH_LO, b.byte);
172
173     b.byte = akc6955_readcmd(AKC6955_CH_HI);
174     b.b5 = 0;
175     if(flag != 0){
176         b.b5 = 1;
177     }
178     akc6955_writecmd(AKC6955_CH_HI, b.byte);
179     akc6955_do_tune();
180 }
181
182 void akc6955_set_tune(unsigned char mode_3k, unsigned int ch)
183 {
184     unsigned char band;
185     __bitops_t f;
186     __bitops_t b;
187     unsigned int i = ch;
188     unsigned char comp;
189     unsigned int start;
190     unsigned int stop;
191     unsigned int q;
192
193     do { // Wait for before completed
194         comp = akc6955_chk_donescan();
195         idle_time_35ms();
196     } while(comp == 0x00);
197    
198     f.byte = akc6955_readcmd(AKC6955_POWER);
199     if(!f.b6){ // AM
200        band = akc6955_get_amband(); 
201        if(band == AKC6955_BAND_MW2){
202           // BAND=AM && MW2
203           i = ch / 3; // On MW2, Channnel must be multiple of 3.
204           i = i * 3; // i = (i/3) * 3
205           mode_3k = 0xff;
206           q = 3;
207        } else if(mode_3k != 0) {
208           q = 3;
209         } else {
210           q = 5;
211         }
212        
213         if(band == AKC6955_BAND_AMUSER) {
214             start = setup.am_usrbands[setup.am_userbandnum].start * 32;
215             stop = setup.am_usrbands[setup.am_userbandnum].stop * 32;
216         } else {
217             start = ambands[band].start / q;
218             stop = ambands[band].end / q;
219         }
220     } else {
221        band = akc6955_get_fmband(); 
222         if(band == AKC6955_BAND_FMUSER) {
223             start = setup.fm_usrbands[setup.fm_userbandnum].start * 32;
224             stop = setup.fm_usrbands[setup.fm_userbandnum].stop * 32;
225         } else {
226             start = ((fmbands[band].start - 3000) * 4) / 10;
227             stop =  ((fmbands[band].end - 3000) * 4)  / 10;
228         }
229     }
230    
231     if(i > 0x1fff) i = 0x1fff;
232     if(i > stop) i = stop;
233     if(i < start) i = start;
234
235     b.byte = i & 0xff;
236     akc6955_writecmd(AKC6955_CH_LO, b.byte);
237
238     b.byte = i >> 8;
239     b.b6 = 1;
240     if((setup.fm == 0) && (mode_3k != 0)){
241         b.b5 = 1; // Mode 3K ON
242     } else {
243         b.b5 = 0;
244     }
245
246     akc6955_writecmd(AKC6955_CH_HI, b.byte);
247
248     akc6955_do_tune();
249 }
250
251 void akc6955_do_scan(unsigned char up)
252 {
253     __bitops_t b;
254
255     //20130823 Need wait for scan/tune completed w/o SDCC 3.3.x.
256 #ifndef __SDCC
257     while(akc6955_chk_donescan() == 0)
258     {
259         idle_time_ms(5);
260     }
261 #endif
262     b.byte = akc6955_readcmd(AKC6955_POWER);
263     b.b3 = 0;
264     b.b4 = 0;
265 // 20130823 : Is this collect?
266 #ifdef __SDCC
267      b.b5 = 0;
268     akc6955_writecmd(AKC6955_POWER, b.byte);
269     idle_time_ms(35);
270 #endif
271
272     b.b5 = 1; // Tune 0->1.
273     akc6955_writecmd(AKC6955_POWER, b.byte);
274     idle_time_ms(35);
275
276     b.b4 = 1;
277     if(up != 0) {
278         b.b3= 1;
279     }
280     akc6955_writecmd(AKC6955_POWER, b.byte); // Raise seek bit to '1'.
281     idle_time_ms(35);
282 }
283
284 void akc6955_abort_scan(void)
285 {
286     unsigned char b;
287     b = akc6955_readcmd(AKC6955_POWER);
288     b &= 0xef;
289     akc6955_writecmd(AKC6955_POWER, b); // Falldown seek bit to '0'.
290 }
291
292 void akc6955_set_scanrate_fm(unsigned char rate)
293 {
294     unsigned char c;
295     c = akc6955_readcmd(AKC6955_SPACE);
296     c = (c & 0xcf) | ((rate & 0x03) << 4);
297     akc6955_writecmd(AKC6955_SPACE, c);
298 }
299
300 unsigned char akc6955_get_scanrate_fm(void)
301 {
302     unsigned char c;
303     c = akc6955_readcmd(AKC6955_SPACE);
304     c = (c & 0x30) >> 4;
305    return c;
306 }
307
308 unsigned char akc6955_chk_donescan(void)
309 {
310     __bitops_t b;
311     b.byte = akc6955_readcmd(AKC6955_RCH_HI);
312     if(b.b6){
313         return 0xff;
314     }
315     return 0;
316 }
317
318 unsigned int akc6955_get_channel(void)
319 {
320     unsigned char h, l;
321     unsigned int u;
322     l = akc6955_readcmd(AKC6955_RCH_LO) ;
323     h = akc6955_readcmd(AKC6955_RCH_HI) & 0x1f;
324     u = (h << 8) | l;
325     return u;
326 }
327
328 /*
329  * Get AM/FM Frequency: ret = KHz at AM, 10KHz @FM.
330  */
331 unsigned int akc6955_get_freq(void)
332 {
333     __bitops_t f, b;
334     unsigned int i;
335     unsigned int freq;
336     unsigned char band;
337
338     f.byte = akc6955_readcmd(AKC6955_POWER);
339     i = akc6955_get_channel();
340     if(f.b6){ // 25KHz
341         freq = (i * 5) / 2 + 3000; // freq' = 25*i[KHz] = (25 / 10) *i [10KHz]
342     } else { // 5K
343        b.byte = akc6955_readcmd(AKC6955_CH_HI);
344        band = akc6955_get_amband();
345        freq = i * 5;
346        if((band == AKC6955_BAND_MW2) || (b.b5)){
347            freq = i * 3;
348        }
349     }
350     return freq;
351 }
352
353 void akc6955_set_freq(unsigned int freq)
354 {
355     unsigned int ch;
356     __bitops_t f;
357     __bitops_t mode3k;
358     unsigned char band;
359
360     f.byte = akc6955_readcmd(AKC6955_POWER);
361     if(f.b6) { // FM
362         band = akc6955_get_fmband();
363         ch = freq - 3000;
364         ch = (ch << 2) / 10;
365     } else {
366         band = akc6955_get_amband();
367         mode3k.byte = akc6955_readcmd(AKC6955_CNR_AM);
368         if(band == AKC6955_BAND_MW2) {
369             ch = (freq / 9) * 3; // See datasheet.
370         } else if(band == AKC6955_BAND_MW3) {
371             ch = freq / 5;
372         } else  if(mode3k.b7){
373             ch = freq / 3;
374         } else {
375             ch = freq / 5;
376         }
377     }
378     akc6955_set_tune(mode3k.b7, ch);
379 }
380
381 void akc6955_set_userband(unsigned char start, unsigned char stop, unsigned int ch, unsigned char mode3k)
382 {
383     __bitops_t f;
384
385     f.byte = akc6955_readcmd(AKC6955_POWER);
386     akc6955_writecmd(AKC6955_UCH_ST, start);
387     akc6955_writecmd(AKC6955_UCH_EN, stop);
388     if(f.b6){
389         akc6955_set_fmband(AKC6955_BAND_FMUSER);
390     } else {
391         akc6955_set_amband(AKC6955_BAND_AMUSER);
392     }
393     akc6955_set_tune(mode3k, ch);
394 }
395
396
397 unsigned char akc6955_get_cnr(void)
398 {
399     __bitops_t f;
400     __bitops_t b;
401     f.byte = akc6955_readcmd(AKC6955_POWER);
402     if(f.b6) { // FM
403         b.byte = akc6955_readcmd(AKC6955_CNR_FM);
404     } else { // AM
405         b.byte = akc6955_readcmd(AKC6955_CNR_AM);
406     }
407     b.b7 = 0;
408     return b.byte;
409 }
410
411 int akc6955_read_level(void)
412 {
413     __bitops_t f;
414     unsigned char rflevel, iflevel;
415     unsigned char b;
416     int rssi;
417     unsigned int freq;
418     int totallevel;
419     int level;
420
421     f.byte = akc6955_readcmd(AKC6955_POWER);
422     b =  akc6955_readcmd(AKC6955_PGALEVEL);
423     rflevel = (b & 0xe0) >> 5;
424     iflevel = (b & 0x1c) >> 2;
425     totallevel = rflevel + iflevel;
426
427     rssi = (int)(akc6955_readcmd(AKC6955_RSSI) & 0x7f);
428     // totallevel = rssi + 6*totallevel;
429     level = (int)(totallevel * 6 + rssi);
430     if(f.b6){
431         level = 103 - level; // totallevel * 6
432     } else {
433         freq = akc6955_get_freq();
434         if(freq > 2560) { // ASSUME SW
435             level = 103 - level;
436         } else { // ASSUME MW,LW
437             level = 123 - level;
438         }
439     }
440     return level;
441 }
442
443
444 // Get diff. unit = 100Hz.
445 int akc6955_get_diff(void)
446 {
447     __bitops_t diff;
448     __bitops_t f;
449     int n;
450
451     diff.byte = akc6955_readcmd(AKC6955_FDNUM);
452     if(diff.b7) {
453         diff.b7 = 0;
454         n = -((int) diff.byte);
455     } else {
456         diff.b7 = 0;
457         n = (int)diff.byte;
458     }
459
460     f.byte = akc6955_readcmd(AKC6955_POWER);
461     if(f.b6) { // FM
462         return n * 10;
463     }
464     return n; // 10n
465 }
466
467 void akc6955_up_freq(unsigned int step)
468 {
469     unsigned int freq;
470     __bitops_t mode3k;
471
472     freq = akc6955_get_channel();
473     freq += step;
474 //    mode3k.byte = akc6955_readcmd(AKC6955_CNR_AM);
475 //    akc6955_set_tune(mode3k.b7, freq);
476     akc6955_set_tune(setup.am_mode3k, freq);
477 }
478
479
480 void akc6955_down_freq(unsigned int step)
481 {
482     unsigned int freq;
483     __bitops_t mode3k;
484
485     freq = akc6955_get_channel();
486     if(freq <= step) return;
487     freq -= step;
488 //    mode3k.byte = akc6955_readcmd(AKC6955_CNR_AM);
489 //    akc6955_set_tune(mode3k.b7, freq);
490     akc6955_set_tune(setup.am_mode3k, freq);
491 }
492
493 void akc6955_setvolumemode(unsigned char flag)
494 {
495     __bitops_t c;
496     c.byte = akc6955_readcmd(AKC6955_ENABLE);
497     c.b3 = 0;
498     if(flag != 0x00){
499         c.b3 = 1;
500     }
501     akc6955_writecmd(AKC6955_ENABLE, c.byte);
502 }
503
504 unsigned char akc6955_getvolumemode(void)
505 {
506     __bitops_t c;
507     c.byte = akc6955_readcmd(AKC6955_ENABLE);
508     if(c.b3){
509         return 0xff;
510     }
511     return 0;
512 }
513
514 void akc6955_setvolume(unsigned char level)
515 {
516 //    unsigned char c;
517 //    c = akc6955_readcmd(AKC6955_VOLUME) & 0x03;
518     if(level > 63) level = 63;
519     akc6955_writecmd(AKC6955_VOLUME, ((akc6955_readcmd(AKC6955_VOLUME) & 0x03) | (level << 2)));
520 }
521
522 unsigned char akc6955_getvolume(void)
523 {
524     unsigned char c;
525     c = akc6955_readcmd(AKC6955_VOLUME) >> 2;
526     return c;
527 }
528
529 void akc6955_set_prevolume(unsigned char level)
530 {
531     unsigned char c;
532     c = akc6955_readcmd(AKC6955_PRE) & 0xf3;
533     c |= ((level & 0x03) << 2);
534     akc6955_writecmd(AKC6955_PRE, c);
535 }
536
537 unsigned char akc6955_get_prevolume(void)
538 {
539     unsigned char c;
540     c = akc6955_readcmd(AKC6955_PRE) & 0x0c;
541     c >>= 2;
542     return c;
543 }
544
545
546 void akc6955_setphase(unsigned char flag)
547 {
548     __bitops_t c;
549     c.byte = akc6955_readcmd(AKC6955_VOLUME);
550
551     c.b0 = 1;
552     if(flag == 0) {
553         c.b0 = 0; //
554     }
555     akc6955_writecmd(AKC6955_VOLUME, c.byte);
556 }
557
558 void akc6955_setline(unsigned char flag)
559 {
560     __bitops_t c;
561     c.byte = akc6955_readcmd(AKC6955_VOLUME);
562     c.b1 = 1;
563     if(flag == 0) {
564         c.b1 = 0;
565     }
566     akc6955_writecmd(AKC6955_VOLUME, c.byte);
567 }
568
569 void akc6955_set_lowboost(unsigned char flag)
570 {
571     __bitops_t c;
572     c.byte = akc6955_readcmd(AKC6955_STEREO);
573     c.b3 = 1;
574     if(flag == 0) {
575         c.b3 = 0;
576     }
577     akc6955_writecmd(AKC6955_STEREO, c.byte);
578 }
579
580 void akc6955_set_stereomode(unsigned char mode)
581 {
582     unsigned char c;
583     c = akc6955_readcmd(AKC6955_STEREO);
584     mode = (mode & 0x03) << 2;
585     c = (c & 0xf3) | mode;
586     akc6955_writecmd(AKC6955_STEREO, c);
587 }
588
589 unsigned char akc6955_get_stereo(void)
590 {
591     unsigned char c;
592     c = akc6955_readcmd(AKC6955_RCH_HI) & 0x80;
593     return c;
594 }
595
596 /*
597  * Get battery level.
598  * Unit = 0.01V
599  */
600
601 unsigned int akc6955_get_battery(void)
602 {
603     unsigned int batt;
604     unsigned char c;
605     c = akc6955_readcmd(AKC6955_VBAT) & 0x3f;
606     batt = 180 + c * 5;
607     return batt;
608 }
609
610 void akc6955_set_thresh_fmstereo(unsigned char a)
611 {
612     unsigned char b;
613     a = a & 0x03;
614     setup.threshold_fmstereo = a;
615     b = akc6955_readcmd(AKC6955_THRESH) & 0xfc;
616     akc6955_writecmd(AKC6955_THRESH, a | b);
617 }
618
619 void akc6955_set_thresh_width(unsigned char a)
620 {
621     unsigned char b;
622     a = a & 0x03;
623     setup.threshold_width = a;
624     a = a << 2; // << 2
625     b = akc6955_readcmd(AKC6955_THRESH) & 0xf3;;
626     akc6955_writecmd(AKC6955_THRESH, a | b);
627 }
628
629 void akc6955_set_thresh_amcnr(unsigned char a)
630 {
631     unsigned char b;
632     a = a & 0x03;
633     setup.threshold_amcnr = a;
634     a = a << 4; // << 4
635     b = akc6955_readcmd(AKC6955_THRESH) & 0xcf;
636     akc6955_writecmd(AKC6955_THRESH, a | b);
637 }
638
639 void akc6955_set_thresh_fmcnr(unsigned char a)
640 {
641     unsigned char b;
642     a = a & 0x03;
643     setup.threshold_fmcnr = a;
644     a = a << 6; // << 4
645     b = akc6955_readcmd(AKC6955_THRESH) & 0x3f;
646     akc6955_writecmd(AKC6955_THRESH, a | b);
647 }