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