altoslib: Handle TeleGPS files for KML export
[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 static uint8_t ao_radio_mutex;
28
29 static uint8_t ao_radio_wake;           /* radio ready. Also used as sleep address */
30 static uint8_t ao_radio_abort;          /* radio operation should abort */
31 static uint8_t ao_radio_mcu_wake;       /* MARC status change */
32 static uint8_t ao_radio_marc_status;    /* Last read MARC status value */
33 static uint8_t ao_radio_tx_finished;    /* MARC status indicates TX finished */
34
35 int8_t  ao_radio_rssi;                  /* Last received RSSI value */
36
37 #define CC1120_DEBUG    AO_FEC_DEBUG
38 #define CC1120_TRACE    0
39
40 extern const uint32_t   ao_radio_cal;
41
42 #define FOSC    32000000
43
44 #define ao_radio_try_select(task_id)    ao_spi_try_get_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS,AO_SPI_SPEED_4MHz, task_id)
45 #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_4MHz)
46 #define ao_radio_deselect()     ao_spi_put_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS)
47 #define ao_radio_spi_send_sync(d,l)     ao_spi_send_sync((d), (l), AO_CC1120_SPI_BUS)
48 #define ao_radio_spi_send(d,l)  ao_spi_send((d), (l), AO_CC1120_SPI_BUS)
49 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1120_SPI_BUS)
50 #define ao_radio_spi_recv(d,l)  ao_spi_recv((d), (l), AO_CC1120_SPI_BUS)
51 #define ao_radio_duplex(o,i,l)  ao_spi_duplex((o), (i), (l), AO_CC1120_SPI_BUS)
52
53 static uint8_t
54 ao_radio_reg_read(uint16_t addr)
55 {
56         uint8_t data[2];
57         uint8_t d;
58
59 #if CC1120_TRACE
60         printf("\t\tao_radio_reg_read (%04x): ", addr); flush();
61 #endif
62         if (CC1120_IS_EXTENDED(addr)) {
63                 data[0] = ((1 << CC1120_READ)  |
64                            (0 << CC1120_BURST) |
65                            CC1120_EXTENDED);
66                 data[1] = addr;
67                 d = 2;
68         } else {
69                 data[0] = ((1 << CC1120_READ)  |
70                            (0 << CC1120_BURST) |
71                            addr);
72                 d = 1;
73         }
74         ao_radio_select();
75         ao_radio_spi_send(data, d);
76         ao_radio_spi_recv(data, 1);
77         ao_radio_deselect();
78 #if CC1120_TRACE
79         printf (" %02x\n", data[0]);
80 #endif
81         return data[0];
82 }
83
84 static void
85 ao_radio_reg_write(uint16_t addr, uint8_t value)
86 {
87         uint8_t data[3];
88         uint8_t d;
89
90 #if CC1120_TRACE
91         printf("\t\tao_radio_reg_write (%04x): %02x\n", addr, value);
92 #endif
93         if (CC1120_IS_EXTENDED(addr)) {
94                 data[0] = ((0 << CC1120_READ)  |
95                            (0 << CC1120_BURST) |
96                            CC1120_EXTENDED);
97                 data[1] = addr;
98                 d = 2;
99         } else {
100                 data[0] = ((0 << CC1120_READ)  |
101                            (0 << CC1120_BURST) |
102                            addr);
103                 d = 1;
104         }
105         data[d] = value;
106         ao_radio_select();
107         ao_radio_spi_send(data, d+1);
108         ao_radio_deselect();
109 }
110
111 static void
112 _ao_radio_burst_read_start (uint16_t addr)
113 {
114         uint8_t data[2];
115         uint8_t d;
116
117         if (CC1120_IS_EXTENDED(addr)) {
118                 data[0] = ((1 << CC1120_READ)  |
119                            (1 << CC1120_BURST) |
120                            CC1120_EXTENDED);
121                 data[1] = addr;
122                 d = 2;
123         } else {
124                 data[0] = ((1 << CC1120_READ)  |
125                            (1 << CC1120_BURST) |
126                            addr);
127                 d = 1;
128         }
129
130         ao_radio_spi_send_sync(data, d);
131 }
132
133 static void
134 ao_radio_burst_read_stop (void)
135 {
136         ao_radio_deselect();
137 }
138
139
140 static uint8_t
141 ao_radio_strobe(uint8_t addr)
142 {
143         uint8_t in;
144
145 #if CC1120_TRACE
146         printf("\t\tao_radio_strobe (%02x): ", addr); flush();
147 #endif
148         ao_radio_select();
149         ao_radio_duplex(&addr, &in, 1);
150         ao_radio_deselect();
151 #if CC1120_TRACE
152         printf("%02x\n", in); flush();
153 #endif
154         return in;
155 }
156
157 #if 0
158 static uint8_t
159 ao_radio_fifo_read(uint8_t *data, uint8_t len)
160 {
161         uint8_t addr = ((1 << CC1120_READ)  |
162                         (1 << CC1120_BURST) |
163                         CC1120_FIFO);
164         uint8_t status;
165
166         ao_radio_select();
167         ao_radio_duplex(&addr, &status, 1);
168         ao_radio_spi_recv(data, len);
169         ao_radio_deselect();
170         return status;
171 }
172 #endif
173
174 static uint8_t
175 ao_radio_fifo_write_start(void)
176 {
177         uint8_t addr = ((0 << CC1120_READ)  |
178                         (1 << CC1120_BURST) |
179                         CC1120_FIFO);
180         uint8_t status;
181
182         ao_radio_select();
183         ao_radio_duplex(&addr, &status, 1);
184         return status;
185 }
186
187 static inline uint8_t ao_radio_fifo_write_stop(uint8_t status) {
188         ao_radio_deselect();
189         return status;
190 }
191
192 static uint8_t
193 ao_radio_fifo_write(uint8_t *data, uint8_t len)
194 {
195         uint8_t status = ao_radio_fifo_write_start();
196         ao_radio_spi_send(data, len);
197         return ao_radio_fifo_write_stop(status);
198 }
199
200 static uint8_t
201 ao_radio_fifo_write_fixed(uint8_t data, uint8_t len)
202 {
203         uint8_t status = ao_radio_fifo_write_start();
204         ao_radio_spi_send_fixed(data, len);
205         return ao_radio_fifo_write_stop(status);
206 }
207
208 static uint8_t
209 ao_radio_tx_fifo_space(void)
210 {
211         return CC1120_FIFO_SIZE - ao_radio_reg_read(CC1120_NUM_TXBYTES);
212 }
213
214 #if CC1120_DEBUG
215 static uint8_t
216 ao_radio_status(void)
217 {
218         return ao_radio_strobe (CC1120_SNOP);
219 }
220 #endif
221
222 void
223 ao_radio_recv_abort(void)
224 {
225         ao_radio_abort = 1;
226         ao_wakeup(&ao_radio_wake);
227 }
228
229 #define ao_radio_rdf_value 0x55
230
231 static uint8_t
232 ao_radio_get_marc_status(void)
233 {
234         return ao_radio_reg_read(CC1120_MARC_STATUS1);
235 }
236
237 static void
238 ao_radio_mcu_wakeup_isr(void)
239 {
240         ao_radio_mcu_wake = 1;
241         ao_wakeup(&ao_radio_wake);
242 }
243
244
245 static void
246 ao_radio_check_marc_status(void)
247 {
248         ao_radio_mcu_wake = 0;
249         ao_radio_marc_status = ao_radio_get_marc_status();
250
251         /* Anyt other than 'tx/rx finished' means an error occurred */
252         if (ao_radio_marc_status & ~(CC1120_MARC_STATUS1_TX_FINISHED|CC1120_MARC_STATUS1_RX_FINISHED))
253                 ao_radio_abort = 1;
254         if (ao_radio_marc_status & (CC1120_MARC_STATUS1_TX_FINISHED))
255                 ao_radio_tx_finished = 1;
256 }
257
258 static void
259 ao_radio_isr(void)
260 {
261         ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
262         ao_radio_wake = 1;
263         ao_wakeup(&ao_radio_wake);
264 }
265
266 static void
267 ao_radio_start_tx(void)
268 {
269         ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);
270         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
271         ao_exti_enable(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN);
272         ao_radio_tx_finished = 0;
273         ao_radio_strobe(CC1120_STX);
274 }
275
276 static void
277 ao_radio_idle(void)
278 {
279         for (;;) {
280                 uint8_t state = (ao_radio_strobe(CC1120_SIDLE) >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK;
281                 if (state == CC1120_STATUS_STATE_IDLE)
282                         break;
283                 if (state == CC1120_STATUS_STATE_TX_FIFO_ERROR)
284                         ao_radio_strobe(CC1120_SFTX);
285                 if (state == CC1120_STATUS_STATE_RX_FIFO_ERROR)
286                         ao_radio_strobe(CC1120_SFRX);
287         }
288         /* Flush any pending TX bytes */
289         ao_radio_strobe(CC1120_SFTX);
290 }
291
292 /*
293  * Packet deviation is 20.5kHz
294  *
295  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
296  *
297  *      32e6Hz / (2 ** 24) * (256 + 80) * (2 ** 5) = 20508Hz
298  */
299
300 #define PACKET_DEV_E    5
301 #define PACKET_DEV_M    80
302
303 /*
304  * For our packet data
305  *
306  *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
307  *      Rdata = -------------------------------------- * fosc
308  *                           2 ** 39
309  *
310  * Symbol rate 38400 Baud:
311  *
312  *      DATARATE_M = 239914
313  *      DATARATE_E = 9
314  *      CHANBW = 74.42 (round to 100)
315  *
316  * Symbol rate 9600 Baud:
317  *
318  *      DATARATE_M = 239914
319  *      DATARATE_E = 7
320  *      CHANBW = 58.58 (round to 62.5)
321  *
322  * Symbol rate 2400 Baud:
323  *
324  *      DATARATE_M = 239914
325  *      DATARATE_E = 5
326  *      CHANBW = 47.61 (round to 50)
327  */
328
329 #define PACKET_DRATE_M  239914
330
331 #define PACKET_DRATE_E_384      9
332 #define PACKET_CHAN_BW_384      0x02    /* 200 / 2 = 100 */
333
334 #define PACKET_DRATE_E_96       7
335 #define PACKET_CHAN_BW_96       0x42    /* 125 / 2 = 62.5 */
336
337 #define PACKET_DRATE_E_24       5
338 #define PACKET_CHAN_BW_24       0x04    /* 200 / 4 = 50 */
339
340 static const uint16_t packet_setup[] = {
341         CC1120_DEVIATION_M,     PACKET_DEV_M,
342         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
343                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
344                                  (PACKET_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
345         CC1120_DRATE1,          ((PACKET_DRATE_M >> 8) & 0xff),
346         CC1120_DRATE0,          ((PACKET_DRATE_M >> 0) & 0xff),
347         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
348                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
349         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
350                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
351                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
352                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
353         CC1120_PKT_CFG0,        ((0 << CC1120_PKT_CFG0_RESERVED7) |
354                                  (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
355                                  (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
356                                  (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
357                                  (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
358         CC1120_PREAMBLE_CFG1,   ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
359                                  (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
360         AO_CC1120_MARC_GPIO_IOCFG,              CC1120_IOCFG_GPIO_CFG_MARC_MCU_WAKEUP,
361 };
362
363 static const uint16_t packet_setup_384[] = {
364         CC1120_DRATE2,          ((PACKET_DRATE_E_384 << CC1120_DRATE2_DATARATE_E) |
365                                  (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
366         CC1120_CHAN_BW,         PACKET_CHAN_BW_384,
367         CC1120_PA_CFG0,         0x7b,
368 };
369
370 static const uint16_t packet_setup_96[] = {
371         CC1120_DRATE2,          ((PACKET_DRATE_E_96 << CC1120_DRATE2_DATARATE_E) |
372                                  (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
373         CC1120_CHAN_BW,         PACKET_CHAN_BW_96,
374         CC1120_PA_CFG0,         0x7d,
375 };
376
377 static const uint16_t packet_setup_24[] = {
378         CC1120_DRATE2,          ((PACKET_DRATE_E_24 << CC1120_DRATE2_DATARATE_E) |
379                                  (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
380         CC1120_CHAN_BW,         PACKET_CHAN_BW_24,
381         CC1120_PA_CFG0,         0x7e,
382 };
383
384 static const uint16_t packet_tx_setup[] = {
385         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
386                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
387         AO_CC1120_INT_GPIO_IOCFG,               CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG,
388 };
389
390 static const uint16_t packet_rx_setup[] = {
391         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
392                                  (CC1120_PKT_CFG2_PKT_FORMAT_SYNCHRONOUS_SERIAL << CC1120_PKT_CFG2_PKT_FORMAT)),
393         AO_CC1120_INT_GPIO_IOCFG,               CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT,
394 };
395
396 /*
397  * RDF deviation is 5kHz
398  *
399  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
400  *
401  *      32e6Hz / (2 ** 24) * (256 + 71) * (2 ** 3) = 4989
402  */
403
404 #define RDF_DEV_E       3
405 #define RDF_DEV_M       71
406 #define RDF_PACKET_LEN  50
407
408 /*
409  * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
410  *
411  *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
412  *      Rdata = -------------------------------------- * fosc
413  *                           2 ** 39
414  *
415  *      DATARATE_M = 25166
416  *      DATARATE_E = 5
417  *
418  * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes
419  */
420 #define RDF_DRATE_E     5
421 #define RDF_DRATE_M     25166
422 #define RDF_PACKET_LEN  50
423
424 static const uint16_t rdf_setup[] = {
425         CC1120_DEVIATION_M,     RDF_DEV_M,
426         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
427                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
428                                  (RDF_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
429         CC1120_DRATE2,          ((RDF_DRATE_E << CC1120_DRATE2_DATARATE_E) |
430                                  (((RDF_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
431         CC1120_DRATE1,          ((RDF_DRATE_M >> 8) & 0xff),
432         CC1120_DRATE0,          ((RDF_DRATE_M >> 0) & 0xff),
433         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
434                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
435         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
436                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
437                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
438                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
439         CC1120_PKT_CFG0,        ((0 << CC1120_PKT_CFG0_RESERVED7) |
440                                  (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
441                                  (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
442                                  (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
443                                  (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
444         CC1120_PREAMBLE_CFG1,   ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_NONE << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
445                                  (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
446         CC1120_PA_CFG0,         0x7e,
447 };
448
449 /*
450  * APRS deviation is 3kHz
451  *
452  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
453  *
454  *      32e6Hz / (2 ** 24) * (256 + 137) * (2 ** 2) = 2998Hz
455  */
456
457 #define APRS_DEV_E      2
458 #define APRS_DEV_M      137
459
460 /*
461  * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate)
462  *
463  *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
464  *      Rdata = -------------------------------------- * fosc
465  *                           2 ** 39
466  *
467  *      DATARATE_M = 239914
468  *      DATARATE_E = 7
469  *
470  *      Rdata = 9599.998593330383301
471  *
472  */
473 #define APRS_DRATE_E    7
474 #define APRS_DRATE_M    239914
475
476 static const uint16_t aprs_setup[] = {
477         CC1120_DEVIATION_M,     APRS_DEV_M,
478         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
479                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
480                                  (APRS_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
481         CC1120_DRATE2,          ((APRS_DRATE_E << CC1120_DRATE2_DATARATE_E) |
482                                  (((APRS_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
483         CC1120_DRATE1,          ((APRS_DRATE_M >> 8) & 0xff),
484         CC1120_DRATE0,          ((APRS_DRATE_M >> 0) & 0xff),
485         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
486                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
487         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
488                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
489                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
490                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
491         CC1120_PREAMBLE_CFG1,   ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_NONE << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
492                                  (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
493         CC1120_PA_CFG0,         0x7d,
494 };
495
496 /*
497  * For Test mode, we want an unmodulated carrier. To do that, we
498  * set the deviation to zero and enable a preamble so that the radio
499  * turns on before we send any data
500  */
501
502 static const uint16_t test_setup[] = {
503         CC1120_DEVIATION_M,     0,
504         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
505                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
506                                  (0 << CC1120_MODCFG_DEV_E_DEV_E)),
507         CC1120_DRATE2,          ((APRS_DRATE_E << CC1120_DRATE2_DATARATE_E) |
508                                  (((APRS_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
509         CC1120_DRATE1,          ((APRS_DRATE_M >> 8) & 0xff),
510         CC1120_DRATE0,          ((APRS_DRATE_M >> 0) & 0xff),
511         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
512                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
513         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
514                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
515                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
516                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
517         CC1120_PREAMBLE_CFG1,   ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
518                                  (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
519 };
520
521 #define AO_PKT_CFG0_INFINITE ((0 << CC1120_PKT_CFG0_RESERVED7) |        \
522                               (CC1120_PKT_CFG0_LENGTH_CONFIG_INFINITE << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
523                               (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |      \
524                               (0 << CC1120_PKT_CFG0_UART_MODE_EN) |     \
525                               (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
526
527 #define AO_PKT_CFG0_FIXED ((0 << CC1120_PKT_CFG0_RESERVED7) |           \
528                            (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
529                            (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |         \
530                            (0 << CC1120_PKT_CFG0_UART_MODE_EN) |        \
531                            (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
532
533 static uint16_t ao_radio_mode;
534
535 #define AO_RADIO_MODE_BITS_PACKET       1
536 #define AO_RADIO_MODE_BITS_PACKET_TX    2
537 #define AO_RADIO_MODE_BITS_TX_BUF       4
538 #define AO_RADIO_MODE_BITS_TX_FINISH    8
539 #define AO_RADIO_MODE_BITS_PACKET_RX    16
540 #define AO_RADIO_MODE_BITS_RDF          32
541 #define AO_RADIO_MODE_BITS_APRS         64
542 #define AO_RADIO_MODE_BITS_TEST         128
543 #define AO_RADIO_MODE_BITS_INFINITE     256
544 #define AO_RADIO_MODE_BITS_FIXED        512
545
546 #define AO_RADIO_MODE_NONE              0
547 #define AO_RADIO_MODE_PACKET_TX_BUF     (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF)
548 #define AO_RADIO_MODE_PACKET_TX_FINISH  (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_FINISH)
549 #define AO_RADIO_MODE_PACKET_RX         (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_RX)
550 #define AO_RADIO_MODE_RDF               (AO_RADIO_MODE_BITS_RDF | AO_RADIO_MODE_BITS_TX_FINISH)
551 #define AO_RADIO_MODE_APRS_BUF          (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF)
552 #define AO_RADIO_MODE_APRS_LAST_BUF     (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_BUF)
553 #define AO_RADIO_MODE_APRS_FINISH       (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_FINISH)
554 #define AO_RADIO_MODE_TEST              (AO_RADIO_MODE_BITS_TEST | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF)
555
556 static void
557 _ao_radio_set_regs(const uint16_t *regs, int nreg)
558 {
559         int i;
560
561         for (i = 0; i < nreg; i++) {
562                 ao_radio_reg_write(regs[0], regs[1]);
563                 regs += 2;
564         }
565 }
566
567 #define ao_radio_set_regs(setup) _ao_radio_set_regs(setup, (sizeof (setup) / sizeof(setup[0])) >> 1)
568
569 static void
570 ao_radio_set_mode(uint16_t new_mode)
571 {
572         uint16_t changes;
573
574         if (new_mode == ao_radio_mode)
575                 return;
576
577         changes = new_mode & (~ao_radio_mode);
578
579         if (changes & AO_RADIO_MODE_BITS_PACKET) {
580                 ao_radio_set_regs(packet_setup);
581
582                 switch (ao_config.radio_rate) {
583                 default:
584                 case AO_RADIO_RATE_38400:
585                         ao_radio_set_regs(packet_setup_384);
586                         break;
587                 case AO_RADIO_RATE_9600:
588                         ao_radio_set_regs(packet_setup_96);
589                         break;
590                 case AO_RADIO_RATE_2400:
591                         ao_radio_set_regs(packet_setup_24);
592                         break;
593                 }
594         }
595
596         if (changes & AO_RADIO_MODE_BITS_PACKET_TX)
597                 ao_radio_set_regs(packet_tx_setup);
598
599         if (changes & AO_RADIO_MODE_BITS_TX_BUF)
600                 ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_TXFIFO_THR);
601
602         if (changes & AO_RADIO_MODE_BITS_TX_FINISH)
603                 ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);
604
605         if (changes & AO_RADIO_MODE_BITS_PACKET_RX)
606                 ao_radio_set_regs(packet_rx_setup);
607
608         if (changes & AO_RADIO_MODE_BITS_RDF)
609                 ao_radio_set_regs(rdf_setup);
610
611         if (changes & AO_RADIO_MODE_BITS_APRS)
612                 ao_radio_set_regs(aprs_setup);
613
614         if (changes & AO_RADIO_MODE_BITS_TEST)
615                 ao_radio_set_regs(test_setup);
616
617         if (changes & AO_RADIO_MODE_BITS_INFINITE)
618                 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_INFINITE);
619
620         if (changes & AO_RADIO_MODE_BITS_FIXED)
621                 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_FIXED);
622
623         ao_radio_mode = new_mode;
624 }
625
626 static const uint16_t radio_setup[] = {
627 #include "ao_cc1120_CC1120.h"
628 };
629
630 static uint8_t  ao_radio_configured = 0;
631
632 static void
633 ao_radio_setup(void)
634 {
635         ao_radio_strobe(CC1120_SRES);
636
637         ao_radio_set_regs(radio_setup);
638
639         ao_radio_mode = 0;
640
641         ao_config_get();
642
643         ao_radio_configured = 1;
644 }
645
646 static void
647 ao_radio_set_len(uint8_t len)
648 {
649         static uint8_t  last_len;
650
651         if (len != last_len) {
652                 ao_radio_reg_write(CC1120_PKT_LEN, len);
653                 last_len = len;
654         }
655 }
656
657 static void
658 ao_radio_get(uint8_t len)
659 {
660         static uint32_t last_radio_setting;
661         static uint8_t  last_radio_rate;
662
663         ao_mutex_get(&ao_radio_mutex);
664
665         if (!ao_radio_configured)
666                 ao_radio_setup();
667         if (ao_config.radio_setting != last_radio_setting) {
668                 ao_radio_reg_write(CC1120_FREQ2, ao_config.radio_setting >> 16);
669                 ao_radio_reg_write(CC1120_FREQ1, ao_config.radio_setting >> 8);
670                 ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting);
671                 last_radio_setting = ao_config.radio_setting;
672         }
673         if (ao_config.radio_rate != last_radio_rate) {
674                 ao_radio_mode &= ~AO_RADIO_MODE_BITS_PACKET;
675                 last_radio_rate = ao_config.radio_rate;
676         }
677         ao_radio_set_len(len);
678 }
679
680 #define ao_radio_put()  ao_mutex_put(&ao_radio_mutex)
681
682 static void
683 ao_rdf_start(uint8_t len)
684 {
685         ao_radio_abort = 0;
686         ao_radio_get(len);
687
688         ao_radio_set_mode(AO_RADIO_MODE_RDF);
689         ao_radio_wake = 0;
690
691 }
692
693 static void
694 ao_rdf_run(void)
695 {
696         ao_radio_start_tx();
697
698         ao_arch_block_interrupts();
699         while (!ao_radio_wake && !ao_radio_abort && !ao_radio_mcu_wake)
700                 ao_sleep(&ao_radio_wake);
701         ao_arch_release_interrupts();
702         if (ao_radio_mcu_wake)
703                 ao_radio_check_marc_status();
704         if (!ao_radio_wake)
705                 ao_radio_idle();
706         ao_radio_put();
707 }
708
709 void
710 ao_radio_rdf(void)
711 {
712         ao_rdf_start(AO_RADIO_RDF_LEN);
713
714         ao_radio_fifo_write_fixed(ao_radio_rdf_value, AO_RADIO_RDF_LEN);
715
716         ao_rdf_run();
717 }
718
719 void
720 ao_radio_continuity(uint8_t c)
721 {
722         uint8_t i;
723         uint8_t status;
724
725         ao_rdf_start(AO_RADIO_CONT_TOTAL_LEN);
726
727         status = ao_radio_fifo_write_start();
728         for (i = 0; i < 3; i++) {
729                 ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN);
730                 if (i < c)
731                         ao_radio_spi_send_fixed(ao_radio_rdf_value, AO_RADIO_CONT_TONE_LEN);
732                 else
733                         ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_TONE_LEN);
734         }
735         ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN);
736         status = ao_radio_fifo_write_stop(status);
737         (void) status;
738         ao_rdf_run();
739 }
740
741 void
742 ao_radio_rdf_abort(void)
743 {
744         ao_radio_abort = 1;
745         ao_wakeup(&ao_radio_wake);
746 }
747
748 static void
749 ao_radio_test_cmd(void)
750 {
751         uint8_t mode = 2;
752         static uint8_t radio_on;
753         ao_cmd_white();
754         if (ao_cmd_lex_c != '\n') {
755                 ao_cmd_decimal();
756                 mode = (uint8_t) ao_cmd_lex_u32;
757         }
758         mode++;
759         if ((mode & 2) && !radio_on) {
760 #if HAS_MONITOR
761                 ao_monitor_disable();
762 #endif
763 #if PACKET_HAS_SLAVE
764                 ao_packet_slave_stop();
765 #endif
766                 ao_radio_get(0xff);
767                 ao_radio_set_mode(AO_RADIO_MODE_TEST);
768                 ao_radio_strobe(CC1120_STX);
769 #if CC1120_TRACE
770                 { int t;
771                         for (t = 0; t < 10; t++) {
772                                 printf ("status: %02x\n", ao_radio_status());
773                                 ao_delay(AO_MS_TO_TICKS(100));
774                         }
775                 }
776 #endif
777                 radio_on = 1;
778         }
779         if (mode == 3) {
780                 printf ("Hit a character to stop..."); flush();
781                 getchar();
782                 putchar('\n');
783         }
784         if ((mode & 1) && radio_on) {
785                 ao_radio_idle();
786                 ao_radio_put();
787                 radio_on = 0;
788 #if HAS_MONITOR
789                 ao_monitor_enable();
790 #endif
791         }
792 }
793
794 static void
795 ao_radio_wait_isr(uint16_t timeout)
796 {
797         if (timeout)
798                 ao_alarm(timeout);
799         ao_arch_block_interrupts();
800         while (!ao_radio_wake && !ao_radio_mcu_wake && !ao_radio_abort)
801                 if (ao_sleep(&ao_radio_wake))
802                         ao_radio_abort = 1;
803         ao_arch_release_interrupts();
804         if (timeout)
805                 ao_clear_alarm();
806         if (ao_radio_mcu_wake)
807                 ao_radio_check_marc_status();
808 }
809
810 static uint8_t
811 ao_radio_wait_tx(uint8_t wait_fifo)
812 {
813         uint8_t fifo_space = 0;
814
815         do {
816                 ao_radio_wait_isr(0);
817                 if (!wait_fifo)
818                         return 0;
819                 fifo_space = ao_radio_tx_fifo_space();
820         } while (!fifo_space && !ao_radio_abort);
821         return fifo_space;
822 }
823
824 static uint8_t  tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
825
826 void
827 ao_radio_send(const void *d, uint8_t size)
828 {
829         uint8_t         *e = tx_data;
830         uint8_t         encode_len;
831         uint8_t         this_len;
832         uint8_t         started = 0;
833         uint8_t         fifo_space;
834
835         encode_len = ao_fec_encode(d, size, tx_data);
836
837         ao_radio_get(encode_len);
838
839         ao_radio_abort = 0;
840
841         /* Flush any pending TX bytes */
842         ao_radio_strobe(CC1120_SFTX);
843
844         started = 0;
845         fifo_space = CC1120_FIFO_SIZE;
846         while (encode_len) {
847                 this_len = encode_len;
848
849                 ao_radio_wake = 0;
850                 if (this_len > fifo_space) {
851                         this_len = fifo_space;
852                         ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF);
853                 } else {
854                         ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_FINISH);
855                 }
856
857                 ao_radio_fifo_write(e, this_len);
858                 e += this_len;
859                 encode_len -= this_len;
860
861                 if (!started) {
862                         ao_radio_start_tx();
863                         started = 1;
864                 } else {
865                         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
866                 }
867
868                 fifo_space = ao_radio_wait_tx(encode_len != 0);
869                 if (ao_radio_abort) {
870                         ao_radio_idle();
871                         break;
872                 }
873         }
874         while (started && !ao_radio_abort && !ao_radio_tx_finished)
875                 ao_radio_wait_isr(0);
876         ao_radio_put();
877 }
878
879 #define AO_RADIO_LOTS   64
880
881 void
882 ao_radio_send_aprs(ao_radio_fill_func fill)
883 {
884         uint8_t buf[AO_RADIO_LOTS], *b;
885         int     cnt;
886         int     total = 0;
887         uint8_t done = 0;
888         uint8_t started = 0;
889         uint8_t fifo_space;
890
891         ao_radio_get(0xff);
892         fifo_space = CC1120_FIFO_SIZE;
893         while (!done) {
894                 cnt = (*fill)(buf, sizeof(buf));
895                 if (cnt < 0) {
896                         done = 1;
897                         cnt = -cnt;
898                 }
899                 total += cnt;
900
901                 /* At the last buffer, set the total length */
902                 if (done)
903                         ao_radio_set_len(total & 0xff);
904
905                 b = buf;
906                 while (cnt) {
907                         uint8_t this_len = cnt;
908
909                         /* Wait for some space in the fifo */
910                         while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
911                                 ao_radio_wake = 0;
912                                 ao_radio_wait_isr(0);
913                         }
914                         if (ao_radio_abort)
915                                 break;
916                         if (this_len > fifo_space)
917                                 this_len = fifo_space;
918
919                         cnt -= this_len;
920
921                         if (done) {
922                                 if (cnt)
923                                         ao_radio_set_mode(AO_RADIO_MODE_APRS_LAST_BUF);
924                                 else
925                                         ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH);
926                         } else
927                                 ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF);
928
929                         ao_radio_fifo_write(b, this_len);
930                         b += this_len;
931
932                         if (!started) {
933                                 ao_radio_start_tx();
934                                 started = 1;
935                         } else
936                                 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
937                 }
938                 if (ao_radio_abort) {
939                         ao_radio_idle();
940                         break;
941                 }
942                 /* Wait for the transmitter to go idle */
943                 ao_radio_wake = 0;
944                 ao_radio_wait_isr(0);
945         }
946         ao_radio_put();
947 }
948
949 static uint8_t  rx_data[(AO_RADIO_MAX_RECV + 4) * 2 * 8];
950 static uint16_t rx_data_count;
951 static uint16_t rx_data_consumed;
952 static uint16_t rx_data_cur;
953 static uint8_t  rx_ignore;
954 static uint8_t  rx_waiting;
955 static uint8_t  rx_starting;
956 static uint8_t  rx_task_id;
957 static uint32_t rx_fast_start;
958 static uint32_t rx_slow_start;
959 static uint32_t rx_missed;
960
961 #if AO_PROFILE
962 static uint32_t rx_start_tick, rx_packet_tick, rx_done_tick, rx_last_done_tick;
963
964 uint32_t        ao_rx_start_tick, ao_rx_packet_tick, ao_rx_done_tick, ao_rx_last_done_tick;
965
966 #include <ao_profile.h>
967 #endif
968
969 static void
970 ao_radio_rx_isr(void)
971 {
972         uint8_t d;
973
974         if (rx_task_id) {
975                 if (ao_radio_try_select(rx_task_id)) {
976                         ++rx_fast_start;
977                         rx_task_id = 0;
978                         _ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
979                 } else {
980                         if (rx_ignore)
981                                 --rx_ignore;
982                         else {
983                                 ao_radio_abort = 1;
984                                 rx_missed++;
985                         }
986                         return;
987                 }
988         }
989         if (rx_starting) {
990                 rx_starting = 0;
991                 ao_wakeup(&ao_radio_wake);
992         }
993         d = AO_CC1120_SPI.dr;
994         AO_CC1120_SPI.dr = 0;
995         if (rx_ignore == 0) {
996                 if (rx_data_cur < rx_data_count)
997                         rx_data[rx_data_cur++] = d;
998                 if (rx_data_cur >= rx_data_count) {
999                         ao_spi_clr_cs(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN));
1000                         ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
1001                 }
1002                 if (rx_waiting && rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) {
1003 #if AO_PROFILE
1004                         if (!rx_packet_tick)
1005                                 rx_packet_tick = ao_profile_tick();
1006                         if (rx_data_cur < rx_data_count)
1007                                 return;
1008 #endif
1009                         rx_waiting = 0;
1010                         ao_wakeup(&ao_radio_wake);
1011                 }
1012         } else {
1013                 --rx_ignore;
1014         }
1015 }
1016
1017 static uint16_t
1018 ao_radio_rx_wait(void)
1019 {
1020         ao_alarm(AO_MS_TO_TICKS(100));
1021         ao_arch_block_interrupts();
1022         rx_waiting = 1;
1023         while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
1024                !ao_radio_abort &&
1025                !ao_radio_mcu_wake)
1026         {
1027                 if (ao_sleep(&ao_radio_wake))
1028                         ao_radio_abort = 1;
1029         }
1030         rx_waiting = 0;
1031         ao_arch_release_interrupts();
1032         ao_clear_alarm();
1033         if (ao_radio_abort || ao_radio_mcu_wake)
1034                 return 0;
1035         rx_data_consumed += AO_FEC_DECODE_BLOCK;
1036 #if AO_PROFILE
1037         return rx_data_cur - rx_data_consumed;
1038 #endif
1039         return AO_FEC_DECODE_BLOCK;
1040 }
1041
1042 uint8_t
1043 ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout)
1044 {
1045         uint8_t         len;
1046         uint8_t         radio_rssi = 0;
1047         uint8_t         rssi0;
1048         uint8_t         ret;
1049
1050         size -= 2;                      /* status bytes */
1051         if (size > AO_RADIO_MAX_RECV) {
1052                 ao_delay(AO_SEC_TO_TICKS(1));
1053                 return 0;
1054         }
1055 #if AO_PROFILE
1056         rx_start_tick = ao_profile_tick();
1057         rx_packet_tick = 0;
1058 #endif
1059         len = size + 2;                 /* CRC bytes */
1060         len += 1 + ~(len & 1);          /* 1 or two pad bytes */
1061         len *= 2;                       /* 1/2 rate convolution */
1062         rx_data_count = len * 8;        /* bytes to bits */
1063         rx_data_cur = 0;
1064         rx_data_consumed = 0;
1065         rx_ignore = 2;
1066
1067         /* Must be set before changing the frequency; any abort
1068          * after the frequency is set needs to terminate the read
1069          * so that the registers can be reprogrammed
1070          */
1071         ao_radio_abort = 0;
1072
1073         ao_radio_get(len);
1074
1075         ao_radio_wake = 0;
1076         ao_radio_mcu_wake = 0;
1077
1078         ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX);
1079
1080         /* configure interrupt pin */
1081         ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT);
1082         ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
1083                          AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH);
1084
1085         ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
1086         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
1087
1088         rx_starting = 1;
1089         rx_task_id = ao_cur_task->task_id;
1090
1091         ao_radio_strobe(CC1120_SRX);
1092
1093         if (timeout)
1094                 ao_alarm(timeout);
1095         ao_arch_block_interrupts();
1096         while (rx_starting && !ao_radio_abort) {
1097                 if (ao_sleep(&ao_radio_wake))
1098                         ao_radio_abort = 1;
1099         }
1100         uint8_t rx_task_id_save = rx_task_id;
1101         rx_task_id = 0;
1102         rx_starting = 0;
1103         ao_arch_release_interrupts();
1104         if (timeout)
1105                 ao_clear_alarm();
1106
1107         if (ao_radio_abort) {
1108                 ret = 0;
1109                 rx_task_id = 0;
1110                 goto abort;
1111         }
1112
1113         if (rx_task_id_save) {
1114                 ++rx_slow_start;
1115                 ao_radio_select();
1116                 _ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
1117                 if (rx_ignore) {
1118                         uint8_t ignore = AO_CC1120_SPI.dr;
1119                         (void) ignore;
1120                         AO_CC1120_SPI.dr = 0;
1121                         --rx_ignore;
1122                 }
1123         }
1124
1125         ret = ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);
1126
1127         ao_radio_burst_read_stop();
1128
1129         if (ao_radio_mcu_wake)
1130                 ao_radio_check_marc_status();
1131         if (ao_radio_abort)
1132                 ret = 0;
1133
1134 abort:
1135         /* Convert from 'real' rssi to cc1111-style values */
1136
1137         rssi0 = ao_radio_reg_read(CC1120_RSSI0);
1138         if (rssi0 & 1) {
1139                 int8_t rssi = ao_radio_reg_read(CC1120_RSSI1);
1140                 ao_radio_rssi = rssi;
1141
1142                 /* Bound it to the representable range */
1143                 if (rssi > -11)
1144                         rssi = -11;
1145                 radio_rssi = AO_RADIO_FROM_RSSI (rssi);
1146         }
1147
1148         ao_radio_idle();
1149
1150         ao_radio_put();
1151
1152         /* Store the received RSSI value; the crc-OK byte is already done */
1153
1154         ((uint8_t *) d)[size] = radio_rssi;
1155
1156 #if AO_PROFILE
1157         rx_last_done_tick = rx_done_tick;
1158         rx_done_tick = ao_profile_tick();
1159
1160         ao_rx_start_tick = rx_start_tick;
1161         ao_rx_packet_tick = rx_packet_tick;
1162         ao_rx_done_tick = rx_done_tick;
1163         ao_rx_last_done_tick = rx_last_done_tick;
1164 #endif
1165
1166         return ret;
1167 }
1168
1169
1170 #if CC1120_DEBUG
1171 static char *cc1120_state_name[] = {
1172         [CC1120_STATUS_STATE_IDLE] = "IDLE",
1173         [CC1120_STATUS_STATE_RX] = "RX",
1174         [CC1120_STATUS_STATE_TX] = "TX",
1175         [CC1120_STATUS_STATE_FSTXON] = "FSTXON",
1176         [CC1120_STATUS_STATE_CALIBRATE] = "CALIBRATE",
1177         [CC1120_STATUS_STATE_SETTLING] = "SETTLING",
1178         [CC1120_STATUS_STATE_RX_FIFO_ERROR] = "RX_FIFO_ERROR",
1179         [CC1120_STATUS_STATE_TX_FIFO_ERROR] = "TX_FIFO_ERROR",
1180 };
1181
1182 struct ao_cc1120_reg {
1183         uint16_t        addr;
1184         char            *name;
1185 };
1186
1187 static const struct ao_cc1120_reg ao_cc1120_reg[] = {
1188         { .addr = CC1120_IOCFG3,        .name = "IOCFG3" },
1189         { .addr = CC1120_IOCFG2,        .name = "IOCFG2" },
1190         { .addr = CC1120_IOCFG1,        .name = "IOCFG1" },
1191         { .addr = CC1120_IOCFG0,        .name = "IOCFG0" },
1192         { .addr = CC1120_SYNC3, .name = "SYNC3" },
1193         { .addr = CC1120_SYNC2, .name = "SYNC2" },
1194         { .addr = CC1120_SYNC1, .name = "SYNC1" },
1195         { .addr = CC1120_SYNC0, .name = "SYNC0" },
1196         { .addr = CC1120_SYNC_CFG1,     .name = "SYNC_CFG1" },
1197         { .addr = CC1120_SYNC_CFG0,     .name = "SYNC_CFG0" },
1198         { .addr = CC1120_DEVIATION_M,   .name = "DEVIATION_M" },
1199         { .addr = CC1120_MODCFG_DEV_E,  .name = "MODCFG_DEV_E" },
1200         { .addr = CC1120_DCFILT_CFG,    .name = "DCFILT_CFG" },
1201         { .addr = CC1120_PREAMBLE_CFG1, .name = "PREAMBLE_CFG1" },
1202         { .addr = CC1120_PREAMBLE_CFG0, .name = "PREAMBLE_CFG0" },
1203         { .addr = CC1120_FREQ_IF_CFG,   .name = "FREQ_IF_CFG" },
1204         { .addr = CC1120_IQIC,  .name = "IQIC" },
1205         { .addr = CC1120_CHAN_BW,       .name = "CHAN_BW" },
1206         { .addr = CC1120_MDMCFG1,       .name = "MDMCFG1" },
1207         { .addr = CC1120_MDMCFG0,       .name = "MDMCFG0" },
1208         { .addr = CC1120_DRATE2,        .name = "DRATE2" },
1209         { .addr = CC1120_DRATE1,        .name = "DRATE1" },
1210         { .addr = CC1120_DRATE0,        .name = "DRATE0" },
1211         { .addr = CC1120_AGC_REF,       .name = "AGC_REF" },
1212         { .addr = CC1120_AGC_CS_THR,    .name = "AGC_CS_THR" },
1213         { .addr = CC1120_AGC_GAIN_ADJUST,       .name = "AGC_GAIN_ADJUST" },
1214         { .addr = CC1120_AGC_CFG3,      .name = "AGC_CFG3" },
1215         { .addr = CC1120_AGC_CFG2,      .name = "AGC_CFG2" },
1216         { .addr = CC1120_AGC_CFG1,      .name = "AGC_CFG1" },
1217         { .addr = CC1120_AGC_CFG0,      .name = "AGC_CFG0" },
1218         { .addr = CC1120_FIFO_CFG,      .name = "FIFO_CFG" },
1219         { .addr = CC1120_DEV_ADDR,      .name = "DEV_ADDR" },
1220         { .addr = CC1120_SETTLING_CFG,  .name = "SETTLING_CFG" },
1221         { .addr = CC1120_FS_CFG,        .name = "FS_CFG" },
1222         { .addr = CC1120_WOR_CFG1,      .name = "WOR_CFG1" },
1223         { .addr = CC1120_WOR_CFG0,      .name = "WOR_CFG0" },
1224         { .addr = CC1120_WOR_EVENT0_MSB,        .name = "WOR_EVENT0_MSB" },
1225         { .addr = CC1120_WOR_EVENT0_LSB,        .name = "WOR_EVENT0_LSB" },
1226         { .addr = CC1120_PKT_CFG2,      .name = "PKT_CFG2" },
1227         { .addr = CC1120_PKT_CFG1,      .name = "PKT_CFG1" },
1228         { .addr = CC1120_PKT_CFG0,      .name = "PKT_CFG0" },
1229         { .addr = CC1120_RFEND_CFG1,    .name = "RFEND_CFG1" },
1230         { .addr = CC1120_RFEND_CFG0,    .name = "RFEND_CFG0" },
1231         { .addr = CC1120_PA_CFG2,       .name = "PA_CFG2" },
1232         { .addr = CC1120_PA_CFG1,       .name = "PA_CFG1" },
1233         { .addr = CC1120_PA_CFG0,       .name = "PA_CFG0" },
1234         { .addr = CC1120_PKT_LEN,       .name = "PKT_LEN" },
1235         { .addr = CC1120_IF_MIX_CFG,    .name = "IF_MIX_CFG" },
1236         { .addr = CC1120_FREQOFF_CFG,   .name = "FREQOFF_CFG" },
1237         { .addr = CC1120_TOC_CFG,       .name = "TOC_CFG" },
1238         { .addr = CC1120_MARC_SPARE,    .name = "MARC_SPARE" },
1239         { .addr = CC1120_ECG_CFG,       .name = "ECG_CFG" },
1240         { .addr = CC1120_SOFT_TX_DATA_CFG,      .name = "SOFT_TX_DATA_CFG" },
1241         { .addr = CC1120_EXT_CTRL,      .name = "EXT_CTRL" },
1242         { .addr = CC1120_RCCAL_FINE,    .name = "RCCAL_FINE" },
1243         { .addr = CC1120_RCCAL_COARSE,  .name = "RCCAL_COARSE" },
1244         { .addr = CC1120_RCCAL_OFFSET,  .name = "RCCAL_OFFSET" },
1245         { .addr = CC1120_FREQOFF1,      .name = "FREQOFF1" },
1246         { .addr = CC1120_FREQOFF0,      .name = "FREQOFF0" },
1247         { .addr = CC1120_FREQ2, .name = "FREQ2" },
1248         { .addr = CC1120_FREQ1, .name = "FREQ1" },
1249         { .addr = CC1120_FREQ0, .name = "FREQ0" },
1250         { .addr = CC1120_IF_ADC2,       .name = "IF_ADC2" },
1251         { .addr = CC1120_IF_ADC1,       .name = "IF_ADC1" },
1252         { .addr = CC1120_IF_ADC0,       .name = "IF_ADC0" },
1253         { .addr = CC1120_FS_DIG1,       .name = "FS_DIG1" },
1254         { .addr = CC1120_FS_DIG0,       .name = "FS_DIG0" },
1255         { .addr = CC1120_FS_CAL3,       .name = "FS_CAL3" },
1256         { .addr = CC1120_FS_CAL2,       .name = "FS_CAL2" },
1257         { .addr = CC1120_FS_CAL1,       .name = "FS_CAL1" },
1258         { .addr = CC1120_FS_CAL0,       .name = "FS_CAL0" },
1259         { .addr = CC1120_FS_CHP,        .name = "FS_CHP" },
1260         { .addr = CC1120_FS_DIVTWO,     .name = "FS_DIVTWO" },
1261         { .addr = CC1120_FS_DSM1,       .name = "FS_DSM1" },
1262         { .addr = CC1120_FS_DSM0,       .name = "FS_DSM0" },
1263         { .addr = CC1120_FS_DVC1,       .name = "FS_DVC1" },
1264         { .addr = CC1120_FS_DVC0,       .name = "FS_DVC0" },
1265         { .addr = CC1120_FS_LBI,        .name = "FS_LBI" },
1266         { .addr = CC1120_FS_PFD,        .name = "FS_PFD" },
1267         { .addr = CC1120_FS_PRE,        .name = "FS_PRE" },
1268         { .addr = CC1120_FS_REG_DIV_CML,        .name = "FS_REG_DIV_CML" },
1269         { .addr = CC1120_FS_SPARE,      .name = "FS_SPARE" },
1270         { .addr = CC1120_FS_VCO4,       .name = "FS_VCO4" },
1271         { .addr = CC1120_FS_VCO3,       .name = "FS_VCO3" },
1272         { .addr = CC1120_FS_VCO2,       .name = "FS_VCO2" },
1273         { .addr = CC1120_FS_VCO1,       .name = "FS_VCO1" },
1274         { .addr = CC1120_FS_VCO0,       .name = "FS_VCO0" },
1275         { .addr = CC1120_GBIAS6,        .name = "GBIAS6" },
1276         { .addr = CC1120_GBIAS5,        .name = "GBIAS5" },
1277         { .addr = CC1120_GBIAS4,        .name = "GBIAS4" },
1278         { .addr = CC1120_GBIAS3,        .name = "GBIAS3" },
1279         { .addr = CC1120_GBIAS2,        .name = "GBIAS2" },
1280         { .addr = CC1120_GBIAS1,        .name = "GBIAS1" },
1281         { .addr = CC1120_GBIAS0,        .name = "GBIAS0" },
1282         { .addr = CC1120_IFAMP, .name = "IFAMP" },
1283         { .addr = CC1120_LNA,   .name = "LNA" },
1284         { .addr = CC1120_RXMIX, .name = "RXMIX" },
1285         { .addr = CC1120_XOSC5, .name = "XOSC5" },
1286         { .addr = CC1120_XOSC4, .name = "XOSC4" },
1287         { .addr = CC1120_XOSC3, .name = "XOSC3" },
1288         { .addr = CC1120_XOSC2, .name = "XOSC2" },
1289         { .addr = CC1120_XOSC1, .name = "XOSC1" },
1290         { .addr = CC1120_XOSC0, .name = "XOSC0" },
1291         { .addr = CC1120_ANALOG_SPARE,  .name = "ANALOG_SPARE" },
1292         { .addr = CC1120_PA_CFG3,       .name = "PA_CFG3" },
1293         { .addr = CC1120_WOR_TIME1,     .name = "WOR_TIME1" },
1294         { .addr = CC1120_WOR_TIME0,     .name = "WOR_TIME0" },
1295         { .addr = CC1120_WOR_CAPTURE1,  .name = "WOR_CAPTURE1" },
1296         { .addr = CC1120_WOR_CAPTURE0,  .name = "WOR_CAPTURE0" },
1297         { .addr = CC1120_BIST,  .name = "BIST" },
1298         { .addr = CC1120_DCFILTOFFSET_I1,       .name = "DCFILTOFFSET_I1" },
1299         { .addr = CC1120_DCFILTOFFSET_I0,       .name = "DCFILTOFFSET_I0" },
1300         { .addr = CC1120_DCFILTOFFSET_Q1,       .name = "DCFILTOFFSET_Q1" },
1301         { .addr = CC1120_DCFILTOFFSET_Q0,       .name = "DCFILTOFFSET_Q0" },
1302         { .addr = CC1120_IQIE_I1,       .name = "IQIE_I1" },
1303         { .addr = CC1120_IQIE_I0,       .name = "IQIE_I0" },
1304         { .addr = CC1120_IQIE_Q1,       .name = "IQIE_Q1" },
1305         { .addr = CC1120_IQIE_Q0,       .name = "IQIE_Q0" },
1306         { .addr = CC1120_RSSI1, .name = "RSSI1" },
1307         { .addr = CC1120_RSSI0, .name = "RSSI0" },
1308         { .addr = CC1120_MARCSTATE,     .name = "MARCSTATE" },
1309         { .addr = CC1120_LQI_VAL,       .name = "LQI_VAL" },
1310         { .addr = CC1120_PQT_SYNC_ERR,  .name = "PQT_SYNC_ERR" },
1311         { .addr = CC1120_DEM_STATUS,    .name = "DEM_STATUS" },
1312         { .addr = CC1120_FREQOFF_EST1,  .name = "FREQOFF_EST1" },
1313         { .addr = CC1120_FREQOFF_EST0,  .name = "FREQOFF_EST0" },
1314         { .addr = CC1120_AGC_GAIN3,     .name = "AGC_GAIN3" },
1315         { .addr = CC1120_AGC_GAIN2,     .name = "AGC_GAIN2" },
1316         { .addr = CC1120_AGC_GAIN1,     .name = "AGC_GAIN1" },
1317         { .addr = CC1120_AGC_GAIN0,     .name = "AGC_GAIN0" },
1318         { .addr = CC1120_SOFT_RX_DATA_OUT,      .name = "SOFT_RX_DATA_OUT" },
1319         { .addr = CC1120_SOFT_TX_DATA_IN,       .name = "SOFT_TX_DATA_IN" },
1320         { .addr = CC1120_ASK_SOFT_RX_DATA,      .name = "ASK_SOFT_RX_DATA" },
1321         { .addr = CC1120_RNDGEN,        .name = "RNDGEN" },
1322         { .addr = CC1120_MAGN2, .name = "MAGN2" },
1323         { .addr = CC1120_MAGN1, .name = "MAGN1" },
1324         { .addr = CC1120_MAGN0, .name = "MAGN0" },
1325         { .addr = CC1120_ANG1,  .name = "ANG1" },
1326         { .addr = CC1120_ANG0,  .name = "ANG0" },
1327         { .addr = CC1120_CHFILT_I2,     .name = "CHFILT_I2" },
1328         { .addr = CC1120_CHFILT_I1,     .name = "CHFILT_I1" },
1329         { .addr = CC1120_CHFILT_I0,     .name = "CHFILT_I0" },
1330         { .addr = CC1120_CHFILT_Q2,     .name = "CHFILT_Q2" },
1331         { .addr = CC1120_CHFILT_Q1,     .name = "CHFILT_Q1" },
1332         { .addr = CC1120_CHFILT_Q0,     .name = "CHFILT_Q0" },
1333         { .addr = CC1120_GPIO_STATUS,   .name = "GPIO_STATUS" },
1334         { .addr = CC1120_FSCAL_CTRL,    .name = "FSCAL_CTRL" },
1335         { .addr = CC1120_PHASE_ADJUST,  .name = "PHASE_ADJUST" },
1336         { .addr = CC1120_PARTNUMBER,    .name = "PARTNUMBER" },
1337         { .addr = CC1120_PARTVERSION,   .name = "PARTVERSION" },
1338         { .addr = CC1120_SERIAL_STATUS, .name = "SERIAL_STATUS" },
1339         { .addr = CC1120_RX_STATUS,     .name = "RX_STATUS" },
1340         { .addr = CC1120_TX_STATUS,     .name = "TX_STATUS" },
1341         { .addr = CC1120_MARC_STATUS1,  .name = "MARC_STATUS1" },
1342         { .addr = CC1120_MARC_STATUS0,  .name = "MARC_STATUS0" },
1343         { .addr = CC1120_PA_IFAMP_TEST, .name = "PA_IFAMP_TEST" },
1344         { .addr = CC1120_FSRF_TEST,     .name = "FSRF_TEST" },
1345         { .addr = CC1120_PRE_TEST,      .name = "PRE_TEST" },
1346         { .addr = CC1120_PRE_OVR,       .name = "PRE_OVR" },
1347         { .addr = CC1120_ADC_TEST,      .name = "ADC_TEST" },
1348         { .addr = CC1120_DVC_TEST,      .name = "DVC_TEST" },
1349         { .addr = CC1120_ATEST, .name = "ATEST" },
1350         { .addr = CC1120_ATEST_LVDS,    .name = "ATEST_LVDS" },
1351         { .addr = CC1120_ATEST_MODE,    .name = "ATEST_MODE" },
1352         { .addr = CC1120_XOSC_TEST1,    .name = "XOSC_TEST1" },
1353         { .addr = CC1120_XOSC_TEST0,    .name = "XOSC_TEST0" },
1354         { .addr = CC1120_RXFIRST,       .name = "RXFIRST" },
1355         { .addr = CC1120_TXFIRST,       .name = "TXFIRST" },
1356         { .addr = CC1120_RXLAST,        .name = "RXLAST" },
1357         { .addr = CC1120_TXLAST,        .name = "TXLAST" },
1358         { .addr = CC1120_NUM_TXBYTES,   .name = "NUM_TXBYTES" },
1359         { .addr = CC1120_NUM_RXBYTES,   .name = "NUM_RXBYTES" },
1360         { .addr = CC1120_FIFO_NUM_TXBYTES,      .name = "FIFO_NUM_TXBYTES" },
1361         { .addr = CC1120_FIFO_NUM_RXBYTES,      .name = "FIFO_NUM_RXBYTES" },
1362 };
1363
1364 #define AO_NUM_CC1120_REG       (sizeof ao_cc1120_reg / sizeof ao_cc1120_reg[0])
1365
1366 static void ao_radio_show(void) {
1367         uint8_t status = ao_radio_status();
1368         unsigned int    i;
1369
1370         ao_radio_get(0xff);
1371         status = ao_radio_status();
1372         printf ("Status:   %02x\n", status);
1373         printf ("CHIP_RDY: %d\n", (status >> CC1120_STATUS_CHIP_RDY) & 1);
1374         printf ("STATE:    %s\n", cc1120_state_name[(status >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK]);
1375         printf ("MARC:     %02x\n", ao_radio_get_marc_status());
1376
1377         for (i = 0; i < AO_NUM_CC1120_REG; i++)
1378                 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name);
1379
1380         printf("RX fast start: %u\n", rx_fast_start);
1381         printf("RX slow start: %u\n", rx_slow_start);
1382         printf("RX missed:     %u\n", rx_missed);
1383         ao_radio_put();
1384 }
1385
1386 static void ao_radio_beep(void) {
1387         ao_radio_rdf();
1388 }
1389
1390 static void ao_radio_packet(void) {
1391         static const uint8_t packet[] = {
1392 #if 1
1393                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1394                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1395                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1396                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1397 #else
1398                 3, 1, 2, 3
1399 #endif
1400         };
1401
1402         ao_radio_send(packet, sizeof (packet));
1403 }
1404
1405 void
1406 ao_radio_test_recv(void)
1407 {
1408         uint8_t bytes[34];
1409         uint8_t b;
1410
1411         if (ao_radio_recv(bytes, 34, 0)) {
1412                 if (bytes[33] & 0x80)
1413                         printf ("CRC OK");
1414                 else
1415                         printf ("CRC BAD");
1416                 printf (" RSSI %d", AO_RSSI_FROM_RADIO(bytes[32]));
1417                 for (b = 0; b < 32; b++)
1418                         printf (" %02x", bytes[b]);
1419                 printf ("\n");
1420         }
1421 }
1422
1423 #if HAS_APRS
1424 #include <ao_aprs.h>
1425
1426 static void
1427 ao_radio_aprs(void)
1428 {
1429         ao_packet_slave_stop();
1430         ao_aprs_send();
1431 }
1432 #endif
1433 #endif
1434
1435 static const struct ao_cmds ao_radio_cmds[] = {
1436         { ao_radio_test_cmd,    "C <1 start, 0 stop, none both>\0Radio carrier test" },
1437 #if CC1120_DEBUG
1438 #if HAS_APRS
1439         { ao_radio_aprs,        "G\0Send APRS packet" },
1440 #endif
1441         { ao_radio_show,        "R\0Show CC1120 status" },
1442         { ao_radio_beep,        "b\0Emit an RDF beacon" },
1443         { ao_radio_packet,      "p\0Send a test packet" },
1444         { ao_radio_test_recv,   "q\0Recv a test packet" },
1445 #endif
1446         { 0, NULL }
1447 };
1448
1449 void
1450 ao_radio_init(void)
1451 {
1452         ao_radio_configured = 0;
1453         ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN));
1454
1455 #if 0
1456         AO_CC1120_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));
1457         for (i = 0; i < 10000; i++) {
1458                 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
1459                         break;
1460         }
1461         AO_CC1120_SPI_CS_PORT->bsrr = (1 << AO_CC1120_SPI_CS_PIN);
1462         if (i == 10000)
1463                 ao_panic(AO_PANIC_SELF_TEST_CC1120);
1464 #endif
1465
1466         /* Enable the EXTI interrupt for the appropriate pin */
1467         ao_enable_port(AO_CC1120_INT_PORT);
1468         ao_exti_setup(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
1469                       AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
1470                       ao_radio_isr);
1471
1472         /* Enable the hacked up GPIO3 pin */
1473         ao_enable_port(AO_CC1120_MCU_WAKEUP_PORT);
1474         ao_exti_setup(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN,
1475                       AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
1476                       ao_radio_mcu_wakeup_isr);
1477
1478         ao_cmd_register(&ao_radio_cmds[0]);
1479 }