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