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