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