Imported Upstream version 3.2.2
[debian/gnuradio] / gnuradio-core / src / lib / io / microtune_4702.cc
1 /* -*- c++-*- */
2 /*
3  * Copyright 2001,2003,2004 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  *
7  * GNU Radio 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 3, or (at your option)
10  * any later version.
11  *
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #include "microtune_4702.h"
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include "i2c.h"
27
28 static const double FIRST_IF = 36.00e6;
29
30 // The tuner internally has 3 bands: VHF Low, VHF High & UHF.
31 // These are the recommened boundaries
32 static const double VHF_High_takeover = 174e6;
33 static const double UHF_takeover = 470e6;
34
35 static int PLL_I2C_ADDR     =   0x60;
36
37 static unsigned char
38 control_byte_1 (bool prescaler, int reference_divisor)
39 {
40   int c = 0x80;
41   //Note: Last two divider bits (bits 2 and 3 of this byte) determined later
42   if (prescaler)
43     c |= 0x10;
44
45   switch (reference_divisor){
46   case 2:
47     c |= 0x00;  break;
48   case 4:
49     c |= 0x01;  break;
50   case 8:
51     c |= 0x02;  break;
52   case 16:
53     c |= 0x03;  break;
54   case 32:
55     c |= 0x04;  break;
56   case 64:
57     c |= 0x05;  break;
58   case 128:
59     c |= 0x06;  break;
60   case 256:
61     c |= 0x07;  break;
62   case 24:
63     c |= 0x08;  break;
64   case 5:
65     c |= 0x09;  break;
66   case 10:
67     c |= 0x0A;  break;
68   case 20:
69     c |= 0x0B;  break;
70   case 40:
71     c |= 0x0C;  break;
72   case 80:
73     c |= 0x0D;  break;
74   case 160:
75     c |= 0x0E;  break;
76   case 320:
77     c |= 0x0F;  break;
78   default:
79     abort ();
80   }
81   return c;
82 }
83
84 static unsigned char
85 control_byte_2 (double target_freq)
86 {
87   int   c;
88
89   if (target_freq < VHF_High_takeover)  // VHF low
90     c = 0x8E;
91
92   else if (target_freq < UHF_takeover){ // VHF high
93     c = 0x05;
94     if (target_freq < 390e6)
95       c |= 0x40;
96     else
97       c |= 0x80;
98   }
99   else {                                // UHF
100     c = 0x03;
101     if (target_freq < 750e6)
102       c |= 0x80;
103     else
104       c |= 0xC0;
105   }
106
107   return c;
108 }
109
110
111 microtune_4702::microtune_4702 (i2c_sptr i2c, int i2c_addr)
112 {
113   d_i2c = i2c;
114   d_i2c_addr = i2c_addr;
115   d_reference_divider = 320;
116   d_prescaler  = false;
117 }
118
119 microtune_4702::~microtune_4702 ()
120 {
121   // nop
122 }
123
124 /*!
125  * \brief select RF frequency to be tuned to output frequency.
126  * \p target_freq is the requested frequency in Hz, \p actual_freq
127  * is set to the actual frequency tuned.  It takes about 100 ms
128  * for the PLL to settle.
129  *
130  * \returns true iff sucessful.
131  */
132 bool
133 microtune_4702::set_RF_freq (double target_freq, double *p_actual_freq)
134 {
135   unsigned char buf[4];
136
137   double target_f_osc = target_freq + FIRST_IF;
138
139   double f_ref = 4e6 / d_reference_divider;
140
141   //int divisor = (int) ((target_f_osc + (f_ref * 4)) / (f_ref * 8));
142
143   long int divisor = (long int) (target_f_osc / f_ref);
144   double actual_freq = (f_ref * divisor) - FIRST_IF;
145   if (p_actual_freq != 0)
146     *p_actual_freq = actual_freq;
147
148   if ((divisor & ~0x1ffff) != 0)        // >17 bit divisor
149     return false;
150
151   buf[0] = ((divisor & 0x07f00) >> 8) & 0xff;   // DB1
152   buf[1] = divisor & 0xff;              // DB2
153   buf[2] = control_byte_1 (d_prescaler, d_reference_divider);
154   buf[2] = buf[2] | (((divisor & 0x18000) >> 10) & 0xff);
155   buf[3] = control_byte_2 (target_freq);
156
157   printf ("%x\n", PLL_I2C_ADDR);
158 //#if 0
159   printf ("set_RF_freq: target: %g MHz actual: %g MHz %02x %02x %02x %02x\n",
160           target_freq/1e6, actual_freq/1e6, buf[0], buf[1], buf[2], buf[3]);
161 //#endif
162
163   return d_i2c->write (d_i2c_addr, buf, sizeof (buf));
164 }
165
166 /*!
167  * \returns true iff PLL is locked
168  */
169 bool 
170 microtune_4702::pll_locked_p ()
171 {
172   // FIXME
173   return true;
174 }
175
176 /*!
177  * \returns the output frequency of the tuner in Hz.
178  */
179 double
180 microtune_4702::get_output_freq ()
181 {
182   return FIRST_IF;
183 }