altos: Incremental viterbi decode
[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_consumed;
404 static uint16_t rx_data_cur;
405 static uint8_t  rx_ignore;
406
407 static void
408 ao_radio_rx_isr(void)
409 {
410         if (rx_ignore == 0) {
411                 rx_data[rx_data_cur++] = stm_spi2.dr;
412                 if (rx_data_cur >= rx_data_count)
413                         ao_exti_disable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
414                 if (rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) {
415                         ao_wakeup(&ao_radio_wake);
416                 }
417         } else {
418                 (void) stm_spi2.dr;
419                 --rx_ignore;
420         }
421         stm_spi2.dr = 0x00;
422 }
423
424 static uint16_t
425 ao_radio_rx_wait(void)
426 {
427         cli();
428         while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
429                !ao_radio_abort)
430                 ao_sleep(&ao_radio_wake);
431         sei();
432         if (ao_radio_abort)
433                 return 0;
434         return AO_FEC_DECODE_BLOCK;
435 }
436
437 uint8_t
438 ao_radio_recv(__xdata void *d, uint8_t size)
439 {
440         uint8_t         len;
441         uint16_t        i;
442         uint8_t         rssi;
443
444         size -= 2;                      /* status bytes */
445         len = size + 2;                 /* CRC bytes */
446         len += 1 + ~(len & 1);          /* 1 or two pad bytes */
447         len *= 2;                       /* 1/2 rate convolution */
448         rx_data_count = len * 8;        /* bytes to bits */
449         rx_data_cur = 0;
450         rx_data_consumed = 0;
451         rx_ignore = 2;
452
453         printf ("len %d rx_data_count %d\n", len, rx_data_count);
454
455         /* configure interrupt pin */
456         ao_radio_get(len);
457         ao_radio_wake = 0;
458         ao_radio_abort = 0;
459
460         ao_radio_reg_write(CC1120_PKT_CFG2,
461                            (CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
462                            (CC1120_PKT_CFG2_PKT_FORMAT_SYNCHRONOUS_SERIAL << CC1120_PKT_CFG2_PKT_FORMAT));
463
464         ao_radio_reg_write(CC1120_EXT_CTRL, 0);
465
466         ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT);
467
468         stm_spi2.cr2 = 0;
469
470         /* clear any RXNE */
471         (void) stm_spi2.dr;
472
473         ao_exti_set_callback(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
474         ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
475
476         ao_radio_strobe(CC1120_SRX);
477
478         ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
479
480         ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);
481
482         ao_radio_burst_read_stop();
483
484         /* Convert from 'real' rssi to cc1111-style values */
485
486         rssi = (((int8_t) ao_radio_reg_read(CC1120_RSSI1)) + 74) * 2;
487
488         ao_radio_strobe(CC1120_SIDLE);
489
490         ao_radio_put();
491
492         /* Construct final packet */
493
494         ao_fec_decode(rx_data, rx_data_cur, d, size + 2, 0);
495
496         if (ao_fec_check_crc(d, size))
497                 ((uint8_t *) d)[size + 1] = 0x80;
498         else
499                 ((uint8_t *) d)[size + 1] = 0x00;
500
501         ((uint8_t *) d)[size] = (uint8_t) rssi;
502
503         return 1;
504 }
505
506 /*
507  * Packet deviation is 20.5kHz
508  *
509  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
510  *
511  *      32e6Hz / (2 ** 24) * (256 + 80) * (2 ** 5) = 20508Hz
512  */
513
514 #define PACKET_DEV_E    5
515 #define PACKET_DEV_M    80
516
517 /*
518  * For our packet data, set the symbol rate to 38360 Baud
519  *
520  *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
521  *      Rdata = -------------------------------------- * fosc
522  *                           2 ** 39
523  *
524  *
525  *      DATARATE_M = 239914
526  *      DATARATE_E = 9
527  */
528 #define PACKET_DRATE_E  9
529 #define PACKET_DRATE_M  239914
530
531 static const uint16_t packet_setup[] = {
532         CC1120_DEVIATION_M,     PACKET_DEV_M,
533         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
534                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
535                                  (PACKET_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
536         CC1120_DRATE2,          ((PACKET_DRATE_E << CC1120_DRATE2_DATARATE_E) |
537                                  (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
538         CC1120_DRATE1,          ((PACKET_DRATE_M >> 8) & 0xff),
539         CC1120_DRATE0,          ((PACKET_DRATE_M >> 0) & 0xff),
540         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
541                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
542         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
543                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
544                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
545                                  (1 << CC1120_PKT_CFG1_APPEND_STATUS)),
546         CC1120_PKT_CFG0,        ((0 << CC1120_PKT_CFG0_RESERVED7) |
547                                  (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
548                                  (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
549                                  (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
550                                  (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
551 };
552
553 void
554 ao_radio_set_packet(void)
555 {
556         int i;
557
558         for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
559                 ao_radio_reg_write(packet_setup[i], packet_setup[i+1]);
560 }
561
562 void
563 ao_radio_idle(void)
564 {
565         for (;;) {
566                 uint8_t state = ao_radio_strobe(CC1120_SIDLE);
567                 if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_IDLE)
568                         break;
569         }
570         ao_radio_strobe(CC1120_SFTX);
571         ao_radio_strobe(CC1120_SFRX);
572 }
573
574 static const uint16_t radio_setup[] = {
575 #include "ao_cc1120_CC1120.h"
576 };
577
578 static uint8_t  ao_radio_configured = 0;
579
580
581 static void
582 ao_radio_setup(void)
583 {
584         int     i;
585
586         ao_radio_strobe(CC1120_SRES);
587
588         for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
589                 ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
590
591         ao_radio_set_packet();
592
593         ao_config_get();
594
595         ao_radio_configured = 1;
596 }
597
598 void
599 ao_radio_get(uint8_t len)
600 {
601         ao_mutex_get(&ao_radio_mutex);
602         if (!ao_radio_configured)
603                 ao_radio_setup();
604         ao_radio_reg_write(CC1120_FREQ2, ao_config.radio_setting >> 16);
605         ao_radio_reg_write(CC1120_FREQ1, ao_config.radio_setting >> 8);
606         ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting);
607         ao_radio_reg_write(CC1120_PKT_LEN, len);
608 }
609
610 #if CC1120_DEBUG
611 static char *cc1120_state_name[] = {
612         [CC1120_STATUS_STATE_IDLE] = "IDLE",
613         [CC1120_STATUS_STATE_RX] = "RX",
614         [CC1120_STATUS_STATE_TX] = "TX",
615         [CC1120_STATUS_STATE_FSTXON] = "FSTXON",
616         [CC1120_STATUS_STATE_CALIBRATE] = "CALIBRATE",
617         [CC1120_STATUS_STATE_SETTLING] = "SETTLING",
618         [CC1120_STATUS_STATE_RX_FIFO_ERROR] = "RX_FIFO_ERROR",
619         [CC1120_STATUS_STATE_TX_FIFO_ERROR] = "TX_FIFO_ERROR",
620 };
621
622 struct ao_cc1120_reg {
623         uint16_t        addr;
624         char            *name;
625 };
626
627 const static struct ao_cc1120_reg ao_cc1120_reg[] = {
628         { .addr = CC1120_IOCFG3,        .name = "IOCFG3" },
629         { .addr = CC1120_IOCFG2,        .name = "IOCFG2" },
630         { .addr = CC1120_IOCFG1,        .name = "IOCFG1" },
631         { .addr = CC1120_IOCFG0,        .name = "IOCFG0" },
632         { .addr = CC1120_SYNC3, .name = "SYNC3" },
633         { .addr = CC1120_SYNC2, .name = "SYNC2" },
634         { .addr = CC1120_SYNC1, .name = "SYNC1" },
635         { .addr = CC1120_SYNC0, .name = "SYNC0" },
636         { .addr = CC1120_SYNC_CFG1,     .name = "SYNC_CFG1" },
637         { .addr = CC1120_SYNC_CFG0,     .name = "SYNC_CFG0" },
638         { .addr = CC1120_DEVIATION_M,   .name = "DEVIATION_M" },
639         { .addr = CC1120_MODCFG_DEV_E,  .name = "MODCFG_DEV_E" },
640         { .addr = CC1120_DCFILT_CFG,    .name = "DCFILT_CFG" },
641         { .addr = CC1120_PREAMBLE_CFG1, .name = "PREAMBLE_CFG1" },
642         { .addr = CC1120_PREAMBLE_CFG0, .name = "PREAMBLE_CFG0" },
643         { .addr = CC1120_FREQ_IF_CFG,   .name = "FREQ_IF_CFG" },
644         { .addr = CC1120_IQIC,  .name = "IQIC" },
645         { .addr = CC1120_CHAN_BW,       .name = "CHAN_BW" },
646         { .addr = CC1120_MDMCFG1,       .name = "MDMCFG1" },
647         { .addr = CC1120_MDMCFG0,       .name = "MDMCFG0" },
648         { .addr = CC1120_DRATE2,        .name = "DRATE2" },
649         { .addr = CC1120_DRATE1,        .name = "DRATE1" },
650         { .addr = CC1120_DRATE0,        .name = "DRATE0" },
651         { .addr = CC1120_AGC_REF,       .name = "AGC_REF" },
652         { .addr = CC1120_AGC_CS_THR,    .name = "AGC_CS_THR" },
653         { .addr = CC1120_AGC_GAIN_ADJUST,       .name = "AGC_GAIN_ADJUST" },
654         { .addr = CC1120_AGC_CFG3,      .name = "AGC_CFG3" },
655         { .addr = CC1120_AGC_CFG2,      .name = "AGC_CFG2" },
656         { .addr = CC1120_AGC_CFG1,      .name = "AGC_CFG1" },
657         { .addr = CC1120_AGC_CFG0,      .name = "AGC_CFG0" },
658         { .addr = CC1120_FIFO_CFG,      .name = "FIFO_CFG" },
659         { .addr = CC1120_DEV_ADDR,      .name = "DEV_ADDR" },
660         { .addr = CC1120_SETTLING_CFG,  .name = "SETTLING_CFG" },
661         { .addr = CC1120_FS_CFG,        .name = "FS_CFG" },
662         { .addr = CC1120_WOR_CFG1,      .name = "WOR_CFG1" },
663         { .addr = CC1120_WOR_CFG0,      .name = "WOR_CFG0" },
664         { .addr = CC1120_WOR_EVENT0_MSB,        .name = "WOR_EVENT0_MSB" },
665         { .addr = CC1120_WOR_EVENT0_LSB,        .name = "WOR_EVENT0_LSB" },
666         { .addr = CC1120_PKT_CFG2,      .name = "PKT_CFG2" },
667         { .addr = CC1120_PKT_CFG1,      .name = "PKT_CFG1" },
668         { .addr = CC1120_PKT_CFG0,      .name = "PKT_CFG0" },
669         { .addr = CC1120_RFEND_CFG1,    .name = "RFEND_CFG1" },
670         { .addr = CC1120_RFEND_CFG0,    .name = "RFEND_CFG0" },
671         { .addr = CC1120_PA_CFG2,       .name = "PA_CFG2" },
672         { .addr = CC1120_PA_CFG1,       .name = "PA_CFG1" },
673         { .addr = CC1120_PA_CFG0,       .name = "PA_CFG0" },
674         { .addr = CC1120_PKT_LEN,       .name = "PKT_LEN" },
675         { .addr = CC1120_IF_MIX_CFG,    .name = "IF_MIX_CFG" },
676         { .addr = CC1120_FREQOFF_CFG,   .name = "FREQOFF_CFG" },
677         { .addr = CC1120_TOC_CFG,       .name = "TOC_CFG" },
678         { .addr = CC1120_MARC_SPARE,    .name = "MARC_SPARE" },
679         { .addr = CC1120_ECG_CFG,       .name = "ECG_CFG" },
680         { .addr = CC1120_SOFT_TX_DATA_CFG,      .name = "SOFT_TX_DATA_CFG" },
681         { .addr = CC1120_EXT_CTRL,      .name = "EXT_CTRL" },
682         { .addr = CC1120_RCCAL_FINE,    .name = "RCCAL_FINE" },
683         { .addr = CC1120_RCCAL_COARSE,  .name = "RCCAL_COARSE" },
684         { .addr = CC1120_RCCAL_OFFSET,  .name = "RCCAL_OFFSET" },
685         { .addr = CC1120_FREQOFF1,      .name = "FREQOFF1" },
686         { .addr = CC1120_FREQOFF0,      .name = "FREQOFF0" },
687         { .addr = CC1120_FREQ2, .name = "FREQ2" },
688         { .addr = CC1120_FREQ1, .name = "FREQ1" },
689         { .addr = CC1120_FREQ0, .name = "FREQ0" },
690         { .addr = CC1120_IF_ADC2,       .name = "IF_ADC2" },
691         { .addr = CC1120_IF_ADC1,       .name = "IF_ADC1" },
692         { .addr = CC1120_IF_ADC0,       .name = "IF_ADC0" },
693         { .addr = CC1120_FS_DIG1,       .name = "FS_DIG1" },
694         { .addr = CC1120_FS_DIG0,       .name = "FS_DIG0" },
695         { .addr = CC1120_FS_CAL3,       .name = "FS_CAL3" },
696         { .addr = CC1120_FS_CAL2,       .name = "FS_CAL2" },
697         { .addr = CC1120_FS_CAL1,       .name = "FS_CAL1" },
698         { .addr = CC1120_FS_CAL0,       .name = "FS_CAL0" },
699         { .addr = CC1120_FS_CHP,        .name = "FS_CHP" },
700         { .addr = CC1120_FS_DIVTWO,     .name = "FS_DIVTWO" },
701         { .addr = CC1120_FS_DSM1,       .name = "FS_DSM1" },
702         { .addr = CC1120_FS_DSM0,       .name = "FS_DSM0" },
703         { .addr = CC1120_FS_DVC1,       .name = "FS_DVC1" },
704         { .addr = CC1120_FS_DVC0,       .name = "FS_DVC0" },
705         { .addr = CC1120_FS_LBI,        .name = "FS_LBI" },
706         { .addr = CC1120_FS_PFD,        .name = "FS_PFD" },
707         { .addr = CC1120_FS_PRE,        .name = "FS_PRE" },
708         { .addr = CC1120_FS_REG_DIV_CML,        .name = "FS_REG_DIV_CML" },
709         { .addr = CC1120_FS_SPARE,      .name = "FS_SPARE" },
710         { .addr = CC1120_FS_VCO4,       .name = "FS_VCO4" },
711         { .addr = CC1120_FS_VCO3,       .name = "FS_VCO3" },
712         { .addr = CC1120_FS_VCO2,       .name = "FS_VCO2" },
713         { .addr = CC1120_FS_VCO1,       .name = "FS_VCO1" },
714         { .addr = CC1120_FS_VCO0,       .name = "FS_VCO0" },
715         { .addr = CC1120_GBIAS6,        .name = "GBIAS6" },
716         { .addr = CC1120_GBIAS5,        .name = "GBIAS5" },
717         { .addr = CC1120_GBIAS4,        .name = "GBIAS4" },
718         { .addr = CC1120_GBIAS3,        .name = "GBIAS3" },
719         { .addr = CC1120_GBIAS2,        .name = "GBIAS2" },
720         { .addr = CC1120_GBIAS1,        .name = "GBIAS1" },
721         { .addr = CC1120_GBIAS0,        .name = "GBIAS0" },
722         { .addr = CC1120_IFAMP, .name = "IFAMP" },
723         { .addr = CC1120_LNA,   .name = "LNA" },
724         { .addr = CC1120_RXMIX, .name = "RXMIX" },
725         { .addr = CC1120_XOSC5, .name = "XOSC5" },
726         { .addr = CC1120_XOSC4, .name = "XOSC4" },
727         { .addr = CC1120_XOSC3, .name = "XOSC3" },
728         { .addr = CC1120_XOSC2, .name = "XOSC2" },
729         { .addr = CC1120_XOSC1, .name = "XOSC1" },
730         { .addr = CC1120_XOSC0, .name = "XOSC0" },
731         { .addr = CC1120_ANALOG_SPARE,  .name = "ANALOG_SPARE" },
732         { .addr = CC1120_PA_CFG3,       .name = "PA_CFG3" },
733         { .addr = CC1120_WOR_TIME1,     .name = "WOR_TIME1" },
734         { .addr = CC1120_WOR_TIME0,     .name = "WOR_TIME0" },
735         { .addr = CC1120_WOR_CAPTURE1,  .name = "WOR_CAPTURE1" },
736         { .addr = CC1120_WOR_CAPTURE0,  .name = "WOR_CAPTURE0" },
737         { .addr = CC1120_BIST,  .name = "BIST" },
738         { .addr = CC1120_DCFILTOFFSET_I1,       .name = "DCFILTOFFSET_I1" },
739         { .addr = CC1120_DCFILTOFFSET_I0,       .name = "DCFILTOFFSET_I0" },
740         { .addr = CC1120_DCFILTOFFSET_Q1,       .name = "DCFILTOFFSET_Q1" },
741         { .addr = CC1120_DCFILTOFFSET_Q0,       .name = "DCFILTOFFSET_Q0" },
742         { .addr = CC1120_IQIE_I1,       .name = "IQIE_I1" },
743         { .addr = CC1120_IQIE_I0,       .name = "IQIE_I0" },
744         { .addr = CC1120_IQIE_Q1,       .name = "IQIE_Q1" },
745         { .addr = CC1120_IQIE_Q0,       .name = "IQIE_Q0" },
746         { .addr = CC1120_RSSI1, .name = "RSSI1" },
747         { .addr = CC1120_RSSI0, .name = "RSSI0" },
748         { .addr = CC1120_MARCSTATE,     .name = "MARCSTATE" },
749         { .addr = CC1120_LQI_VAL,       .name = "LQI_VAL" },
750         { .addr = CC1120_PQT_SYNC_ERR,  .name = "PQT_SYNC_ERR" },
751         { .addr = CC1120_DEM_STATUS,    .name = "DEM_STATUS" },
752         { .addr = CC1120_FREQOFF_EST1,  .name = "FREQOFF_EST1" },
753         { .addr = CC1120_FREQOFF_EST0,  .name = "FREQOFF_EST0" },
754         { .addr = CC1120_AGC_GAIN3,     .name = "AGC_GAIN3" },
755         { .addr = CC1120_AGC_GAIN2,     .name = "AGC_GAIN2" },
756         { .addr = CC1120_AGC_GAIN1,     .name = "AGC_GAIN1" },
757         { .addr = CC1120_AGC_GAIN0,     .name = "AGC_GAIN0" },
758         { .addr = CC1120_SOFT_RX_DATA_OUT,      .name = "SOFT_RX_DATA_OUT" },
759         { .addr = CC1120_SOFT_TX_DATA_IN,       .name = "SOFT_TX_DATA_IN" },
760         { .addr = CC1120_ASK_SOFT_RX_DATA,      .name = "ASK_SOFT_RX_DATA" },
761         { .addr = CC1120_RNDGEN,        .name = "RNDGEN" },
762         { .addr = CC1120_MAGN2, .name = "MAGN2" },
763         { .addr = CC1120_MAGN1, .name = "MAGN1" },
764         { .addr = CC1120_MAGN0, .name = "MAGN0" },
765         { .addr = CC1120_ANG1,  .name = "ANG1" },
766         { .addr = CC1120_ANG0,  .name = "ANG0" },
767         { .addr = CC1120_CHFILT_I2,     .name = "CHFILT_I2" },
768         { .addr = CC1120_CHFILT_I1,     .name = "CHFILT_I1" },
769         { .addr = CC1120_CHFILT_I0,     .name = "CHFILT_I0" },
770         { .addr = CC1120_CHFILT_Q2,     .name = "CHFILT_Q2" },
771         { .addr = CC1120_CHFILT_Q1,     .name = "CHFILT_Q1" },
772         { .addr = CC1120_CHFILT_Q0,     .name = "CHFILT_Q0" },
773         { .addr = CC1120_GPIO_STATUS,   .name = "GPIO_STATUS" },
774         { .addr = CC1120_FSCAL_CTRL,    .name = "FSCAL_CTRL" },
775         { .addr = CC1120_PHASE_ADJUST,  .name = "PHASE_ADJUST" },
776         { .addr = CC1120_PARTNUMBER,    .name = "PARTNUMBER" },
777         { .addr = CC1120_PARTVERSION,   .name = "PARTVERSION" },
778         { .addr = CC1120_SERIAL_STATUS, .name = "SERIAL_STATUS" },
779         { .addr = CC1120_RX_STATUS,     .name = "RX_STATUS" },
780         { .addr = CC1120_TX_STATUS,     .name = "TX_STATUS" },
781         { .addr = CC1120_MARC_STATUS1,  .name = "MARC_STATUS1" },
782         { .addr = CC1120_MARC_STATUS0,  .name = "MARC_STATUS0" },
783         { .addr = CC1120_PA_IFAMP_TEST, .name = "PA_IFAMP_TEST" },
784         { .addr = CC1120_FSRF_TEST,     .name = "FSRF_TEST" },
785         { .addr = CC1120_PRE_TEST,      .name = "PRE_TEST" },
786         { .addr = CC1120_PRE_OVR,       .name = "PRE_OVR" },
787         { .addr = CC1120_ADC_TEST,      .name = "ADC_TEST" },
788         { .addr = CC1120_DVC_TEST,      .name = "DVC_TEST" },
789         { .addr = CC1120_ATEST, .name = "ATEST" },
790         { .addr = CC1120_ATEST_LVDS,    .name = "ATEST_LVDS" },
791         { .addr = CC1120_ATEST_MODE,    .name = "ATEST_MODE" },
792         { .addr = CC1120_XOSC_TEST1,    .name = "XOSC_TEST1" },
793         { .addr = CC1120_XOSC_TEST0,    .name = "XOSC_TEST0" },
794         { .addr = CC1120_RXFIRST,       .name = "RXFIRST" },
795         { .addr = CC1120_TXFIRST,       .name = "TXFIRST" },
796         { .addr = CC1120_RXLAST,        .name = "RXLAST" },
797         { .addr = CC1120_TXLAST,        .name = "TXLAST" },
798         { .addr = CC1120_NUM_TXBYTES,   .name = "NUM_TXBYTES" },
799         { .addr = CC1120_NUM_RXBYTES,   .name = "NUM_RXBYTES" },
800         { .addr = CC1120_FIFO_NUM_TXBYTES,      .name = "FIFO_NUM_TXBYTES" },
801         { .addr = CC1120_FIFO_NUM_RXBYTES,      .name = "FIFO_NUM_RXBYTES" },
802 };
803
804 #define AO_NUM_CC1120_REG       (sizeof ao_cc1120_reg / sizeof ao_cc1120_reg[0])
805
806 static void ao_radio_show(void) {
807         uint8_t status = ao_radio_status();
808         int     i;
809
810         ao_radio_get(0xff);
811         status = ao_radio_status();
812         printf ("Status:   %02x\n", status);
813         printf ("CHIP_RDY: %d\n", (status >> CC1120_STATUS_CHIP_RDY) & 1);
814         printf ("STATE:    %s\n", cc1120_state_name[(status >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK]);
815         printf ("MARC:     %02x\n", ao_radio_marc_status());
816
817         for (i = 0; i < AO_NUM_CC1120_REG; i++)
818                 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name);
819         ao_radio_put();
820 }
821
822 static void ao_radio_beep(void) {
823         ao_radio_rdf(RDF_PACKET_LEN);
824 }
825
826 static void ao_radio_packet(void) {
827         static uint8_t packet[] = {
828 #if 1
829                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
830                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
831                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
832                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
833 #else
834                 3, 1, 2, 3
835 #endif
836         };
837
838         ao_radio_send(packet, sizeof (packet));
839 }
840
841 void
842 ao_radio_test_recv()
843 {
844         ao_radio_recv(0, 34);
845 }
846
847 #endif
848
849 static const struct ao_cmds ao_radio_cmds[] = {
850         { ao_radio_test,        "C <1 start, 0 stop, none both>\0Radio carrier test" },
851 #if CC1120_DEBUG
852         { ao_radio_show,        "R\0Show CC1120 status" },
853         { ao_radio_beep,        "b\0Emit an RDF beacon" },
854         { ao_radio_packet,      "p\0Send a test packet" },
855         { ao_radio_test_recv,   "q\0Recv a test packet" },
856 #endif
857         { 0, NULL }
858 };
859
860 void
861 ao_radio_init(void)
862 {
863         int     i;
864
865         ao_radio_configured = 0;
866         ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN));
867
868         AO_CC1120_SPI_CS_PORT.bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));
869         for (i = 0; i < 10000; i++) {
870                 if ((SPI_2_GPIO.idr & (1 << SPI_2_MISO)) == 0)
871                         break;
872         }
873         AO_CC1120_SPI_CS_PORT.bsrr = (1 << AO_CC1120_SPI_CS_PIN);
874         if (i == 10000)
875                 ao_panic(AO_PANIC_SELF_TEST);
876
877         /* Enable the EXTI interrupt for the appropriate pin */
878         ao_enable_port(AO_CC1120_INT_PORT);
879         ao_exti_setup(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, AO_EXTI_MODE_FALLING, ao_radio_tx_isr);
880
881         ao_cmd_register(&ao_radio_cmds[0]);
882 }