Merge branch 'master' into aprs
[fw/altos] / src / drivers / ao_cc1120.c
1 /*
2  * Copyright © 2012 Keith Packard <keithp@keithp.com>
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; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include <ao.h>
19 #include <ao_cc1120.h>
20 #include <ao_exti.h>
21 #include <ao_fec.h>
22 #include <ao_packet.h>
23
24 #define AO_RADIO_MAX_RECV       sizeof(struct ao_packet)
25 #define AO_RADIO_MAX_SEND       sizeof(struct ao_packet)
26
27 uint8_t ao_radio_wake;
28 uint8_t ao_radio_mutex;
29 uint8_t ao_radio_abort;
30 uint8_t ao_radio_in_recv;
31
32 #define CC1120_DEBUG    AO_FEC_DEBUG
33 #define CC1120_TRACE    0
34
35 extern const uint32_t   ao_radio_cal;
36
37 #define FOSC    32000000
38
39 #define ao_radio_select()       ao_spi_get_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS,AO_SPI_SPEED_1MHz)
40 #define ao_radio_deselect()     ao_spi_put_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS)
41 #define ao_radio_spi_send(d,l)  ao_spi_send((d), (l), AO_CC1120_SPI_BUS)
42 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1120_SPI_BUS)
43 #define ao_radio_spi_recv(d,l)  ao_spi_recv((d), (l), AO_CC1120_SPI_BUS)
44 #define ao_radio_duplex(o,i,l)  ao_spi_duplex((o), (i), (l), AO_CC1120_SPI_BUS)
45
46 static uint8_t
47 ao_radio_reg_read(uint16_t addr)
48 {
49         uint8_t data[2];
50         uint8_t d;
51
52 #if CC1120_TRACE
53         printf("\t\tao_radio_reg_read (%04x): ", addr); flush();
54 #endif
55         if (CC1120_IS_EXTENDED(addr)) {
56                 data[0] = ((1 << CC1120_READ)  |
57                            (0 << CC1120_BURST) |
58                            CC1120_EXTENDED);
59                 data[1] = addr;
60                 d = 2;
61         } else {
62                 data[0] = ((1 << CC1120_READ)  |
63                            (0 << CC1120_BURST) |
64                            addr);
65                 d = 1;
66         }
67         ao_radio_select();
68         ao_radio_spi_send(data, d);
69         ao_radio_spi_recv(data, 1);
70         ao_radio_deselect();
71 #if CC1120_TRACE
72         printf (" %02x\n", data[0]);
73 #endif
74         return data[0];
75 }
76
77 static void
78 ao_radio_reg_write(uint16_t addr, uint8_t value)
79 {
80         uint8_t data[3];
81         uint8_t d;
82
83 #if CC1120_TRACE
84         printf("\t\tao_radio_reg_write (%04x): %02x\n", addr, value);
85 #endif
86         if (CC1120_IS_EXTENDED(addr)) {
87                 data[0] = ((0 << CC1120_READ)  |
88                            (0 << CC1120_BURST) |
89                            CC1120_EXTENDED);
90                 data[1] = addr;
91                 d = 2;
92         } else {
93                 data[0] = ((0 << CC1120_READ)  |
94                            (0 << CC1120_BURST) |
95                            addr);
96                 d = 1;
97         }
98         data[d] = value;
99         ao_radio_select();
100         ao_radio_spi_send(data, d+1);
101         ao_radio_deselect();
102 }
103
104 static void
105 ao_radio_burst_read_start (uint16_t addr)
106 {
107         uint8_t data[2];
108         uint8_t d;
109
110         if (CC1120_IS_EXTENDED(addr)) {
111                 data[0] = ((1 << CC1120_READ)  |
112                            (1 << CC1120_BURST) |
113                            CC1120_EXTENDED);
114                 data[1] = addr;
115                 d = 2;
116         } else {
117                 data[0] = ((1 << CC1120_READ)  |
118                            (1 << CC1120_BURST) |
119                            addr);
120                 d = 1;
121         }
122         ao_radio_select();
123         ao_radio_spi_send(data, d);
124 }
125
126 static void
127 ao_radio_burst_read_stop (void)
128 {
129         ao_radio_deselect();
130 }
131
132
133 static uint8_t
134 ao_radio_strobe(uint8_t addr)
135 {
136         uint8_t in;
137
138 #if CC1120_TRACE
139         printf("\t\tao_radio_strobe (%02x): ", addr); flush();
140 #endif
141         ao_radio_select();
142         ao_radio_duplex(&addr, &in, 1);
143         ao_radio_deselect();
144 #if CC1120_TRACE
145         printf("%02x\n", in); flush();
146 #endif
147         return in;
148 }
149
150 static uint8_t
151 ao_radio_fifo_read(uint8_t *data, uint8_t len)
152 {
153         uint8_t addr = ((1 << CC1120_READ)  |
154                         (1 << CC1120_BURST) |
155                         CC1120_FIFO);
156         uint8_t status;
157
158         ao_radio_select();
159         ao_radio_duplex(&addr, &status, 1);
160         ao_radio_spi_recv(data, len);
161         ao_radio_deselect();
162         return status;
163 }
164
165 static uint8_t
166 ao_radio_fifo_write_start(void)
167 {
168         uint8_t addr = ((0 << CC1120_READ)  |
169                         (1 << CC1120_BURST) |
170                         CC1120_FIFO);
171         uint8_t status;
172
173         ao_radio_select();
174         ao_radio_duplex(&addr, &status, 1);
175         return status;
176 }
177
178 static inline uint8_t ao_radio_fifo_write_stop(uint8_t status) {
179         ao_radio_deselect();
180         return status;
181 }
182
183 static uint8_t
184 ao_radio_fifo_write(uint8_t *data, uint8_t len)
185 {
186         uint8_t status = ao_radio_fifo_write_start();
187         ao_radio_spi_send(data, len);
188         return ao_radio_fifo_write_stop(status);
189 }
190
191 static uint8_t
192 ao_radio_fifo_write_fixed(uint8_t data, uint8_t len)
193 {
194         uint8_t status = ao_radio_fifo_write_start();
195         ao_radio_spi_send_fixed(data, len);
196         return ao_radio_fifo_write_stop(status);
197 }
198
199 static uint8_t
200 ao_radio_tx_fifo_space(void)
201 {
202         return CC1120_FIFO_SIZE - ao_radio_reg_read(CC1120_NUM_TXBYTES);
203 }
204
205 static uint8_t
206 ao_radio_status(void)
207 {
208         return ao_radio_strobe (CC1120_SNOP);
209 }
210
211 void
212 ao_radio_recv_abort(void)
213 {
214         ao_radio_abort = 1;
215         ao_wakeup(&ao_radio_wake);
216 }
217
218 #define ao_radio_rdf_value 0x55
219
220 static uint8_t
221 ao_radio_marc_status(void)
222 {
223         return ao_radio_reg_read(CC1120_MARC_STATUS1);
224 }
225
226 static void
227 ao_radio_tx_isr(void)
228 {
229         ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
230         ao_radio_wake = 1;
231         ao_wakeup(&ao_radio_wake);
232 }
233
234 static void
235 ao_radio_start_tx(void)
236 {
237         ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_tx_isr);
238         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
239         ao_radio_strobe(CC1120_STX);
240 }
241
242 static void
243 ao_radio_idle(void)
244 {
245         for (;;) {
246                 uint8_t state = ao_radio_strobe(CC1120_SIDLE);
247                 if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_IDLE)
248                         break;
249         }
250 }
251
252 /*
253  * Packet deviation is 20.5kHz
254  *
255  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
256  *
257  *      32e6Hz / (2 ** 24) * (256 + 80) * (2 ** 5) = 20508Hz
258  */
259
260 #define PACKET_DEV_E    5
261 #define PACKET_DEV_M    80
262
263 /*
264  * For our packet data, set the symbol rate to 38400 Baud
265  *
266  *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
267  *      Rdata = -------------------------------------- * fosc
268  *                           2 ** 39
269  *
270  *
271  *      DATARATE_M = 239914
272  *      DATARATE_E = 9
273  */
274 #define PACKET_DRATE_E  9
275 #define PACKET_DRATE_M  239914
276
277 static const uint16_t packet_setup[] = {
278         CC1120_DEVIATION_M,     PACKET_DEV_M,
279         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
280                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
281                                  (PACKET_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
282         CC1120_DRATE2,          ((PACKET_DRATE_E << CC1120_DRATE2_DATARATE_E) |
283                                  (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
284         CC1120_DRATE1,          ((PACKET_DRATE_M >> 8) & 0xff),
285         CC1120_DRATE0,          ((PACKET_DRATE_M >> 0) & 0xff),
286         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
287                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
288         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
289                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
290                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
291                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
292         CC1120_PKT_CFG0,        ((0 << CC1120_PKT_CFG0_RESERVED7) |
293                                  (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
294                                  (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
295                                  (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
296                                  (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
297 };
298
299 static const uint16_t packet_tx_setup[] = {
300         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
301                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
302         CC1120_IOCFG2,          CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG,
303 };
304
305 static const uint16_t packet_rx_setup[] = {
306         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
307                                  (CC1120_PKT_CFG2_PKT_FORMAT_SYNCHRONOUS_SERIAL << CC1120_PKT_CFG2_PKT_FORMAT)),
308         CC1120_IOCFG2,          CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT,
309 };
310
311 /*
312  * RDF deviation is 5kHz
313  *
314  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
315  *
316  *      32e6Hz / (2 ** 24) * (256 + 71) * (2 ** 3) = 4989
317  */
318
319 #define RDF_DEV_E       3
320 #define RDF_DEV_M       71
321 #define RDF_PACKET_LEN  50
322
323 /*
324  * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
325  *
326  *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
327  *      Rdata = -------------------------------------- * fosc
328  *                           2 ** 39
329  *
330  *      DATARATE_M = 25166
331  *      DATARATE_E = 5
332  *
333  * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes
334  */
335 #define RDF_DRATE_E     5
336 #define RDF_DRATE_M     25166
337 #define RDF_PACKET_LEN  50
338
339 static const uint16_t rdf_setup[] = {
340         CC1120_DEVIATION_M,     RDF_DEV_M,
341         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
342                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
343                                  (RDF_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
344         CC1120_DRATE2,          ((RDF_DRATE_E << CC1120_DRATE2_DATARATE_E) |
345                                  (((RDF_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
346         CC1120_DRATE1,          ((RDF_DRATE_M >> 8) & 0xff),
347         CC1120_DRATE0,          ((RDF_DRATE_M >> 0) & 0xff),
348         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
349                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
350         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
351                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
352                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
353                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
354         CC1120_PKT_CFG0,        ((0 << CC1120_PKT_CFG0_RESERVED7) |
355                                  (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
356                                  (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
357                                  (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
358                                  (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
359 };
360
361 /*
362  * APRS deviation is 5kHz
363  *
364  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
365  *
366  *      32e6Hz / (2 ** 24) * (256 + 71) * (2 ** 3) = 4989
367  */
368
369 #define APRS_DEV_E      3
370 #define APRS_DEV_M      71
371 #define APRS_PACKET_LEN 50
372
373 /*
374  * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate)
375  *
376  *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
377  *      Rdata = -------------------------------------- * fosc
378  *                           2 ** 39
379  *
380  *      DATARATE_M = 239914
381  *      DATARATE_E = 7
382  *
383  *      Rdata = 9599.998593330383301
384  *
385  */
386 #define APRS_DRATE_E    7
387 #define APRS_DRATE_M    239914
388
389 static const uint16_t aprs_setup[] = {
390         CC1120_DEVIATION_M,     APRS_DEV_M,
391         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
392                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
393                                  (APRS_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
394         CC1120_DRATE2,          ((APRS_DRATE_E << CC1120_DRATE2_DATARATE_E) |
395                                  (((APRS_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
396         CC1120_DRATE1,          ((APRS_DRATE_M >> 8) & 0xff),
397         CC1120_DRATE0,          ((APRS_DRATE_M >> 0) & 0xff),
398         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
399                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
400         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
401                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
402                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
403                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
404 };
405
406 #define AO_PKT_CFG0_INFINITE ((0 << CC1120_PKT_CFG0_RESERVED7) |        \
407                               (CC1120_PKT_CFG0_LENGTH_CONFIG_INFINITE << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
408                               (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |      \
409                               (0 << CC1120_PKT_CFG0_UART_MODE_EN) |     \
410                               (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
411
412 #define AO_PKT_CFG0_FIXED ((0 << CC1120_PKT_CFG0_RESERVED7) |           \
413                            (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
414                            (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |         \
415                            (0 << CC1120_PKT_CFG0_UART_MODE_EN) |        \
416                            (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
417
418 static uint16_t ao_radio_mode;
419
420 #define AO_RADIO_MODE_BITS_PACKET       1
421 #define AO_RADIO_MODE_BITS_PACKET_TX    2
422 #define AO_RADIO_MODE_BITS_TX_BUF       4
423 #define AO_RADIO_MODE_BITS_TX_FINISH    8
424 #define AO_RADIO_MODE_BITS_PACKET_RX    16
425 #define AO_RADIO_MODE_BITS_RDF          32
426 #define AO_RADIO_MODE_BITS_APRS         64
427 #define AO_RADIO_MODE_BITS_INFINITE     128
428 #define AO_RADIO_MODE_BITS_FIXED        256
429
430 #define AO_RADIO_MODE_NONE              0
431 #define AO_RADIO_MODE_PACKET_TX_BUF     (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF)
432 #define AO_RADIO_MODE_PACKET_TX_FINISH  (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_FINISH)
433 #define AO_RADIO_MODE_PACKET_RX         (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_RX)
434 #define AO_RADIO_MODE_RDF               (AO_RADIO_MODE_BITS_RDF | AO_RADIO_MODE_BITS_TX_FINISH)
435 #define AO_RADIO_MODE_APRS_BUF          (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF)
436 #define AO_RADIO_MODE_APRS_LAST_BUF     (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_BUF)
437 #define AO_RADIO_MODE_APRS_FINISH       (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_FINISH)
438
439 static void
440 ao_radio_set_mode(uint16_t new_mode)
441 {
442         uint16_t changes;
443         int i;
444
445         if (new_mode == ao_radio_mode)
446                 return;
447
448         changes = new_mode & (~ao_radio_mode);
449         if (changes & AO_RADIO_MODE_BITS_PACKET)
450                 for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2)
451                         ao_radio_reg_write(packet_setup[i], packet_setup[i+1]);
452
453         if (changes & AO_RADIO_MODE_BITS_PACKET_TX)
454                 for (i = 0; i < sizeof (packet_tx_setup) / sizeof (packet_tx_setup[0]); i += 2)
455                         ao_radio_reg_write(packet_tx_setup[i], packet_tx_setup[i+1]);
456                 
457         if (changes & AO_RADIO_MODE_BITS_TX_BUF)
458                 ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_TXFIFO_THR);
459
460         if (changes & AO_RADIO_MODE_BITS_TX_FINISH)
461                 ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);
462
463         if (changes & AO_RADIO_MODE_BITS_PACKET_RX)
464                 for (i = 0; i < sizeof (packet_rx_setup) / sizeof (packet_rx_setup[0]); i += 2)
465                         ao_radio_reg_write(packet_rx_setup[i], packet_rx_setup[i+1]);
466                 
467         if (changes & AO_RADIO_MODE_BITS_RDF)
468                 for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
469                         ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
470
471         if (changes & AO_RADIO_MODE_BITS_APRS)
472                 for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2)
473                         ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]);
474
475         if (changes & AO_RADIO_MODE_BITS_INFINITE)
476                 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_INFINITE);
477
478         if (changes & AO_RADIO_MODE_BITS_FIXED)
479                 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_FIXED);
480
481         ao_radio_mode = new_mode;
482 }
483
484 static const uint16_t radio_setup[] = {
485 #include "ao_cc1120_CC1120.h"
486 };
487
488 static uint8_t  ao_radio_configured = 0;
489
490 static void
491 ao_radio_setup(void)
492 {
493         int     i;
494
495         ao_radio_strobe(CC1120_SRES);
496
497         for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
498                 ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
499
500         ao_radio_mode = 0;
501
502         ao_config_get();
503
504         ao_radio_configured = 1;
505 }
506
507 static void
508 ao_radio_set_len(uint8_t len)
509 {
510         static uint8_t  last_len;
511
512         if (len != last_len) {
513                 ao_radio_reg_write(CC1120_PKT_LEN, len);
514                 last_len = len;
515         }
516 }
517
518 static void
519 ao_radio_get(uint8_t len)
520 {
521         static uint32_t last_radio_setting;
522
523         ao_mutex_get(&ao_radio_mutex);
524         if (!ao_radio_configured)
525                 ao_radio_setup();
526         if (ao_config.radio_setting != last_radio_setting) {
527                 ao_radio_reg_write(CC1120_FREQ2, ao_config.radio_setting >> 16);
528                 ao_radio_reg_write(CC1120_FREQ1, ao_config.radio_setting >> 8);
529                 ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting);
530                 last_radio_setting = ao_config.radio_setting;
531         }
532         ao_radio_set_len(len);
533 }
534
535 #define ao_radio_put()  ao_mutex_put(&ao_radio_mutex)
536
537 static void
538 ao_rdf_start(uint8_t len)
539 {
540         ao_radio_abort = 0;
541         ao_radio_get(len);
542
543         ao_radio_set_mode(AO_RADIO_MODE_RDF);
544         ao_radio_wake = 0;
545
546 }
547
548 static void
549 ao_rdf_run(void)
550 {
551         ao_radio_start_tx();
552
553         ao_arch_block_interrupts();
554         while (!ao_radio_wake && !ao_radio_abort)
555                 ao_sleep(&ao_radio_wake);
556         ao_arch_release_interrupts();
557         if (!ao_radio_wake)
558                 ao_radio_idle();
559         ao_radio_put();
560 }
561
562 void
563 ao_radio_rdf(void)
564 {
565         ao_rdf_start(AO_RADIO_RDF_LEN);
566
567         ao_radio_fifo_write_fixed(ao_radio_rdf_value, AO_RADIO_RDF_LEN);
568
569         ao_rdf_run();
570 }
571
572 void
573 ao_radio_continuity(uint8_t c)
574 {
575         uint8_t i;
576         uint8_t status;
577
578         ao_rdf_start(AO_RADIO_CONT_TOTAL_LEN);
579
580         status = ao_radio_fifo_write_start();
581         for (i = 0; i < 3; i++) {
582                 ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN);
583                 if (i < c)
584                         ao_radio_spi_send_fixed(ao_radio_rdf_value, AO_RADIO_CONT_TONE_LEN);
585                 else
586                         ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_TONE_LEN);
587         }
588         ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN);
589         status = ao_radio_fifo_write_stop(status);
590         (void) status;
591         ao_rdf_run();
592 }
593
594 void
595 ao_radio_rdf_abort(void)
596 {
597         ao_radio_abort = 1;
598         ao_wakeup(&ao_radio_wake);
599 }
600
601 static void
602 ao_radio_test_cmd(void)
603 {
604         uint8_t mode = 2;
605         static uint8_t radio_on;
606         ao_cmd_white();
607         if (ao_cmd_lex_c != '\n') {
608                 ao_cmd_decimal();
609                 mode = (uint8_t) ao_cmd_lex_u32;
610         }
611         mode++;
612         if ((mode & 2) && !radio_on) {
613 #if HAS_MONITOR
614                 ao_monitor_disable();
615 #endif
616 #if PACKET_HAS_SLAVE
617                 ao_packet_slave_stop();
618 #endif
619                 ao_radio_get(0xff);
620                 ao_radio_strobe(CC1120_STX);
621 #if CC1120_TRACE
622                 { int t; 
623                         for (t = 0; t < 10; t++) {
624                                 printf ("status: %02x\n", ao_radio_status());
625                                 ao_delay(AO_MS_TO_TICKS(100));
626                         }
627                 }
628 #endif
629                 radio_on = 1;
630         }
631         if (mode == 3) {
632                 printf ("Hit a character to stop..."); flush();
633                 getchar();
634                 putchar('\n');
635         }
636         if ((mode & 1) && radio_on) {
637                 ao_radio_idle();
638                 ao_radio_put();
639                 radio_on = 0;
640 #if HAS_MONITOR
641                 ao_monitor_enable();
642 #endif
643         }
644 }
645
646 static void
647 ao_radio_wait_isr(void)
648 {
649         ao_radio_wake = 0;
650         ao_arch_block_interrupts();
651         while (!ao_radio_wake)
652                 ao_sleep(&ao_radio_wake);
653         ao_arch_release_interrupts();
654 }
655
656 static uint8_t
657 ao_radio_wait_tx(uint8_t wait_fifo)
658 {
659         uint8_t fifo_space = 0;
660
661         do {
662                 ao_radio_wait_isr();
663                 if (!wait_fifo)
664                         return 0;
665                 fifo_space = ao_radio_tx_fifo_space();
666         } while (!fifo_space);
667         return fifo_space;
668 }
669
670 static uint8_t  tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
671
672 void
673 ao_radio_send(const void *d, uint8_t size)
674 {
675         uint8_t         marc_status;
676         uint8_t         *e = tx_data;
677         uint8_t         encode_len;
678         uint8_t         this_len;
679         uint8_t         started = 0;
680         uint8_t         fifo_space;
681
682         encode_len = ao_fec_encode(d, size, tx_data);
683
684         ao_radio_get(encode_len);
685
686         started = 0;
687         fifo_space = CC1120_FIFO_SIZE;
688         while (encode_len) {
689                 this_len = encode_len;
690
691                 if (this_len > fifo_space) {
692                         this_len = fifo_space;
693                         ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF);
694                 } else {
695                         ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_FINISH);
696                 }
697
698                 ao_radio_fifo_write(e, this_len);
699                 e += this_len;
700                 encode_len -= this_len;
701
702                 if (!started) {
703                         ao_radio_start_tx();
704                         started = 1;
705                 } else {
706                         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
707                 }
708                         
709                 fifo_space = ao_radio_wait_tx(encode_len != 0);
710         }
711         ao_radio_put();
712 }
713
714 #define AO_RADIO_LOTS   64
715
716 void
717 ao_radio_send_lots(ao_radio_fill_func fill)
718 {
719         uint8_t buf[AO_RADIO_LOTS], *b;
720         int     cnt;
721         int     total = 0;
722         uint8_t done = 0;
723         uint8_t started = 0;
724         uint8_t fifo_space;
725
726         ao_radio_get(0xff);
727         fifo_space = CC1120_FIFO_SIZE;
728         while (!done) {
729                 cnt = (*fill)(buf, sizeof(buf));
730                 if (cnt < 0) {
731                         done = 1;
732                         cnt = -cnt;
733                 }
734                 total += cnt;
735
736                 /* At the last buffer, set the total length */
737                 if (done)
738                         ao_radio_set_len(total & 0xff);
739
740                 b = buf;
741                 while (cnt) {
742                         uint8_t this_len = cnt;
743
744                         /* Wait for some space in the fifo */
745                         while ((fifo_space = ao_radio_tx_fifo_space()) == 0) {
746                                 ao_radio_wake = 0;
747                                 ao_arch_block_interrupts();
748                                 while (!ao_radio_wake)
749                                         ao_sleep(&ao_radio_wake);
750                                 ao_arch_release_interrupts();
751                         }
752                         if (this_len > fifo_space)
753                                 this_len = fifo_space;
754
755                         cnt -= this_len;
756
757                         if (done) {
758                                 if (cnt)
759                                         ao_radio_set_mode(AO_RADIO_MODE_APRS_LAST_BUF);
760                                 else
761                                         ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH);
762                         } else
763                                 ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF);
764
765                         ao_radio_fifo_write(b, this_len);
766                         b += this_len;
767
768                         if (!started) {
769                                 ao_radio_start_tx();
770                                 started = 1;
771                         } else
772                                 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
773                 }
774                 /* Wait for the transmitter to go idle */
775                 ao_radio_wait_isr();
776         }
777         ao_radio_put();
778 }
779
780 static uint8_t  rx_data[(AO_RADIO_MAX_RECV + 4) * 2 * 8];
781 static uint16_t rx_data_count;
782 static uint16_t rx_data_consumed;
783 static uint16_t rx_data_cur;
784 static uint8_t  rx_ignore;
785 static uint8_t  rx_waiting;
786
787 #if AO_PROFILE
788 static uint32_t rx_start_tick, rx_packet_tick, rx_done_tick, rx_last_done_tick;
789
790 uint32_t        ao_rx_start_tick, ao_rx_packet_tick, ao_rx_done_tick, ao_rx_last_done_tick;
791
792 #include <ao_profile.h>
793 #endif
794
795 static void
796 ao_radio_rx_isr(void)
797 {
798         uint8_t d;
799
800         d = stm_spi2.dr;
801         stm_spi2.dr = 0;
802         if (rx_ignore == 0) {
803                 if (rx_data_cur >= rx_data_count)
804                         ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
805                 else
806                         rx_data[rx_data_cur++] = d;
807                 if (rx_waiting && rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) {
808 #if AO_PROFILE
809                         if (!rx_packet_tick)
810                                 rx_packet_tick = ao_profile_tick();
811                         if (rx_data_cur < rx_data_count)
812                                 return;
813 #endif
814                         rx_waiting = 0;
815                         ao_wakeup(&ao_radio_wake);
816                 }
817         } else {
818                 --rx_ignore;
819         }
820 }
821
822 static uint16_t
823 ao_radio_rx_wait(void)
824 {
825         ao_arch_block_interrupts();
826         rx_waiting = 1;
827         while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
828                !ao_radio_abort) {
829                 ao_sleep(&ao_radio_wake);
830         }
831         rx_waiting = 0;
832         ao_arch_release_interrupts();
833         if (ao_radio_abort)
834                 return 0;
835         rx_data_consumed += AO_FEC_DECODE_BLOCK;
836 #if AO_PROFILE
837         return rx_data_cur - rx_data_consumed;
838 #endif
839         return AO_FEC_DECODE_BLOCK;
840 }
841
842 uint8_t
843 ao_radio_recv(__xdata void *d, uint8_t size)
844 {
845         uint8_t         len;
846         uint16_t        i;
847         uint8_t         rssi;
848         uint8_t         ret;
849         static int been_here = 0;
850
851         size -= 2;                      /* status bytes */
852         if (size > AO_RADIO_MAX_RECV) {
853                 ao_delay(AO_SEC_TO_TICKS(1));
854                 return 0;
855         }
856 #if AO_PROFILE
857         rx_start_tick = ao_profile_tick();
858         rx_packet_tick = 0;
859 #endif
860         len = size + 2;                 /* CRC bytes */
861         len += 1 + ~(len & 1);          /* 1 or two pad bytes */
862         len *= 2;                       /* 1/2 rate convolution */
863         rx_data_count = len * 8;        /* bytes to bits */
864         rx_data_cur = 0;
865         rx_data_consumed = 0;
866         rx_ignore = 2;
867
868         ao_radio_abort = 0;
869         ao_radio_in_recv = 1;
870         /* configure interrupt pin */
871         ao_radio_get(len);
872         ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX);
873
874         ao_radio_wake = 0;
875
876         stm_spi2.cr2 = 0;
877
878         /* clear any RXNE */
879         (void) stm_spi2.dr;
880
881         ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
882         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
883
884         ao_radio_strobe(CC1120_SRX);
885
886         ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
887
888         ret = ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);
889
890         ao_radio_burst_read_stop();
891
892         ao_radio_strobe(CC1120_SIDLE);
893
894         /* Convert from 'real' rssi to cc1111-style values */
895
896         rssi = AO_RADIO_FROM_RSSI(ao_radio_reg_read(CC1120_RSSI1));
897
898         ao_radio_put();
899
900         /* Store the received RSSI value; the crc-OK byte is already done */
901
902         ((uint8_t *) d)[size] = (uint8_t) rssi;
903
904         ao_radio_in_recv = 0;
905
906         if (ao_radio_abort)
907                 ao_delay(1);
908
909 #if AO_PROFILE
910         rx_last_done_tick = rx_done_tick;
911         rx_done_tick = ao_profile_tick();
912
913         ao_rx_start_tick = rx_start_tick;
914         ao_rx_packet_tick = rx_packet_tick;
915         ao_rx_done_tick = rx_done_tick;
916         ao_rx_last_done_tick = rx_last_done_tick;
917 #endif
918
919         return ret;
920 }
921
922
923 #if CC1120_DEBUG
924 static char *cc1120_state_name[] = {
925         [CC1120_STATUS_STATE_IDLE] = "IDLE",
926         [CC1120_STATUS_STATE_RX] = "RX",
927         [CC1120_STATUS_STATE_TX] = "TX",
928         [CC1120_STATUS_STATE_FSTXON] = "FSTXON",
929         [CC1120_STATUS_STATE_CALIBRATE] = "CALIBRATE",
930         [CC1120_STATUS_STATE_SETTLING] = "SETTLING",
931         [CC1120_STATUS_STATE_RX_FIFO_ERROR] = "RX_FIFO_ERROR",
932         [CC1120_STATUS_STATE_TX_FIFO_ERROR] = "TX_FIFO_ERROR",
933 };
934
935 struct ao_cc1120_reg {
936         uint16_t        addr;
937         char            *name;
938 };
939
940 const static struct ao_cc1120_reg ao_cc1120_reg[] = {
941         { .addr = CC1120_IOCFG3,        .name = "IOCFG3" },
942         { .addr = CC1120_IOCFG2,        .name = "IOCFG2" },
943         { .addr = CC1120_IOCFG1,        .name = "IOCFG1" },
944         { .addr = CC1120_IOCFG0,        .name = "IOCFG0" },
945         { .addr = CC1120_SYNC3, .name = "SYNC3" },
946         { .addr = CC1120_SYNC2, .name = "SYNC2" },
947         { .addr = CC1120_SYNC1, .name = "SYNC1" },
948         { .addr = CC1120_SYNC0, .name = "SYNC0" },
949         { .addr = CC1120_SYNC_CFG1,     .name = "SYNC_CFG1" },
950         { .addr = CC1120_SYNC_CFG0,     .name = "SYNC_CFG0" },
951         { .addr = CC1120_DEVIATION_M,   .name = "DEVIATION_M" },
952         { .addr = CC1120_MODCFG_DEV_E,  .name = "MODCFG_DEV_E" },
953         { .addr = CC1120_DCFILT_CFG,    .name = "DCFILT_CFG" },
954         { .addr = CC1120_PREAMBLE_CFG1, .name = "PREAMBLE_CFG1" },
955         { .addr = CC1120_PREAMBLE_CFG0, .name = "PREAMBLE_CFG0" },
956         { .addr = CC1120_FREQ_IF_CFG,   .name = "FREQ_IF_CFG" },
957         { .addr = CC1120_IQIC,  .name = "IQIC" },
958         { .addr = CC1120_CHAN_BW,       .name = "CHAN_BW" },
959         { .addr = CC1120_MDMCFG1,       .name = "MDMCFG1" },
960         { .addr = CC1120_MDMCFG0,       .name = "MDMCFG0" },
961         { .addr = CC1120_DRATE2,        .name = "DRATE2" },
962         { .addr = CC1120_DRATE1,        .name = "DRATE1" },
963         { .addr = CC1120_DRATE0,        .name = "DRATE0" },
964         { .addr = CC1120_AGC_REF,       .name = "AGC_REF" },
965         { .addr = CC1120_AGC_CS_THR,    .name = "AGC_CS_THR" },
966         { .addr = CC1120_AGC_GAIN_ADJUST,       .name = "AGC_GAIN_ADJUST" },
967         { .addr = CC1120_AGC_CFG3,      .name = "AGC_CFG3" },
968         { .addr = CC1120_AGC_CFG2,      .name = "AGC_CFG2" },
969         { .addr = CC1120_AGC_CFG1,      .name = "AGC_CFG1" },
970         { .addr = CC1120_AGC_CFG0,      .name = "AGC_CFG0" },
971         { .addr = CC1120_FIFO_CFG,      .name = "FIFO_CFG" },
972         { .addr = CC1120_DEV_ADDR,      .name = "DEV_ADDR" },
973         { .addr = CC1120_SETTLING_CFG,  .name = "SETTLING_CFG" },
974         { .addr = CC1120_FS_CFG,        .name = "FS_CFG" },
975         { .addr = CC1120_WOR_CFG1,      .name = "WOR_CFG1" },
976         { .addr = CC1120_WOR_CFG0,      .name = "WOR_CFG0" },
977         { .addr = CC1120_WOR_EVENT0_MSB,        .name = "WOR_EVENT0_MSB" },
978         { .addr = CC1120_WOR_EVENT0_LSB,        .name = "WOR_EVENT0_LSB" },
979         { .addr = CC1120_PKT_CFG2,      .name = "PKT_CFG2" },
980         { .addr = CC1120_PKT_CFG1,      .name = "PKT_CFG1" },
981         { .addr = CC1120_PKT_CFG0,      .name = "PKT_CFG0" },
982         { .addr = CC1120_RFEND_CFG1,    .name = "RFEND_CFG1" },
983         { .addr = CC1120_RFEND_CFG0,    .name = "RFEND_CFG0" },
984         { .addr = CC1120_PA_CFG2,       .name = "PA_CFG2" },
985         { .addr = CC1120_PA_CFG1,       .name = "PA_CFG1" },
986         { .addr = CC1120_PA_CFG0,       .name = "PA_CFG0" },
987         { .addr = CC1120_PKT_LEN,       .name = "PKT_LEN" },
988         { .addr = CC1120_IF_MIX_CFG,    .name = "IF_MIX_CFG" },
989         { .addr = CC1120_FREQOFF_CFG,   .name = "FREQOFF_CFG" },
990         { .addr = CC1120_TOC_CFG,       .name = "TOC_CFG" },
991         { .addr = CC1120_MARC_SPARE,    .name = "MARC_SPARE" },
992         { .addr = CC1120_ECG_CFG,       .name = "ECG_CFG" },
993         { .addr = CC1120_SOFT_TX_DATA_CFG,      .name = "SOFT_TX_DATA_CFG" },
994         { .addr = CC1120_EXT_CTRL,      .name = "EXT_CTRL" },
995         { .addr = CC1120_RCCAL_FINE,    .name = "RCCAL_FINE" },
996         { .addr = CC1120_RCCAL_COARSE,  .name = "RCCAL_COARSE" },
997         { .addr = CC1120_RCCAL_OFFSET,  .name = "RCCAL_OFFSET" },
998         { .addr = CC1120_FREQOFF1,      .name = "FREQOFF1" },
999         { .addr = CC1120_FREQOFF0,      .name = "FREQOFF0" },
1000         { .addr = CC1120_FREQ2, .name = "FREQ2" },
1001         { .addr = CC1120_FREQ1, .name = "FREQ1" },
1002         { .addr = CC1120_FREQ0, .name = "FREQ0" },
1003         { .addr = CC1120_IF_ADC2,       .name = "IF_ADC2" },
1004         { .addr = CC1120_IF_ADC1,       .name = "IF_ADC1" },
1005         { .addr = CC1120_IF_ADC0,       .name = "IF_ADC0" },
1006         { .addr = CC1120_FS_DIG1,       .name = "FS_DIG1" },
1007         { .addr = CC1120_FS_DIG0,       .name = "FS_DIG0" },
1008         { .addr = CC1120_FS_CAL3,       .name = "FS_CAL3" },
1009         { .addr = CC1120_FS_CAL2,       .name = "FS_CAL2" },
1010         { .addr = CC1120_FS_CAL1,       .name = "FS_CAL1" },
1011         { .addr = CC1120_FS_CAL0,       .name = "FS_CAL0" },
1012         { .addr = CC1120_FS_CHP,        .name = "FS_CHP" },
1013         { .addr = CC1120_FS_DIVTWO,     .name = "FS_DIVTWO" },
1014         { .addr = CC1120_FS_DSM1,       .name = "FS_DSM1" },
1015         { .addr = CC1120_FS_DSM0,       .name = "FS_DSM0" },
1016         { .addr = CC1120_FS_DVC1,       .name = "FS_DVC1" },
1017         { .addr = CC1120_FS_DVC0,       .name = "FS_DVC0" },
1018         { .addr = CC1120_FS_LBI,        .name = "FS_LBI" },
1019         { .addr = CC1120_FS_PFD,        .name = "FS_PFD" },
1020         { .addr = CC1120_FS_PRE,        .name = "FS_PRE" },
1021         { .addr = CC1120_FS_REG_DIV_CML,        .name = "FS_REG_DIV_CML" },
1022         { .addr = CC1120_FS_SPARE,      .name = "FS_SPARE" },
1023         { .addr = CC1120_FS_VCO4,       .name = "FS_VCO4" },
1024         { .addr = CC1120_FS_VCO3,       .name = "FS_VCO3" },
1025         { .addr = CC1120_FS_VCO2,       .name = "FS_VCO2" },
1026         { .addr = CC1120_FS_VCO1,       .name = "FS_VCO1" },
1027         { .addr = CC1120_FS_VCO0,       .name = "FS_VCO0" },
1028         { .addr = CC1120_GBIAS6,        .name = "GBIAS6" },
1029         { .addr = CC1120_GBIAS5,        .name = "GBIAS5" },
1030         { .addr = CC1120_GBIAS4,        .name = "GBIAS4" },
1031         { .addr = CC1120_GBIAS3,        .name = "GBIAS3" },
1032         { .addr = CC1120_GBIAS2,        .name = "GBIAS2" },
1033         { .addr = CC1120_GBIAS1,        .name = "GBIAS1" },
1034         { .addr = CC1120_GBIAS0,        .name = "GBIAS0" },
1035         { .addr = CC1120_IFAMP, .name = "IFAMP" },
1036         { .addr = CC1120_LNA,   .name = "LNA" },
1037         { .addr = CC1120_RXMIX, .name = "RXMIX" },
1038         { .addr = CC1120_XOSC5, .name = "XOSC5" },
1039         { .addr = CC1120_XOSC4, .name = "XOSC4" },
1040         { .addr = CC1120_XOSC3, .name = "XOSC3" },
1041         { .addr = CC1120_XOSC2, .name = "XOSC2" },
1042         { .addr = CC1120_XOSC1, .name = "XOSC1" },
1043         { .addr = CC1120_XOSC0, .name = "XOSC0" },
1044         { .addr = CC1120_ANALOG_SPARE,  .name = "ANALOG_SPARE" },
1045         { .addr = CC1120_PA_CFG3,       .name = "PA_CFG3" },
1046         { .addr = CC1120_WOR_TIME1,     .name = "WOR_TIME1" },
1047         { .addr = CC1120_WOR_TIME0,     .name = "WOR_TIME0" },
1048         { .addr = CC1120_WOR_CAPTURE1,  .name = "WOR_CAPTURE1" },
1049         { .addr = CC1120_WOR_CAPTURE0,  .name = "WOR_CAPTURE0" },
1050         { .addr = CC1120_BIST,  .name = "BIST" },
1051         { .addr = CC1120_DCFILTOFFSET_I1,       .name = "DCFILTOFFSET_I1" },
1052         { .addr = CC1120_DCFILTOFFSET_I0,       .name = "DCFILTOFFSET_I0" },
1053         { .addr = CC1120_DCFILTOFFSET_Q1,       .name = "DCFILTOFFSET_Q1" },
1054         { .addr = CC1120_DCFILTOFFSET_Q0,       .name = "DCFILTOFFSET_Q0" },
1055         { .addr = CC1120_IQIE_I1,       .name = "IQIE_I1" },
1056         { .addr = CC1120_IQIE_I0,       .name = "IQIE_I0" },
1057         { .addr = CC1120_IQIE_Q1,       .name = "IQIE_Q1" },
1058         { .addr = CC1120_IQIE_Q0,       .name = "IQIE_Q0" },
1059         { .addr = CC1120_RSSI1, .name = "RSSI1" },
1060         { .addr = CC1120_RSSI0, .name = "RSSI0" },
1061         { .addr = CC1120_MARCSTATE,     .name = "MARCSTATE" },
1062         { .addr = CC1120_LQI_VAL,       .name = "LQI_VAL" },
1063         { .addr = CC1120_PQT_SYNC_ERR,  .name = "PQT_SYNC_ERR" },
1064         { .addr = CC1120_DEM_STATUS,    .name = "DEM_STATUS" },
1065         { .addr = CC1120_FREQOFF_EST1,  .name = "FREQOFF_EST1" },
1066         { .addr = CC1120_FREQOFF_EST0,  .name = "FREQOFF_EST0" },
1067         { .addr = CC1120_AGC_GAIN3,     .name = "AGC_GAIN3" },
1068         { .addr = CC1120_AGC_GAIN2,     .name = "AGC_GAIN2" },
1069         { .addr = CC1120_AGC_GAIN1,     .name = "AGC_GAIN1" },
1070         { .addr = CC1120_AGC_GAIN0,     .name = "AGC_GAIN0" },
1071         { .addr = CC1120_SOFT_RX_DATA_OUT,      .name = "SOFT_RX_DATA_OUT" },
1072         { .addr = CC1120_SOFT_TX_DATA_IN,       .name = "SOFT_TX_DATA_IN" },
1073         { .addr = CC1120_ASK_SOFT_RX_DATA,      .name = "ASK_SOFT_RX_DATA" },
1074         { .addr = CC1120_RNDGEN,        .name = "RNDGEN" },
1075         { .addr = CC1120_MAGN2, .name = "MAGN2" },
1076         { .addr = CC1120_MAGN1, .name = "MAGN1" },
1077         { .addr = CC1120_MAGN0, .name = "MAGN0" },
1078         { .addr = CC1120_ANG1,  .name = "ANG1" },
1079         { .addr = CC1120_ANG0,  .name = "ANG0" },
1080         { .addr = CC1120_CHFILT_I2,     .name = "CHFILT_I2" },
1081         { .addr = CC1120_CHFILT_I1,     .name = "CHFILT_I1" },
1082         { .addr = CC1120_CHFILT_I0,     .name = "CHFILT_I0" },
1083         { .addr = CC1120_CHFILT_Q2,     .name = "CHFILT_Q2" },
1084         { .addr = CC1120_CHFILT_Q1,     .name = "CHFILT_Q1" },
1085         { .addr = CC1120_CHFILT_Q0,     .name = "CHFILT_Q0" },
1086         { .addr = CC1120_GPIO_STATUS,   .name = "GPIO_STATUS" },
1087         { .addr = CC1120_FSCAL_CTRL,    .name = "FSCAL_CTRL" },
1088         { .addr = CC1120_PHASE_ADJUST,  .name = "PHASE_ADJUST" },
1089         { .addr = CC1120_PARTNUMBER,    .name = "PARTNUMBER" },
1090         { .addr = CC1120_PARTVERSION,   .name = "PARTVERSION" },
1091         { .addr = CC1120_SERIAL_STATUS, .name = "SERIAL_STATUS" },
1092         { .addr = CC1120_RX_STATUS,     .name = "RX_STATUS" },
1093         { .addr = CC1120_TX_STATUS,     .name = "TX_STATUS" },
1094         { .addr = CC1120_MARC_STATUS1,  .name = "MARC_STATUS1" },
1095         { .addr = CC1120_MARC_STATUS0,  .name = "MARC_STATUS0" },
1096         { .addr = CC1120_PA_IFAMP_TEST, .name = "PA_IFAMP_TEST" },
1097         { .addr = CC1120_FSRF_TEST,     .name = "FSRF_TEST" },
1098         { .addr = CC1120_PRE_TEST,      .name = "PRE_TEST" },
1099         { .addr = CC1120_PRE_OVR,       .name = "PRE_OVR" },
1100         { .addr = CC1120_ADC_TEST,      .name = "ADC_TEST" },
1101         { .addr = CC1120_DVC_TEST,      .name = "DVC_TEST" },
1102         { .addr = CC1120_ATEST, .name = "ATEST" },
1103         { .addr = CC1120_ATEST_LVDS,    .name = "ATEST_LVDS" },
1104         { .addr = CC1120_ATEST_MODE,    .name = "ATEST_MODE" },
1105         { .addr = CC1120_XOSC_TEST1,    .name = "XOSC_TEST1" },
1106         { .addr = CC1120_XOSC_TEST0,    .name = "XOSC_TEST0" },
1107         { .addr = CC1120_RXFIRST,       .name = "RXFIRST" },
1108         { .addr = CC1120_TXFIRST,       .name = "TXFIRST" },
1109         { .addr = CC1120_RXLAST,        .name = "RXLAST" },
1110         { .addr = CC1120_TXLAST,        .name = "TXLAST" },
1111         { .addr = CC1120_NUM_TXBYTES,   .name = "NUM_TXBYTES" },
1112         { .addr = CC1120_NUM_RXBYTES,   .name = "NUM_RXBYTES" },
1113         { .addr = CC1120_FIFO_NUM_TXBYTES,      .name = "FIFO_NUM_TXBYTES" },
1114         { .addr = CC1120_FIFO_NUM_RXBYTES,      .name = "FIFO_NUM_RXBYTES" },
1115 };
1116
1117 #define AO_NUM_CC1120_REG       (sizeof ao_cc1120_reg / sizeof ao_cc1120_reg[0])
1118
1119 static void ao_radio_show(void) {
1120         uint8_t status = ao_radio_status();
1121         int     i;
1122
1123         ao_radio_get(0xff);
1124         status = ao_radio_status();
1125         printf ("Status:   %02x\n", status);
1126         printf ("CHIP_RDY: %d\n", (status >> CC1120_STATUS_CHIP_RDY) & 1);
1127         printf ("STATE:    %s\n", cc1120_state_name[(status >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK]);
1128         printf ("MARC:     %02x\n", ao_radio_marc_status());
1129
1130         for (i = 0; i < AO_NUM_CC1120_REG; i++)
1131                 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name);
1132         ao_radio_put();
1133 }
1134
1135 static void ao_radio_beep(void) {
1136         ao_radio_rdf(RDF_PACKET_LEN);
1137 }
1138
1139 static void ao_radio_packet(void) {
1140         static const uint8_t packet[] = {
1141 #if 1
1142                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1143                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1144                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1145                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1146 #else
1147                 3, 1, 2, 3
1148 #endif
1149         };
1150
1151         ao_radio_send(packet, sizeof (packet));
1152 }
1153
1154 void
1155 ao_radio_test_recv()
1156 {
1157         uint8_t bytes[34];
1158         uint8_t b;
1159
1160         if (ao_radio_recv(bytes, 34)) {
1161                 if (bytes[33] & 0x80)
1162                         printf ("CRC OK");
1163                 else
1164                         printf ("CRC BAD");
1165                 printf (" RSSI %d", AO_RSSI_FROM_RADIO(bytes[32]));
1166                 for (b = 0; b < 32; b++)
1167                         printf (" %02x", bytes[b]);
1168                 printf ("\n");
1169         }
1170 }
1171
1172 #include <ao_aprs.h>
1173
1174 static void
1175 ao_radio_aprs()
1176 {
1177         ao_packet_slave_stop();
1178         ao_aprs_send();
1179 }
1180
1181 #endif
1182
1183 static const struct ao_cmds ao_radio_cmds[] = {
1184         { ao_radio_test_cmd,    "C <1 start, 0 stop, none both>\0Radio carrier test" },
1185 #if CC1120_DEBUG
1186         { ao_radio_aprs,        "G\0Send APRS packet" },
1187         { ao_radio_show,        "R\0Show CC1120 status" },
1188         { ao_radio_beep,        "b\0Emit an RDF beacon" },
1189         { ao_radio_packet,      "p\0Send a test packet" },
1190         { ao_radio_test_recv,   "q\0Recv a test packet" },
1191 #endif
1192         { 0, NULL }
1193 };
1194
1195 void
1196 ao_radio_init(void)
1197 {
1198         int     i;
1199
1200         ao_radio_configured = 0;
1201         ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN));
1202
1203 #if 0
1204         AO_CC1120_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));
1205         for (i = 0; i < 10000; i++) {
1206                 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
1207                         break;
1208         }
1209         AO_CC1120_SPI_CS_PORT->bsrr = (1 << AO_CC1120_SPI_CS_PIN);
1210         if (i == 10000)
1211                 ao_panic(AO_PANIC_SELF_TEST_CC1120);
1212 #endif
1213
1214         /* Enable the EXTI interrupt for the appropriate pin */
1215         ao_enable_port(AO_CC1120_INT_PORT);
1216         ao_exti_setup(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
1217                       AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
1218                       ao_radio_tx_isr);
1219
1220         ao_cmd_register(&ao_radio_cmds[0]);
1221 }