OSDN Git Service

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