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