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