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