fb778f72efdca64b8632852885decba306d839f3
[goodfet] / shellcode / chipcon / cc1110 / specan.c
1 /*
2  * Copyright 2010 Michael Ossmann
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2, or (at your option)
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; see the file COPYING.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include <cc1110.h>
21 #include "ioCCxx10_bitdef.h"
22 #include "specan.h"
23
24 /* globals */
25 __xdata channel_info chan_table[NUM_CHANNELS];
26 u16 center_freq;
27 u16 user_freq;
28 u8 band;
29 u8 width;
30 __bit max_hold;
31 __bit height;
32 __bit sleepy;
33 u8 vscroll;
34 u8 min_chan;
35 u8 max_chan;
36
37
38 void sleepMillis(int ms) {
39   int j;
40   //k=1000;
41   //while(--k>0)
42   while (--ms > 0) { 
43     for (j=0; j<1200;j++); // about 1 millisecond
44   };
45 }
46
47
48 void radio_setup() {
49         /* IF of 457.031 kHz */
50         FSCTRL1 = 0x12;
51         FSCTRL0 = 0x00;
52
53         /* disable 3 highest DVGA settings */
54         AGCCTRL2 |= AGCCTRL2_MAX_DVGA_GAIN;
55
56         /* frequency synthesizer calibration */
57         FSCAL3 = 0xEA;
58         FSCAL2 = 0x2A;
59         FSCAL1 = 0x00;
60         FSCAL0 = 0x1F;
61
62         /* "various test settings" */
63         TEST2 = 0x88;
64         TEST1 = 0x31;
65         TEST0 = 0x09;
66
67         /* no automatic frequency calibration */
68         MCSM0 = 0;
69 }
70
71 /* set the channel bandwidth */
72 void set_filter() {
73         /* channel spacing should fit within 80% of channel filter bandwidth */
74         switch (width) {
75         case NARROW:
76                 MDMCFG4 = 0xEC; /* 67.708333 kHz */
77                 break;
78         case ULTRAWIDE:
79                 MDMCFG4 = 0x0C; /* 812.5 kHz */
80                 break;
81         default:
82                 MDMCFG4 = 0x6C; /* 270.833333 kHz */
83                 break;
84         }
85 }
86
87 /* set the radio frequency in Hz */
88 void set_radio_freq(u32 freq) {
89         /* the frequency setting is in units of 396.728515625 Hz */
90         u32 setting = (u32) (freq * .0025206154);
91         FREQ2 = (setting >> 16) & 0xff;
92         FREQ1 = (setting >> 8) & 0xff;
93         FREQ0 = setting & 0xff;
94
95         if ((band == BAND_300 && freq < MID_300) ||
96                         (band == BAND_400 && freq < MID_400) ||
97                         (band == BAND_900 && freq < MID_900))
98                 /* select low VCO */
99                 FSCAL2 = 0x0A;
100         else
101                 /* select high VCO */
102                 FSCAL2 = 0x2A;
103 }
104
105 /* freq in Hz */
106 void calibrate_freq(u32 freq, u8 ch) {
107                 set_radio_freq(freq);
108
109                 RFST = RFST_SCAL;
110                 RFST = RFST_SRX;
111
112                 /* wait for calibration */
113                 sleepMillis(2);
114
115                 /* store frequency/calibration settings */
116                 chan_table[ch].freq2 = FREQ2;
117                 chan_table[ch].freq1 = FREQ1;
118                 chan_table[ch].freq0 = FREQ0;
119                 chan_table[ch].fscal3 = FSCAL3;
120                 chan_table[ch].fscal2 = FSCAL2;
121                 chan_table[ch].fscal1 = FSCAL1;
122
123                 /* get initial RSSI measurement */
124                 chan_table[ch].ss = (RSSI ^ 0x80);
125                 chan_table[ch].max = 0;
126
127                 RFST = RFST_SIDLE;
128 }
129
130 #define UPPER(a, b, c)  ((((a) - (b) + ((c) / 2)) / (c)) * (c))
131 #define LOWER(a, b, c)  ((((a) + (b)) / (c)) * (c))
132
133 /* set the center frequency in MHz */
134 u16 set_center_freq(u16 freq) {
135         u8 new_band;
136         u32 spacing;
137         u32 hz;
138         u32 min_hz;
139         u32 max_hz;
140         u8 margin;
141         u8 step;
142         u16 upper_limit;
143         u16 lower_limit;
144         u16 next_up;
145         u16 next_down;
146         u8 next_band_up;
147         u8 next_band_down;
148
149         switch (width) {
150         case NARROW:
151                 margin = NARROW_MARGIN;
152                 step = NARROW_STEP;
153                 spacing = NARROW_SPACING;
154                 break;
155         case ULTRAWIDE:
156                 margin = ULTRAWIDE_MARGIN;
157                 step = ULTRAWIDE_STEP;
158                 spacing = ULTRAWIDE_SPACING;
159
160                 /* nearest 20 MHz step */
161                 freq = ((freq + 10) / 20) * 20;
162                 break;
163         default:
164                 margin = WIDE_MARGIN;
165                 step = WIDE_STEP;
166                 spacing = WIDE_SPACING;
167
168                 /* nearest 5 MHz step */
169                 freq = ((freq + 2) / 5) * 5;
170                 break;
171         }
172
173         /* handle cases near edges of bands */
174         if (freq > EDGE_900) {
175                 new_band = BAND_900;
176                 upper_limit = UPPER(MAX_900, margin, step);
177                 lower_limit = LOWER(MIN_900, margin, step);
178                 next_up = LOWER(MIN_300, margin, step);
179                 next_down = UPPER(MAX_400, margin, step);
180                 next_band_up = BAND_300;
181                 next_band_down = BAND_400;
182         } else if (freq > EDGE_400) {
183                 new_band = BAND_400;
184                 upper_limit = UPPER(MAX_400, margin, step);
185                 lower_limit = LOWER(MIN_400, margin, step);
186                 next_up = LOWER(MIN_900, margin, step);
187                 next_down = UPPER(MAX_300, margin, step);
188                 next_band_up = BAND_900;
189                 next_band_down = BAND_300;
190         } else {
191                 new_band = BAND_300;
192                 upper_limit = UPPER(MAX_300, margin, step);
193                 lower_limit = LOWER(MIN_300, margin, step);
194                 next_up = LOWER(MIN_400, margin, step);
195                 next_down = UPPER(MAX_900, margin, step);
196                 next_band_up = BAND_400;
197                 next_band_down = BAND_900;
198         }
199
200         if (freq > upper_limit) {
201                 freq = upper_limit;
202                 if (new_band == band) {
203                         new_band = next_band_up;
204                         freq = next_up;
205                 }
206         } else if (freq < lower_limit) {
207                 freq = lower_limit;
208                 if (new_band == band) {
209                         new_band = next_band_down;
210                         freq = next_down;
211                 }
212         }
213
214         band = new_band;
215
216         /* doing everything in Hz from here on */
217         switch (band) {
218         case BAND_400:
219                 min_hz = MIN_400 * 1000000;
220                 max_hz = MAX_400 * 1000000;
221                 break;
222         case BAND_300:
223                 min_hz = MIN_300 * 1000000;
224                 max_hz = MAX_300 * 1000000;
225                 break;
226         default:
227                 min_hz = MIN_900 * 1000000;
228                 max_hz = MAX_900 * 1000000;
229                 break;
230         }
231
232         /* calibrate upper channels */
233         hz = freq * 1000000;
234         max_chan = NUM_CHANNELS / 2;
235         while (hz <= max_hz && max_chan < NUM_CHANNELS) {
236                 calibrate_freq(hz, max_chan);
237                 hz += spacing;
238                 max_chan++;
239         }
240
241         /* calibrate lower channels */
242         hz = freq * 1000000 - spacing;
243         min_chan = NUM_CHANNELS / 2;
244         while (hz >= min_hz && min_chan > 0) {
245                 min_chan--;
246                 calibrate_freq(hz, min_chan);
247                 hz -= spacing;
248         }
249
250         center_freq = freq;
251         max_hold = 0;
252
253         return freq;
254 }
255
256 /* tune the radio using stored calibration */
257 void tune(u8 ch) {
258         FREQ2 = chan_table[ch].freq2;
259         FREQ1 = chan_table[ch].freq1;
260         FREQ0 = chan_table[ch].freq0;
261
262         FSCAL3 = chan_table[ch].fscal3;
263         FSCAL2 = chan_table[ch].fscal2;
264         FSCAL1 = chan_table[ch].fscal1;
265 }
266
267 void set_width(u8 w) {
268         width = w;
269         set_filter();
270         set_center_freq(center_freq);
271 }
272
273 void poll_keyboard() {
274   /*
275         u8 vstep;
276         u8 hstep;
277
278         vstep = (height == TALL) ? TALL_STEP : SHORT_STEP;
279
280         switch (width) {
281         case NARROW:
282                 hstep = NARROW_STEP;
283                 break;
284         case ULTRAWIDE:
285                 hstep = ULTRAWIDE_STEP;
286                 break;
287         default:
288                 hstep = WIDE_STEP;
289                 break;
290         }
291
292         switch (getkey()) {
293         case 'W':
294                 set_width(WIDE);
295                 break;
296         case 'N':
297                 set_width(NARROW);
298                 break;
299         case 'U':
300                 set_width(ULTRAWIDE);
301                 break;
302         case KMNU:
303                 switch (width) {
304                 case WIDE:
305                         set_width(NARROW);
306                         break;
307                 case NARROW:
308                         set_width(ULTRAWIDE);
309                         break;
310                 default:
311                         set_width(WIDE);
312                         break;
313                 }
314                 break;
315         case 'T':
316                 height = TALL;
317                 break;
318         case 'S':
319                 height = SHORT;
320                 break;
321         case KBYE:
322                 height = !height;
323                 break;
324         case '>':
325                 user_freq += hstep;
326                 break;
327         case '<':
328                 user_freq -= hstep;
329                 break;
330         case '^':
331         case 'Q':
332                 vscroll = MIN(vscroll + vstep, MAX_VSCROLL);
333                 break;
334         case KDWN:
335         case 'A':
336                 vscroll = MAX(vscroll - vstep, MIN_VSCROLL);
337                 break;
338         case 'M':
339                 max_hold = !max_hold;
340                 break;
341         case KPWR:
342                 sleepy = 1;
343                 break;
344         default:
345                 break;
346         }
347   */
348 }
349
350 void main(void) {
351         u8 ch;
352         u16 i;
353
354 reset:
355         center_freq = DEFAULT_FREQ;
356         user_freq = DEFAULT_FREQ;
357         band = BAND_900;
358         width = WIDE;
359         max_hold = 0;
360         height = 0;
361         sleepy = 0;
362         vscroll = 0;
363         min_chan = 0;
364         max_chan = NUM_CHANNELS - 1;
365         
366         //presumed to be done by GoodFET.
367         //xtalClock(); 
368         //setIOPorts();
369         radio_setup();
370         set_width(WIDE);
371
372         while (1) {
373                 for (ch = min_chan; ch < max_chan; ch++) {
374                         /* tune radio and start RX */
375                         tune(ch);
376                         RFST = RFST_SRX;
377
378                         /* delay while waiting for RSSI measurement */
379                         sleepMillis(10);
380                         
381                         /* measurement needs a bit more time in narrow mode */
382                         if (width == NARROW)
383                                 for (i = 350; i-- ;);
384
385                         /* read RSSI */
386                         chan_table[ch].ss = (RSSI ^ 0x80);
387                         if (max_hold)
388                                 chan_table[ch].max = MAX(chan_table[ch].ss,
389                                                 chan_table[ch].max);
390                         else
391                                 chan_table[ch].max = 0;
392
393                         /* end RX */
394                         RFST = RFST_SIDLE;
395                 }
396
397                 poll_keyboard();
398
399
400                 if (user_freq != center_freq)
401                         user_freq = set_center_freq(user_freq);
402         }
403 }