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