67a36c5c797fba8f9cd16590ec0da79dff8f27a1
[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
23 uint8_t ao_radio_wake;
24 uint8_t ao_radio_mutex;
25 uint8_t ao_radio_abort;
26
27 #define CC1120_DEBUG    1
28 #define CC1120_TRACE    0
29
30 #if CC1120_TRACE
31 #define fec_dump_bytes(b,l,n) ao_fec_dump_bytes(b,l,n)
32 #else
33 #define fec_dump_bytes(b,l,n)
34 #endif
35
36 uint32_t        ao_radio_cal = 0x6ca333;
37
38 #define FOSC    32000000
39
40 #define ao_radio_select()       ao_spi_get_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS)
41 #define ao_radio_deselect()     ao_spi_put_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS)
42 #define ao_radio_spi_send(d,l)  ao_spi_send((d), (l), AO_CC1120_SPI_BUS)
43 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1120_SPI_BUS)
44 #define ao_radio_spi_recv(d,l)  ao_spi_recv((d), (l), AO_CC1120_SPI_BUS)
45 #define ao_radio_duplex(o,i,l)  ao_spi_duplex((o), (i), (l), AO_CC1120_SPI_BUS)
46
47 static uint8_t
48 ao_radio_reg_read(uint16_t addr)
49 {
50         uint8_t data[2];
51         uint8_t d;
52
53 #if CC1120_TRACE
54         printf("\t\tao_radio_reg_read (%04x): ", addr); flush();
55 #endif
56         if (CC1120_IS_EXTENDED(addr)) {
57                 data[0] = ((1 << CC1120_READ)  |
58                            (0 << CC1120_BURST) |
59                            CC1120_EXTENDED);
60                 data[1] = addr;
61                 d = 2;
62         } else {
63                 data[0] = ((1 << CC1120_READ)  |
64                            (0 << CC1120_BURST) |
65                            addr);
66                 d = 1;
67         }
68         ao_radio_select();
69         ao_radio_spi_send(data, d);
70         ao_radio_spi_recv(data, 1);
71         ao_radio_deselect();
72 #if CC1120_TRACE
73         printf (" %02x\n", data[0]);
74 #endif
75         return data[0];
76 }
77
78 static void
79 ao_radio_reg_write(uint16_t addr, uint8_t value)
80 {
81         uint8_t data[3];
82         uint8_t d;
83
84 #if CC1120_TRACE
85         printf("\t\tao_radio_reg_write (%04x): %02x\n", addr, value);
86 #endif
87         if (CC1120_IS_EXTENDED(addr)) {
88                 data[0] = ((0 << CC1120_READ)  |
89                            (0 << CC1120_BURST) |
90                            CC1120_EXTENDED);
91                 data[1] = addr;
92                 d = 2;
93         } else {
94                 data[0] = ((0 << CC1120_READ)  |
95                            (0 << CC1120_BURST) |
96                            addr);
97                 d = 1;
98         }
99         data[d] = value;
100         ao_radio_select();
101         ao_radio_spi_send(data, d+1);
102         ao_radio_deselect();
103 }
104
105 static uint8_t
106 ao_radio_strobe(uint8_t addr)
107 {
108         uint8_t in;
109
110 #if CC1120_TRACE
111         printf("\t\tao_radio_strobe (%02x): ", addr); flush();
112 #endif
113         ao_radio_select();
114         ao_radio_duplex(&addr, &in, 1);
115         ao_radio_deselect();
116 #if CC1120_TRACE
117         printf("%02x\n", in); flush();
118 #endif
119         return in;
120 }
121
122 static uint8_t
123 ao_radio_fifo_read(uint8_t *data, uint8_t len)
124 {
125         uint8_t addr = ((1 << CC1120_READ)  |
126                         (1 << CC1120_BURST) |
127                         CC1120_FIFO);
128         uint8_t status;
129
130         ao_radio_select();
131         ao_radio_duplex(&addr, &status, 1);
132         ao_radio_spi_recv(data, len);
133         ao_radio_deselect();
134         return status;
135 }
136
137 static uint8_t
138 ao_radio_fifo_write(uint8_t *data, uint8_t len)
139 {
140         uint8_t addr = ((0 << CC1120_READ)  |
141                         (1 << CC1120_BURST) |
142                         CC1120_FIFO);
143         uint8_t status;
144
145         ao_radio_select();
146         ao_radio_duplex(&addr, &status, 1);
147         ao_radio_spi_send(data, len);
148         ao_radio_deselect();
149         return status;
150 }
151
152 static uint8_t
153 ao_radio_fifo_write_fixed(uint8_t data, uint8_t len)
154 {
155         uint8_t addr = ((0 << CC1120_READ)  |
156                         (1 << CC1120_BURST) |
157                         CC1120_FIFO);
158         uint8_t status;
159
160         ao_radio_select();
161         ao_radio_duplex(&addr, &status, 1);
162         ao_radio_spi_send_fixed(data, len);
163         ao_radio_deselect();
164         return status;
165 }
166
167 static uint8_t
168 ao_radio_status(void)
169 {
170         return ao_radio_strobe (CC1120_SNOP);
171 }
172
173 void
174 ao_radio_recv_abort(void)
175 {
176         ao_radio_abort = 1;
177         ao_wakeup(&ao_radio_wake);
178 }
179
180 #define ao_radio_rdf_value 0x55
181
182 /*
183  * RDF deviation is 5kHz
184  *
185  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
186  *
187  *      32e6Hz / (2 ** 24) * (256 + 71) * (2 ** 3) = 4989
188  */
189
190 #define RDF_DEV_E       3
191 #define RDF_DEV_M       71
192 #define RDF_PACKET_LEN  50
193
194 /*
195  * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
196  *
197  *              (2**20 - DATARATE_M) * 2 ** DATARATE_E
198  *      Rdata = -------------------------------------- * fosc
199  *                           2 ** 39
200  *
201  *      DATARATE_M = 511705
202  *      DATARATE_E = 6
203  *
204  * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes
205  */
206 #define RDF_DRATE_E     5
207 #define RDF_DRATE_M     25166
208 #define RDF_PACKET_LEN  50
209
210 static const uint16_t rdf_setup[] = {
211         CC1120_DEVIATION_M,     RDF_DEV_M,
212         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
213                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
214                                  (RDF_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
215         CC1120_DRATE2,          ((RDF_DRATE_E << CC1120_DRATE2_DATARATE_E) |
216                                  (((RDF_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
217         CC1120_DRATE1,          ((RDF_DRATE_M >> 8) & 0xff),
218         CC1120_DRATE0,          ((RDF_DRATE_M >> 0) & 0xff),
219         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
220                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
221         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
222                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
223                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
224                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
225         CC1120_PKT_CFG0,        ((0 << CC1120_PKT_CFG0_RESERVED7) |
226                                  (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
227                                  (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
228                                  (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
229                                  (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
230 };
231
232 static uint8_t
233 ao_radio_marc_status(void)
234 {
235         return ao_radio_reg_read(CC1120_MARC_STATUS1);
236 }
237
238 static uint8_t
239 ao_radio_tx_done(void)
240 {
241         return ao_radio_marc_status() == CC1120_MARC_STATUS1_TX_FINISHED;
242 }
243
244 static uint8_t
245 ao_radio_rx_done(void)
246 {
247         return ao_radio_marc_status() == CC1120_MARC_STATUS1_RX_FINISHED;
248 }
249
250 static void
251 ao_radio_start_tx(void)
252 {
253         ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);
254         ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
255         ao_radio_strobe(CC1120_STX);
256 }
257
258 void
259 ao_radio_rdf(uint8_t len)
260 {
261         int i;
262
263         ao_radio_get(len);
264         ao_radio_wake = 0;
265         for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
266                 ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
267
268         ao_radio_fifo_write_fixed(ao_radio_rdf_value, len);
269
270         ao_radio_start_tx();
271
272         cli();
273         while (!ao_radio_wake && !ao_radio_abort)
274                 ao_sleep(&ao_radio_wake);
275
276         sei();
277         if (!ao_radio_tx_done())
278                 ao_radio_idle();
279         ao_radio_set_packet();
280         ao_radio_put();
281 }
282
283 void
284 ao_radio_rdf_abort(void)
285 {
286         ao_radio_abort = 1;
287         ao_wakeup(&ao_radio_wake);
288 }
289
290 static void
291 ao_radio_test(void)
292 {
293         uint8_t mode = 2;
294         uint8_t radio_on;
295         ao_cmd_white();
296         if (ao_cmd_lex_c != '\n') {
297                 ao_cmd_decimal();
298                 mode = (uint8_t) ao_cmd_lex_u32;
299         }
300         mode++;
301         if ((mode & 2) && !radio_on) {
302 #if HAS_MONITOR
303                 ao_monitor_disable();
304 #endif
305 #if PACKET_HAS_SLAVE
306                 ao_packet_slave_stop();
307 #endif
308                 ao_radio_get(0xff);
309                 ao_radio_strobe(CC1120_STX);
310 #if CC1120_TRACE
311                 { int t; 
312                         for (t = 0; t < 10; t++) {
313                                 printf ("status: %02x\n", ao_radio_status());
314                                 ao_delay(AO_MS_TO_TICKS(100));
315                         }
316                 }
317 #endif
318                 radio_on = 1;
319         }
320         if (mode == 3) {
321                 printf ("Hit a character to stop..."); flush();
322                 getchar();
323                 putchar('\n');
324         }
325         if ((mode & 1) && radio_on) {
326                 ao_radio_idle();
327                 ao_radio_put();
328                 radio_on = 0;
329 #if HAS_MONITOR
330                 ao_monitor_enable();
331 #endif
332         }
333 }
334
335 void
336 ao_radio_send(void *d, uint8_t size)
337 {
338         uint8_t         marc_status;
339         uint8_t         prepare[size + AO_FEC_PREPARE_EXTRA];
340         uint8_t         prepare_len;
341         uint8_t         encode[sizeof(prepare) * 2];
342         uint8_t         encode_len;
343         uint8_t         interleave[sizeof(encode)];
344         uint8_t         interleave_len;
345
346         fec_dump_bytes(d, size, "Input");
347
348         prepare_len = ao_fec_prepare(d, size, prepare);
349         fec_dump_bytes(prepare, prepare_len, "Prepare");
350
351         ao_fec_whiten(prepare, prepare_len, prepare);
352         fec_dump_bytes(prepare, prepare_len, "Whiten");
353
354         encode_len = ao_fec_encode(prepare, prepare_len, encode);
355         fec_dump_bytes(encode, encode_len, "Encode");
356
357         interleave_len = ao_fec_interleave(encode, encode_len, interleave);
358         fec_dump_bytes(interleave, interleave_len, "Interleave");
359
360         ao_radio_get(interleave_len);
361         ao_radio_fifo_write(interleave, interleave_len);
362
363         ao_radio_wake = 0;
364
365         ao_radio_start_tx();
366
367         cli();
368         while (!ao_radio_wake && !ao_radio_abort)
369                 ao_sleep(&ao_radio_wake);
370         sei();
371         if (!ao_radio_tx_done())
372                 ao_radio_idle();
373         ao_radio_put();
374 }
375
376 uint8_t
377 ao_radio_recv(__xdata void *d, uint8_t size)
378 {
379         uint8_t marc_status = CC1120_MARC_STATUS1_NO_FAILURE;
380
381         /* configure interrupt pin */
382         ao_radio_get(size);
383         ao_radio_wake = 0;
384         ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
385         ao_radio_strobe(CC1120_SRX);
386         cli();
387         for (;;) {
388                 if (ao_radio_abort)
389
390                         break;
391                 if (ao_radio_wake) {
392                         marc_status = ao_radio_marc_status();
393                         if (marc_status != CC1120_MARC_STATUS1_NO_FAILURE)
394                                 break;
395                         ao_radio_wake = 0;
396                 }
397                 ao_sleep(&ao_radio_wake);
398         }
399         sei();
400         if (marc_status != CC1120_MARC_STATUS1_RX_FINISHED)
401                 ao_radio_fifo_read(d, size);
402         ao_radio_put();
403         return marc_status == CC1120_MARC_STATUS1_RX_FINISHED;
404 }
405
406 /*
407  * Packet deviation is 20.5kHz
408  *
409  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
410  *
411  *      32e6Hz / (2 ** 24) * (256 + 80) * (2 ** 5) = 20508Hz
412  */
413
414 #define PACKET_DEV_E    5
415 #define PACKET_DEV_M    80
416
417 /*
418  * For our packet data, set the symbol rate to 38360 Baud
419  *
420  *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
421  *      Rdata = -------------------------------------- * fosc
422  *                           2 ** 39
423  *
424  *
425  *      DATARATE_M = 239914
426  *      DATARATE_E = 9
427  */
428 #define PACKET_DRATE_E  9
429 #define PACKET_DRATE_M  239914
430
431 static const uint16_t packet_setup[] = {
432         CC1120_DEVIATION_M,     PACKET_DEV_M,
433         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
434                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
435                                  (PACKET_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
436         CC1120_DRATE2,          ((PACKET_DRATE_E << CC1120_DRATE2_DATARATE_E) |
437                                  (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
438         CC1120_DRATE1,          ((PACKET_DRATE_M >> 8) & 0xff),
439         CC1120_DRATE0,          ((PACKET_DRATE_M >> 0) & 0xff),
440         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
441                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
442         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
443                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
444                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
445                                  (1 << CC1120_PKT_CFG1_APPEND_STATUS)),
446         CC1120_PKT_CFG0,        ((0 << CC1120_PKT_CFG0_RESERVED7) |
447                                  (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
448                                  (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
449                                  (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
450                                  (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
451 };
452
453 void
454 ao_radio_set_packet(void)
455 {
456         int i;
457
458         for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
459                 ao_radio_reg_write(packet_setup[i], packet_setup[i+1]);
460 }
461
462 void
463 ao_radio_idle(void)
464 {
465         for (;;) {
466                 uint8_t state = ao_radio_strobe(CC1120_SIDLE);
467                 if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_IDLE)
468                         break;
469         }
470         ao_radio_strobe(CC1120_SFTX);
471         ao_radio_strobe(CC1120_SFRX);
472 }
473
474 static const uint16_t radio_setup[] = {
475 #include "ao_cc1120_CC1120.h"
476 };
477
478 static uint8_t  ao_radio_configured = 0;
479
480 static void
481 ao_radio_isr(void)
482 {
483         ao_exti_disable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
484         ao_radio_wake = 1;
485         ao_wakeup(&ao_radio_wake);
486 }
487
488 static void
489 ao_radio_setup(void)
490 {
491         int     i;
492
493         ao_radio_strobe(CC1120_SRES);
494
495         for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
496                 ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
497
498         ao_radio_set_packet();
499
500         ao_config_get();
501
502         ao_radio_configured = 1;
503 }
504
505 void
506 ao_radio_get(uint8_t len)
507 {
508         ao_mutex_get(&ao_radio_mutex);
509         if (!ao_radio_configured)
510                 ao_radio_setup();
511         ao_radio_reg_write(CC1120_FREQ2, ao_config.radio_setting >> 16);
512         ao_radio_reg_write(CC1120_FREQ1, ao_config.radio_setting >> 8);
513         ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting);
514         ao_radio_reg_write(CC1120_PKT_LEN, len);
515 }
516
517 #if CC1120_DEBUG
518 static char *cc1120_state_name[] = {
519         [CC1120_STATUS_STATE_IDLE] = "IDLE",
520         [CC1120_STATUS_STATE_RX] = "RX",
521         [CC1120_STATUS_STATE_TX] = "TX",
522         [CC1120_STATUS_STATE_FSTXON] = "FSTXON",
523         [CC1120_STATUS_STATE_CALIBRATE] = "CALIBRATE",
524         [CC1120_STATUS_STATE_SETTLING] = "SETTLING",
525         [CC1120_STATUS_STATE_RX_FIFO_ERROR] = "RX_FIFO_ERROR",
526         [CC1120_STATUS_STATE_TX_FIFO_ERROR] = "TX_FIFO_ERROR",
527 };
528
529 struct ao_cc1120_reg {
530         uint16_t        addr;
531         char            *name;
532 };
533
534 const static struct ao_cc1120_reg ao_cc1120_reg[] = {
535         { .addr = CC1120_IOCFG3,        .name = "IOCFG3" },
536         { .addr = CC1120_IOCFG2,        .name = "IOCFG2" },
537         { .addr = CC1120_IOCFG1,        .name = "IOCFG1" },
538         { .addr = CC1120_IOCFG0,        .name = "IOCFG0" },
539         { .addr = CC1120_SYNC3, .name = "SYNC3" },
540         { .addr = CC1120_SYNC2, .name = "SYNC2" },
541         { .addr = CC1120_SYNC1, .name = "SYNC1" },
542         { .addr = CC1120_SYNC0, .name = "SYNC0" },
543         { .addr = CC1120_SYNC_CFG1,     .name = "SYNC_CFG1" },
544         { .addr = CC1120_SYNC_CFG0,     .name = "SYNC_CFG0" },
545         { .addr = CC1120_DEVIATION_M,   .name = "DEVIATION_M" },
546         { .addr = CC1120_MODCFG_DEV_E,  .name = "MODCFG_DEV_E" },
547         { .addr = CC1120_DCFILT_CFG,    .name = "DCFILT_CFG" },
548         { .addr = CC1120_PREAMBLE_CFG1, .name = "PREAMBLE_CFG1" },
549         { .addr = CC1120_PREAMBLE_CFG0, .name = "PREAMBLE_CFG0" },
550         { .addr = CC1120_FREQ_IF_CFG,   .name = "FREQ_IF_CFG" },
551         { .addr = CC1120_IQIC,  .name = "IQIC" },
552         { .addr = CC1120_CHAN_BW,       .name = "CHAN_BW" },
553         { .addr = CC1120_MDMCFG1,       .name = "MDMCFG1" },
554         { .addr = CC1120_MDMCFG0,       .name = "MDMCFG0" },
555         { .addr = CC1120_DRATE2,        .name = "DRATE2" },
556         { .addr = CC1120_DRATE1,        .name = "DRATE1" },
557         { .addr = CC1120_DRATE0,        .name = "DRATE0" },
558         { .addr = CC1120_AGC_REF,       .name = "AGC_REF" },
559         { .addr = CC1120_AGC_CS_THR,    .name = "AGC_CS_THR" },
560         { .addr = CC1120_AGC_GAIN_ADJUST,       .name = "AGC_GAIN_ADJUST" },
561         { .addr = CC1120_AGC_CFG3,      .name = "AGC_CFG3" },
562         { .addr = CC1120_AGC_CFG2,      .name = "AGC_CFG2" },
563         { .addr = CC1120_AGC_CFG1,      .name = "AGC_CFG1" },
564         { .addr = CC1120_AGC_CFG0,      .name = "AGC_CFG0" },
565         { .addr = CC1120_FIFO_CFG,      .name = "FIFO_CFG" },
566         { .addr = CC1120_DEV_ADDR,      .name = "DEV_ADDR" },
567         { .addr = CC1120_SETTLING_CFG,  .name = "SETTLING_CFG" },
568         { .addr = CC1120_FS_CFG,        .name = "FS_CFG" },
569         { .addr = CC1120_WOR_CFG1,      .name = "WOR_CFG1" },
570         { .addr = CC1120_WOR_CFG0,      .name = "WOR_CFG0" },
571         { .addr = CC1120_WOR_EVENT0_MSB,        .name = "WOR_EVENT0_MSB" },
572         { .addr = CC1120_WOR_EVENT0_LSB,        .name = "WOR_EVENT0_LSB" },
573         { .addr = CC1120_PKT_CFG2,      .name = "PKT_CFG2" },
574         { .addr = CC1120_PKT_CFG1,      .name = "PKT_CFG1" },
575         { .addr = CC1120_PKT_CFG0,      .name = "PKT_CFG0" },
576         { .addr = CC1120_RFEND_CFG1,    .name = "RFEND_CFG1" },
577         { .addr = CC1120_RFEND_CFG0,    .name = "RFEND_CFG0" },
578         { .addr = CC1120_PA_CFG2,       .name = "PA_CFG2" },
579         { .addr = CC1120_PA_CFG1,       .name = "PA_CFG1" },
580         { .addr = CC1120_PA_CFG0,       .name = "PA_CFG0" },
581         { .addr = CC1120_PKT_LEN,       .name = "PKT_LEN" },
582         { .addr = CC1120_IF_MIX_CFG,    .name = "IF_MIX_CFG" },
583         { .addr = CC1120_FREQOFF_CFG,   .name = "FREQOFF_CFG" },
584         { .addr = CC1120_TOC_CFG,       .name = "TOC_CFG" },
585         { .addr = CC1120_MARC_SPARE,    .name = "MARC_SPARE" },
586         { .addr = CC1120_ECG_CFG,       .name = "ECG_CFG" },
587         { .addr = CC1120_SOFT_TX_DATA_CFG,      .name = "SOFT_TX_DATA_CFG" },
588         { .addr = CC1120_EXT_CTRL,      .name = "EXT_CTRL" },
589         { .addr = CC1120_RCCAL_FINE,    .name = "RCCAL_FINE" },
590         { .addr = CC1120_RCCAL_COARSE,  .name = "RCCAL_COARSE" },
591         { .addr = CC1120_RCCAL_OFFSET,  .name = "RCCAL_OFFSET" },
592         { .addr = CC1120_FREQOFF1,      .name = "FREQOFF1" },
593         { .addr = CC1120_FREQOFF0,      .name = "FREQOFF0" },
594         { .addr = CC1120_FREQ2, .name = "FREQ2" },
595         { .addr = CC1120_FREQ1, .name = "FREQ1" },
596         { .addr = CC1120_FREQ0, .name = "FREQ0" },
597         { .addr = CC1120_IF_ADC2,       .name = "IF_ADC2" },
598         { .addr = CC1120_IF_ADC1,       .name = "IF_ADC1" },
599         { .addr = CC1120_IF_ADC0,       .name = "IF_ADC0" },
600         { .addr = CC1120_FS_DIG1,       .name = "FS_DIG1" },
601         { .addr = CC1120_FS_DIG0,       .name = "FS_DIG0" },
602         { .addr = CC1120_FS_CAL3,       .name = "FS_CAL3" },
603         { .addr = CC1120_FS_CAL2,       .name = "FS_CAL2" },
604         { .addr = CC1120_FS_CAL1,       .name = "FS_CAL1" },
605         { .addr = CC1120_FS_CAL0,       .name = "FS_CAL0" },
606         { .addr = CC1120_FS_CHP,        .name = "FS_CHP" },
607         { .addr = CC1120_FS_DIVTWO,     .name = "FS_DIVTWO" },
608         { .addr = CC1120_FS_DSM1,       .name = "FS_DSM1" },
609         { .addr = CC1120_FS_DSM0,       .name = "FS_DSM0" },
610         { .addr = CC1120_FS_DVC1,       .name = "FS_DVC1" },
611         { .addr = CC1120_FS_DVC0,       .name = "FS_DVC0" },
612         { .addr = CC1120_FS_LBI,        .name = "FS_LBI" },
613         { .addr = CC1120_FS_PFD,        .name = "FS_PFD" },
614         { .addr = CC1120_FS_PRE,        .name = "FS_PRE" },
615         { .addr = CC1120_FS_REG_DIV_CML,        .name = "FS_REG_DIV_CML" },
616         { .addr = CC1120_FS_SPARE,      .name = "FS_SPARE" },
617         { .addr = CC1120_FS_VCO4,       .name = "FS_VCO4" },
618         { .addr = CC1120_FS_VCO3,       .name = "FS_VCO3" },
619         { .addr = CC1120_FS_VCO2,       .name = "FS_VCO2" },
620         { .addr = CC1120_FS_VCO1,       .name = "FS_VCO1" },
621         { .addr = CC1120_FS_VCO0,       .name = "FS_VCO0" },
622         { .addr = CC1120_GBIAS6,        .name = "GBIAS6" },
623         { .addr = CC1120_GBIAS5,        .name = "GBIAS5" },
624         { .addr = CC1120_GBIAS4,        .name = "GBIAS4" },
625         { .addr = CC1120_GBIAS3,        .name = "GBIAS3" },
626         { .addr = CC1120_GBIAS2,        .name = "GBIAS2" },
627         { .addr = CC1120_GBIAS1,        .name = "GBIAS1" },
628         { .addr = CC1120_GBIAS0,        .name = "GBIAS0" },
629         { .addr = CC1120_IFAMP, .name = "IFAMP" },
630         { .addr = CC1120_LNA,   .name = "LNA" },
631         { .addr = CC1120_RXMIX, .name = "RXMIX" },
632         { .addr = CC1120_XOSC5, .name = "XOSC5" },
633         { .addr = CC1120_XOSC4, .name = "XOSC4" },
634         { .addr = CC1120_XOSC3, .name = "XOSC3" },
635         { .addr = CC1120_XOSC2, .name = "XOSC2" },
636         { .addr = CC1120_XOSC1, .name = "XOSC1" },
637         { .addr = CC1120_XOSC0, .name = "XOSC0" },
638         { .addr = CC1120_ANALOG_SPARE,  .name = "ANALOG_SPARE" },
639         { .addr = CC1120_PA_CFG3,       .name = "PA_CFG3" },
640         { .addr = CC1120_WOR_TIME1,     .name = "WOR_TIME1" },
641         { .addr = CC1120_WOR_TIME0,     .name = "WOR_TIME0" },
642         { .addr = CC1120_WOR_CAPTURE1,  .name = "WOR_CAPTURE1" },
643         { .addr = CC1120_WOR_CAPTURE0,  .name = "WOR_CAPTURE0" },
644         { .addr = CC1120_BIST,  .name = "BIST" },
645         { .addr = CC1120_DCFILTOFFSET_I1,       .name = "DCFILTOFFSET_I1" },
646         { .addr = CC1120_DCFILTOFFSET_I0,       .name = "DCFILTOFFSET_I0" },
647         { .addr = CC1120_DCFILTOFFSET_Q1,       .name = "DCFILTOFFSET_Q1" },
648         { .addr = CC1120_DCFILTOFFSET_Q0,       .name = "DCFILTOFFSET_Q0" },
649         { .addr = CC1120_IQIE_I1,       .name = "IQIE_I1" },
650         { .addr = CC1120_IQIE_I0,       .name = "IQIE_I0" },
651         { .addr = CC1120_IQIE_Q1,       .name = "IQIE_Q1" },
652         { .addr = CC1120_IQIE_Q0,       .name = "IQIE_Q0" },
653         { .addr = CC1120_RSSI1, .name = "RSSI1" },
654         { .addr = CC1120_RSSI0, .name = "RSSI0" },
655         { .addr = CC1120_MARCSTATE,     .name = "MARCSTATE" },
656         { .addr = CC1120_LQI_VAL,       .name = "LQI_VAL" },
657         { .addr = CC1120_PQT_SYNC_ERR,  .name = "PQT_SYNC_ERR" },
658         { .addr = CC1120_DEM_STATUS,    .name = "DEM_STATUS" },
659         { .addr = CC1120_FREQOFF_EST1,  .name = "FREQOFF_EST1" },
660         { .addr = CC1120_FREQOFF_EST0,  .name = "FREQOFF_EST0" },
661         { .addr = CC1120_AGC_GAIN3,     .name = "AGC_GAIN3" },
662         { .addr = CC1120_AGC_GAIN2,     .name = "AGC_GAIN2" },
663         { .addr = CC1120_AGC_GAIN1,     .name = "AGC_GAIN1" },
664         { .addr = CC1120_AGC_GAIN0,     .name = "AGC_GAIN0" },
665         { .addr = CC1120_SOFT_RX_DATA_OUT,      .name = "SOFT_RX_DATA_OUT" },
666         { .addr = CC1120_SOFT_TX_DATA_IN,       .name = "SOFT_TX_DATA_IN" },
667         { .addr = CC1120_ASK_SOFT_RX_DATA,      .name = "ASK_SOFT_RX_DATA" },
668         { .addr = CC1120_RNDGEN,        .name = "RNDGEN" },
669         { .addr = CC1120_MAGN2, .name = "MAGN2" },
670         { .addr = CC1120_MAGN1, .name = "MAGN1" },
671         { .addr = CC1120_MAGN0, .name = "MAGN0" },
672         { .addr = CC1120_ANG1,  .name = "ANG1" },
673         { .addr = CC1120_ANG0,  .name = "ANG0" },
674         { .addr = CC1120_CHFILT_I2,     .name = "CHFILT_I2" },
675         { .addr = CC1120_CHFILT_I1,     .name = "CHFILT_I1" },
676         { .addr = CC1120_CHFILT_I0,     .name = "CHFILT_I0" },
677         { .addr = CC1120_CHFILT_Q2,     .name = "CHFILT_Q2" },
678         { .addr = CC1120_CHFILT_Q1,     .name = "CHFILT_Q1" },
679         { .addr = CC1120_CHFILT_Q0,     .name = "CHFILT_Q0" },
680         { .addr = CC1120_GPIO_STATUS,   .name = "GPIO_STATUS" },
681         { .addr = CC1120_FSCAL_CTRL,    .name = "FSCAL_CTRL" },
682         { .addr = CC1120_PHASE_ADJUST,  .name = "PHASE_ADJUST" },
683         { .addr = CC1120_PARTNUMBER,    .name = "PARTNUMBER" },
684         { .addr = CC1120_PARTVERSION,   .name = "PARTVERSION" },
685         { .addr = CC1120_SERIAL_STATUS, .name = "SERIAL_STATUS" },
686         { .addr = CC1120_RX_STATUS,     .name = "RX_STATUS" },
687         { .addr = CC1120_TX_STATUS,     .name = "TX_STATUS" },
688         { .addr = CC1120_MARC_STATUS1,  .name = "MARC_STATUS1" },
689         { .addr = CC1120_MARC_STATUS0,  .name = "MARC_STATUS0" },
690         { .addr = CC1120_PA_IFAMP_TEST, .name = "PA_IFAMP_TEST" },
691         { .addr = CC1120_FSRF_TEST,     .name = "FSRF_TEST" },
692         { .addr = CC1120_PRE_TEST,      .name = "PRE_TEST" },
693         { .addr = CC1120_PRE_OVR,       .name = "PRE_OVR" },
694         { .addr = CC1120_ADC_TEST,      .name = "ADC_TEST" },
695         { .addr = CC1120_DVC_TEST,      .name = "DVC_TEST" },
696         { .addr = CC1120_ATEST, .name = "ATEST" },
697         { .addr = CC1120_ATEST_LVDS,    .name = "ATEST_LVDS" },
698         { .addr = CC1120_ATEST_MODE,    .name = "ATEST_MODE" },
699         { .addr = CC1120_XOSC_TEST1,    .name = "XOSC_TEST1" },
700         { .addr = CC1120_XOSC_TEST0,    .name = "XOSC_TEST0" },
701         { .addr = CC1120_RXFIRST,       .name = "RXFIRST" },
702         { .addr = CC1120_TXFIRST,       .name = "TXFIRST" },
703         { .addr = CC1120_RXLAST,        .name = "RXLAST" },
704         { .addr = CC1120_TXLAST,        .name = "TXLAST" },
705         { .addr = CC1120_NUM_TXBYTES,   .name = "NUM_TXBYTES" },
706         { .addr = CC1120_NUM_RXBYTES,   .name = "NUM_RXBYTES" },
707         { .addr = CC1120_FIFO_NUM_TXBYTES,      .name = "FIFO_NUM_TXBYTES" },
708         { .addr = CC1120_FIFO_NUM_RXBYTES,      .name = "FIFO_NUM_RXBYTES" },
709 };
710
711 #define AO_NUM_CC1120_REG       (sizeof ao_cc1120_reg / sizeof ao_cc1120_reg[0])
712
713 static void ao_radio_show(void) {
714         uint8_t status = ao_radio_status();
715         int     i;
716
717         ao_radio_get(0xff);
718         status = ao_radio_status();
719         printf ("Status:   %02x\n", status);
720         printf ("CHIP_RDY: %d\n", (status >> CC1120_STATUS_CHIP_RDY) & 1);
721         printf ("STATE:    %s\n", cc1120_state_name[(status >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK]);
722         printf ("MARC:     %02x\n", ao_radio_marc_status());
723
724         for (i = 0; i < AO_NUM_CC1120_REG; i++)
725                 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name);
726         ao_radio_put();
727 }
728
729 static void ao_radio_beep(void) {
730         ao_radio_rdf(RDF_PACKET_LEN);
731 }
732
733 static void ao_radio_packet(void) {
734         static uint8_t packet[] = {
735 #if 1
736                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
737                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
738                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
739                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
740 #else
741                 3, 1, 2, 3
742 #endif
743         };
744
745         ao_radio_send(packet, sizeof (packet));
746 }
747
748 #endif
749
750 static const struct ao_cmds ao_radio_cmds[] = {
751         { ao_radio_test,        "C <1 start, 0 stop, none both>\0Radio carrier test" },
752 #if CC1120_DEBUG
753         { ao_radio_show,        "R\0Show CC1120 status" },
754         { ao_radio_beep,        "b\0Emit an RDF beacon" },
755         { ao_radio_packet,      "p\0Send a test packet" },
756 #endif
757         { 0, NULL }
758 };
759
760 void
761 ao_radio_init(void)
762 {
763         int     i;
764
765         ao_radio_configured = 0;
766         ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN));
767
768         AO_CC1120_SPI_CS_PORT.bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));
769         for (i = 0; i < 10000; i++) {
770                 if ((SPI_2_GPIO.idr & (1 << SPI_2_MISO)) == 0)
771                         break;
772         }
773         AO_CC1120_SPI_CS_PORT.bsrr = (1 << AO_CC1120_SPI_CS_PIN);
774         if (i == 10000)
775                 ao_panic(AO_PANIC_SELF_TEST);
776
777         /* Enable the EXTI interrupt for the appropriate pin */
778         ao_enable_port(AO_CC1120_INT_PORT);
779         ao_exti_setup(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, AO_EXTI_MODE_FALLING, ao_radio_isr);
780
781         ao_cmd_register(&ao_radio_cmds[0]);
782 }