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