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