altos/cc1200: Adjust bit-sync configuration
[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         ao_arch_block_interrupts();
841         while (!ao_radio_wake && !ao_radio_mcu_wake && !ao_radio_abort)
842                 if (ao_sleep_for(&ao_radio_wake, timeout))
843                         ao_radio_abort = 1;
844         ao_arch_release_interrupts();
845         if (ao_radio_mcu_wake)
846                 ao_radio_check_marc_status();
847 }
848
849 static uint8_t
850 ao_radio_wait_tx(uint8_t wait_fifo)
851 {
852         uint8_t fifo_space = 0;
853
854         do {
855                 ao_radio_wait_isr(0);
856                 if (!wait_fifo)
857                         return 0;
858                 fifo_space = ao_radio_tx_fifo_space();
859         } while (!fifo_space && !ao_radio_abort);
860         return fifo_space;
861 }
862
863 static uint8_t  tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
864
865 void
866 ao_radio_send(const void *d, uint8_t size)
867 {
868         uint8_t         *e = tx_data;
869         uint8_t         encode_len;
870         uint8_t         this_len;
871         uint8_t         started = 0;
872         uint8_t         fifo_space;
873
874         encode_len = ao_fec_encode(d, size, tx_data);
875
876         ao_radio_get(encode_len);
877
878         ao_radio_abort = 0;
879
880         /* Flush any pending TX bytes */
881         ao_radio_strobe(CC1120_SFTX);
882
883         started = 0;
884         fifo_space = CC1120_FIFO_SIZE;
885         while (encode_len) {
886                 this_len = encode_len;
887
888                 ao_radio_wake = 0;
889                 if (this_len > fifo_space) {
890                         this_len = fifo_space;
891                         ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF);
892                 } else {
893                         ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_FINISH);
894                 }
895
896                 ao_radio_fifo_write(e, this_len);
897                 e += this_len;
898                 encode_len -= this_len;
899
900                 if (!started) {
901                         ao_radio_start_tx();
902                         started = 1;
903                 } else {
904                         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
905                 }
906
907                 fifo_space = ao_radio_wait_tx(encode_len != 0);
908                 if (ao_radio_abort) {
909                         ao_radio_idle();
910                         break;
911                 }
912         }
913         while (started && !ao_radio_abort && !ao_radio_tx_finished)
914                 ao_radio_wait_isr(0);
915         ao_radio_put();
916 }
917
918 #define AO_RADIO_LOTS   64
919
920 void
921 ao_radio_send_aprs(ao_radio_fill_func fill)
922 {
923         uint8_t buf[AO_RADIO_LOTS], *b;
924         int     cnt;
925         int     total = 0;
926         uint8_t done = 0;
927         uint8_t started = 0;
928         uint8_t fifo_space;
929
930         ao_radio_get(0xff);
931         fifo_space = CC1120_FIFO_SIZE;
932         while (!done) {
933                 cnt = (*fill)(buf, sizeof(buf));
934                 if (cnt < 0) {
935                         done = 1;
936                         cnt = -cnt;
937                 }
938                 total += cnt;
939
940                 /* At the last buffer, set the total length */
941                 if (done)
942                         ao_radio_set_len(total & 0xff);
943
944                 b = buf;
945                 while (cnt) {
946                         uint8_t this_len = cnt;
947
948                         /* Wait for some space in the fifo */
949                         while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
950                                 ao_radio_wake = 0;
951                                 ao_radio_wait_isr(0);
952                         }
953                         if (ao_radio_abort)
954                                 break;
955                         if (this_len > fifo_space)
956                                 this_len = fifo_space;
957
958                         cnt -= this_len;
959
960                         if (done) {
961                                 if (cnt)
962                                         ao_radio_set_mode(AO_RADIO_MODE_APRS_LAST_BUF);
963                                 else
964                                         ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH);
965                         } else
966                                 ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF);
967
968                         ao_radio_fifo_write(b, this_len);
969                         b += this_len;
970
971                         if (!started) {
972                                 ao_radio_start_tx();
973                                 started = 1;
974                         } else
975                                 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
976                 }
977                 if (ao_radio_abort) {
978                         ao_radio_idle();
979                         break;
980                 }
981                 /* Wait for the transmitter to go idle */
982                 ao_radio_wake = 0;
983                 ao_radio_wait_isr(0);
984         }
985         ao_radio_put();
986 }
987
988 static uint8_t  rx_data[(AO_RADIO_MAX_RECV + 4) * 2 * 8];
989 static uint16_t rx_data_count;
990 static uint16_t rx_data_consumed;
991 static uint16_t rx_data_cur;
992 static uint8_t  rx_ignore;
993 static uint8_t  rx_waiting;
994 static uint8_t  rx_starting;
995 static uint8_t  rx_task_id;
996 static uint32_t rx_fast_start;
997 static uint32_t rx_slow_start;
998 static uint32_t rx_missed;
999
1000 #if AO_PROFILE
1001 static uint32_t rx_start_tick, rx_packet_tick, rx_done_tick, rx_last_done_tick;
1002
1003 uint32_t        ao_rx_start_tick, ao_rx_packet_tick, ao_rx_done_tick, ao_rx_last_done_tick;
1004
1005 #include <ao_profile.h>
1006 #endif
1007
1008 static void
1009 ao_radio_rx_isr(void)
1010 {
1011         uint8_t d;
1012
1013         if (rx_task_id) {
1014                 if (ao_radio_try_select(rx_task_id)) {
1015                         ++rx_fast_start;
1016                         rx_task_id = 0;
1017                         _ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
1018                 } else {
1019                         if (rx_ignore)
1020                                 --rx_ignore;
1021                         else {
1022                                 ao_radio_abort = 1;
1023                                 rx_missed++;
1024                         }
1025                         return;
1026                 }
1027         }
1028         if (rx_starting) {
1029                 rx_starting = 0;
1030                 ao_wakeup(&ao_radio_wake);
1031         }
1032         d = AO_CC1120_SPI.dr;
1033         AO_CC1120_SPI.dr = 0;
1034         if (rx_ignore == 0) {
1035                 if (rx_data_cur < rx_data_count)
1036                         rx_data[rx_data_cur++] = d;
1037                 if (rx_data_cur >= rx_data_count) {
1038                         ao_spi_clr_cs(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN));
1039                         ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
1040                 }
1041                 if (rx_waiting && rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) {
1042 #if AO_PROFILE
1043                         if (!rx_packet_tick)
1044                                 rx_packet_tick = ao_profile_tick();
1045                         if (rx_data_cur < rx_data_count)
1046                                 return;
1047 #endif
1048                         rx_waiting = 0;
1049                         ao_wakeup(&ao_radio_wake);
1050                 }
1051         } else {
1052                 --rx_ignore;
1053         }
1054 }
1055
1056 static uint16_t
1057 ao_radio_rx_wait(void)
1058 {
1059         ao_arch_block_interrupts();
1060         rx_waiting = 1;
1061         while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
1062                !ao_radio_abort &&
1063                !ao_radio_mcu_wake)
1064         {
1065                 if (ao_sleep_for(&ao_radio_wake, AO_MS_TO_TICKS(100)))
1066                         ao_radio_abort = 1;
1067         }
1068         rx_waiting = 0;
1069         ao_arch_release_interrupts();
1070         if (ao_radio_abort || ao_radio_mcu_wake)
1071                 return 0;
1072         rx_data_consumed += AO_FEC_DECODE_BLOCK;
1073 #if AO_PROFILE
1074         return rx_data_cur - rx_data_consumed;
1075 #endif
1076         return AO_FEC_DECODE_BLOCK;
1077 }
1078
1079 uint8_t
1080 ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout)
1081 {
1082         uint8_t         len;
1083         uint8_t         radio_rssi = 0;
1084         uint8_t         rssi0;
1085         uint8_t         ret;
1086
1087         size -= 2;                      /* status bytes */
1088         if (size > AO_RADIO_MAX_RECV) {
1089                 ao_delay(AO_SEC_TO_TICKS(1));
1090                 return 0;
1091         }
1092 #if AO_PROFILE
1093         rx_start_tick = ao_profile_tick();
1094         rx_packet_tick = 0;
1095 #endif
1096         len = size + 2;                 /* CRC bytes */
1097         len += 1 + ~(len & 1);          /* 1 or two pad bytes */
1098         len *= 2;                       /* 1/2 rate convolution */
1099         rx_data_count = len * 8;        /* bytes to bits */
1100         rx_data_cur = 0;
1101         rx_data_consumed = 0;
1102         rx_ignore = 2;
1103
1104         /* Must be set before changing the frequency; any abort
1105          * after the frequency is set needs to terminate the read
1106          * so that the registers can be reprogrammed
1107          */
1108         ao_radio_abort = 0;
1109
1110         ao_radio_get(len);
1111
1112         ao_radio_wake = 0;
1113         ao_radio_mcu_wake = 0;
1114
1115         ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX);
1116
1117         /* configure interrupt pin */
1118         ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT);
1119         ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
1120                          AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH);
1121
1122         rx_starting = 1;
1123         rx_task_id = ao_cur_task->task_id;
1124
1125         ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
1126         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
1127
1128         ao_radio_strobe(CC1120_SRX);
1129
1130         ao_arch_block_interrupts();
1131         while (rx_starting && !ao_radio_abort) {
1132                 if (ao_sleep_for(&ao_radio_wake, timeout))
1133                         ao_radio_abort = 1;
1134         }
1135         uint8_t rx_task_id_save = rx_task_id;
1136         rx_task_id = 0;
1137         rx_starting = 0;
1138         ao_arch_release_interrupts();
1139
1140         if (ao_radio_abort) {
1141                 if (rx_task_id_save == 0)
1142                         ao_radio_burst_read_stop();
1143                 ret = 0;
1144                 goto abort;
1145         }
1146
1147         if (rx_task_id_save) {
1148                 ++rx_slow_start;
1149                 ao_radio_select();
1150                 _ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
1151                 if (rx_ignore) {
1152                         uint8_t ignore = AO_CC1120_SPI.dr;
1153                         (void) ignore;
1154                         AO_CC1120_SPI.dr = 0;
1155                         --rx_ignore;
1156                 }
1157         }
1158
1159         ret = ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);
1160
1161         ao_radio_burst_read_stop();
1162
1163         if (ao_radio_mcu_wake)
1164                 ao_radio_check_marc_status();
1165         if (ao_radio_abort)
1166                 ret = 0;
1167
1168 abort:
1169         /* Convert from 'real' rssi to cc1111-style values */
1170
1171         rssi0 = ao_radio_reg_read(CC1120_RSSI0);
1172         if (rssi0 & 1) {
1173                 int8_t rssi = ao_radio_reg_read(CC1120_RSSI1);
1174                 ao_radio_rssi = rssi;
1175
1176                 /* Bound it to the representable range */
1177                 if (rssi > -11)
1178                         rssi = -11;
1179                 radio_rssi = AO_RADIO_FROM_RSSI (rssi);
1180         }
1181
1182         ao_radio_idle();
1183
1184         ao_radio_put();
1185
1186         /* Store the received RSSI value; the crc-OK byte is already done */
1187
1188         ((uint8_t *) d)[size] = radio_rssi;
1189
1190 #if AO_PROFILE
1191         rx_last_done_tick = rx_done_tick;
1192         rx_done_tick = ao_profile_tick();
1193
1194         ao_rx_start_tick = rx_start_tick;
1195         ao_rx_packet_tick = rx_packet_tick;
1196         ao_rx_done_tick = rx_done_tick;
1197         ao_rx_last_done_tick = rx_last_done_tick;
1198 #endif
1199
1200         return ret;
1201 }
1202
1203
1204 #if CC1120_DEBUG
1205 static char *cc1120_state_name[] = {
1206         [CC1120_STATUS_STATE_IDLE] = "IDLE",
1207         [CC1120_STATUS_STATE_RX] = "RX",
1208         [CC1120_STATUS_STATE_TX] = "TX",
1209         [CC1120_STATUS_STATE_FSTXON] = "FSTXON",
1210         [CC1120_STATUS_STATE_CALIBRATE] = "CALIBRATE",
1211         [CC1120_STATUS_STATE_SETTLING] = "SETTLING",
1212         [CC1120_STATUS_STATE_RX_FIFO_ERROR] = "RX_FIFO_ERROR",
1213         [CC1120_STATUS_STATE_TX_FIFO_ERROR] = "TX_FIFO_ERROR",
1214 };
1215
1216 struct ao_cc1120_reg {
1217         uint16_t        addr;
1218         char            *name;
1219 };
1220
1221 static const struct ao_cc1120_reg ao_cc1120_reg[] = {
1222         { .addr = CC1120_IOCFG3,        .name = "IOCFG3" },
1223         { .addr = CC1120_IOCFG2,        .name = "IOCFG2" },
1224         { .addr = CC1120_IOCFG1,        .name = "IOCFG1" },
1225         { .addr = CC1120_IOCFG0,        .name = "IOCFG0" },
1226         { .addr = CC1120_SYNC3, .name = "SYNC3" },
1227         { .addr = CC1120_SYNC2, .name = "SYNC2" },
1228         { .addr = CC1120_SYNC1, .name = "SYNC1" },
1229         { .addr = CC1120_SYNC0, .name = "SYNC0" },
1230         { .addr = CC1120_SYNC_CFG1,     .name = "SYNC_CFG1" },
1231         { .addr = CC1120_SYNC_CFG0,     .name = "SYNC_CFG0" },
1232         { .addr = CC1120_DEVIATION_M,   .name = "DEVIATION_M" },
1233         { .addr = CC1120_MODCFG_DEV_E,  .name = "MODCFG_DEV_E" },
1234         { .addr = CC1120_DCFILT_CFG,    .name = "DCFILT_CFG" },
1235         { .addr = CC1120_PREAMBLE_CFG1, .name = "PREAMBLE_CFG1" },
1236         { .addr = CC1120_PREAMBLE_CFG0, .name = "PREAMBLE_CFG0" },
1237         { .addr = CC1120_FREQ_IF_CFG,   .name = "FREQ_IF_CFG" },
1238         { .addr = CC1120_IQIC,  .name = "IQIC" },
1239         { .addr = CC1120_CHAN_BW,       .name = "CHAN_BW" },
1240         { .addr = CC1120_MDMCFG1,       .name = "MDMCFG1" },
1241         { .addr = CC1120_MDMCFG0,       .name = "MDMCFG0" },
1242         { .addr = CC1120_DRATE2,        .name = "DRATE2" },
1243         { .addr = CC1120_DRATE1,        .name = "DRATE1" },
1244         { .addr = CC1120_DRATE0,        .name = "DRATE0" },
1245         { .addr = CC1120_AGC_REF,       .name = "AGC_REF" },
1246         { .addr = CC1120_AGC_CS_THR,    .name = "AGC_CS_THR" },
1247         { .addr = CC1120_AGC_GAIN_ADJUST,       .name = "AGC_GAIN_ADJUST" },
1248         { .addr = CC1120_AGC_CFG3,      .name = "AGC_CFG3" },
1249         { .addr = CC1120_AGC_CFG2,      .name = "AGC_CFG2" },
1250         { .addr = CC1120_AGC_CFG1,      .name = "AGC_CFG1" },
1251         { .addr = CC1120_AGC_CFG0,      .name = "AGC_CFG0" },
1252         { .addr = CC1120_FIFO_CFG,      .name = "FIFO_CFG" },
1253         { .addr = CC1120_DEV_ADDR,      .name = "DEV_ADDR" },
1254         { .addr = CC1120_SETTLING_CFG,  .name = "SETTLING_CFG" },
1255         { .addr = CC1120_FS_CFG,        .name = "FS_CFG" },
1256         { .addr = CC1120_WOR_CFG1,      .name = "WOR_CFG1" },
1257         { .addr = CC1120_WOR_CFG0,      .name = "WOR_CFG0" },
1258         { .addr = CC1120_WOR_EVENT0_MSB,        .name = "WOR_EVENT0_MSB" },
1259         { .addr = CC1120_WOR_EVENT0_LSB,        .name = "WOR_EVENT0_LSB" },
1260         { .addr = CC1120_PKT_CFG2,      .name = "PKT_CFG2" },
1261         { .addr = CC1120_PKT_CFG1,      .name = "PKT_CFG1" },
1262         { .addr = CC1120_PKT_CFG0,      .name = "PKT_CFG0" },
1263         { .addr = CC1120_RFEND_CFG1,    .name = "RFEND_CFG1" },
1264         { .addr = CC1120_RFEND_CFG0,    .name = "RFEND_CFG0" },
1265         { .addr = CC1120_PA_CFG2,       .name = "PA_CFG2" },
1266         { .addr = CC1120_PA_CFG1,       .name = "PA_CFG1" },
1267         { .addr = CC1120_PA_CFG0,       .name = "PA_CFG0" },
1268         { .addr = CC1120_PKT_LEN,       .name = "PKT_LEN" },
1269         { .addr = CC1120_IF_MIX_CFG,    .name = "IF_MIX_CFG" },
1270         { .addr = CC1120_FREQOFF_CFG,   .name = "FREQOFF_CFG" },
1271         { .addr = CC1120_TOC_CFG,       .name = "TOC_CFG" },
1272         { .addr = CC1120_MARC_SPARE,    .name = "MARC_SPARE" },
1273         { .addr = CC1120_ECG_CFG,       .name = "ECG_CFG" },
1274         { .addr = CC1120_SOFT_TX_DATA_CFG,      .name = "SOFT_TX_DATA_CFG" },
1275         { .addr = CC1120_EXT_CTRL,      .name = "EXT_CTRL" },
1276         { .addr = CC1120_RCCAL_FINE,    .name = "RCCAL_FINE" },
1277         { .addr = CC1120_RCCAL_COARSE,  .name = "RCCAL_COARSE" },
1278         { .addr = CC1120_RCCAL_OFFSET,  .name = "RCCAL_OFFSET" },
1279         { .addr = CC1120_FREQOFF1,      .name = "FREQOFF1" },
1280         { .addr = CC1120_FREQOFF0,      .name = "FREQOFF0" },
1281         { .addr = CC1120_FREQ2, .name = "FREQ2" },
1282         { .addr = CC1120_FREQ1, .name = "FREQ1" },
1283         { .addr = CC1120_FREQ0, .name = "FREQ0" },
1284         { .addr = CC1120_IF_ADC2,       .name = "IF_ADC2" },
1285         { .addr = CC1120_IF_ADC1,       .name = "IF_ADC1" },
1286         { .addr = CC1120_IF_ADC0,       .name = "IF_ADC0" },
1287         { .addr = CC1120_FS_DIG1,       .name = "FS_DIG1" },
1288         { .addr = CC1120_FS_DIG0,       .name = "FS_DIG0" },
1289         { .addr = CC1120_FS_CAL3,       .name = "FS_CAL3" },
1290         { .addr = CC1120_FS_CAL2,       .name = "FS_CAL2" },
1291         { .addr = CC1120_FS_CAL1,       .name = "FS_CAL1" },
1292         { .addr = CC1120_FS_CAL0,       .name = "FS_CAL0" },
1293         { .addr = CC1120_FS_CHP,        .name = "FS_CHP" },
1294         { .addr = CC1120_FS_DIVTWO,     .name = "FS_DIVTWO" },
1295         { .addr = CC1120_FS_DSM1,       .name = "FS_DSM1" },
1296         { .addr = CC1120_FS_DSM0,       .name = "FS_DSM0" },
1297         { .addr = CC1120_FS_DVC1,       .name = "FS_DVC1" },
1298         { .addr = CC1120_FS_DVC0,       .name = "FS_DVC0" },
1299         { .addr = CC1120_FS_LBI,        .name = "FS_LBI" },
1300         { .addr = CC1120_FS_PFD,        .name = "FS_PFD" },
1301         { .addr = CC1120_FS_PRE,        .name = "FS_PRE" },
1302         { .addr = CC1120_FS_REG_DIV_CML,        .name = "FS_REG_DIV_CML" },
1303         { .addr = CC1120_FS_SPARE,      .name = "FS_SPARE" },
1304         { .addr = CC1120_FS_VCO4,       .name = "FS_VCO4" },
1305         { .addr = CC1120_FS_VCO3,       .name = "FS_VCO3" },
1306         { .addr = CC1120_FS_VCO2,       .name = "FS_VCO2" },
1307         { .addr = CC1120_FS_VCO1,       .name = "FS_VCO1" },
1308         { .addr = CC1120_FS_VCO0,       .name = "FS_VCO0" },
1309         { .addr = CC1120_GBIAS6,        .name = "GBIAS6" },
1310         { .addr = CC1120_GBIAS5,        .name = "GBIAS5" },
1311         { .addr = CC1120_GBIAS4,        .name = "GBIAS4" },
1312         { .addr = CC1120_GBIAS3,        .name = "GBIAS3" },
1313         { .addr = CC1120_GBIAS2,        .name = "GBIAS2" },
1314         { .addr = CC1120_GBIAS1,        .name = "GBIAS1" },
1315         { .addr = CC1120_GBIAS0,        .name = "GBIAS0" },
1316         { .addr = CC1120_IFAMP, .name = "IFAMP" },
1317         { .addr = CC1120_LNA,   .name = "LNA" },
1318         { .addr = CC1120_RXMIX, .name = "RXMIX" },
1319         { .addr = CC1120_XOSC5, .name = "XOSC5" },
1320         { .addr = CC1120_XOSC4, .name = "XOSC4" },
1321         { .addr = CC1120_XOSC3, .name = "XOSC3" },
1322         { .addr = CC1120_XOSC2, .name = "XOSC2" },
1323         { .addr = CC1120_XOSC1, .name = "XOSC1" },
1324         { .addr = CC1120_XOSC0, .name = "XOSC0" },
1325         { .addr = CC1120_ANALOG_SPARE,  .name = "ANALOG_SPARE" },
1326         { .addr = CC1120_PA_CFG3,       .name = "PA_CFG3" },
1327         { .addr = CC1120_WOR_TIME1,     .name = "WOR_TIME1" },
1328         { .addr = CC1120_WOR_TIME0,     .name = "WOR_TIME0" },
1329         { .addr = CC1120_WOR_CAPTURE1,  .name = "WOR_CAPTURE1" },
1330         { .addr = CC1120_WOR_CAPTURE0,  .name = "WOR_CAPTURE0" },
1331         { .addr = CC1120_BIST,  .name = "BIST" },
1332         { .addr = CC1120_DCFILTOFFSET_I1,       .name = "DCFILTOFFSET_I1" },
1333         { .addr = CC1120_DCFILTOFFSET_I0,       .name = "DCFILTOFFSET_I0" },
1334         { .addr = CC1120_DCFILTOFFSET_Q1,       .name = "DCFILTOFFSET_Q1" },
1335         { .addr = CC1120_DCFILTOFFSET_Q0,       .name = "DCFILTOFFSET_Q0" },
1336         { .addr = CC1120_IQIE_I1,       .name = "IQIE_I1" },
1337         { .addr = CC1120_IQIE_I0,       .name = "IQIE_I0" },
1338         { .addr = CC1120_IQIE_Q1,       .name = "IQIE_Q1" },
1339         { .addr = CC1120_IQIE_Q0,       .name = "IQIE_Q0" },
1340         { .addr = CC1120_RSSI1, .name = "RSSI1" },
1341         { .addr = CC1120_RSSI0, .name = "RSSI0" },
1342         { .addr = CC1120_MARCSTATE,     .name = "MARCSTATE" },
1343         { .addr = CC1120_LQI_VAL,       .name = "LQI_VAL" },
1344         { .addr = CC1120_PQT_SYNC_ERR,  .name = "PQT_SYNC_ERR" },
1345         { .addr = CC1120_DEM_STATUS,    .name = "DEM_STATUS" },
1346         { .addr = CC1120_FREQOFF_EST1,  .name = "FREQOFF_EST1" },
1347         { .addr = CC1120_FREQOFF_EST0,  .name = "FREQOFF_EST0" },
1348         { .addr = CC1120_AGC_GAIN3,     .name = "AGC_GAIN3" },
1349         { .addr = CC1120_AGC_GAIN2,     .name = "AGC_GAIN2" },
1350         { .addr = CC1120_AGC_GAIN1,     .name = "AGC_GAIN1" },
1351         { .addr = CC1120_AGC_GAIN0,     .name = "AGC_GAIN0" },
1352         { .addr = CC1120_SOFT_RX_DATA_OUT,      .name = "SOFT_RX_DATA_OUT" },
1353         { .addr = CC1120_SOFT_TX_DATA_IN,       .name = "SOFT_TX_DATA_IN" },
1354         { .addr = CC1120_ASK_SOFT_RX_DATA,      .name = "ASK_SOFT_RX_DATA" },
1355         { .addr = CC1120_RNDGEN,        .name = "RNDGEN" },
1356         { .addr = CC1120_MAGN2, .name = "MAGN2" },
1357         { .addr = CC1120_MAGN1, .name = "MAGN1" },
1358         { .addr = CC1120_MAGN0, .name = "MAGN0" },
1359         { .addr = CC1120_ANG1,  .name = "ANG1" },
1360         { .addr = CC1120_ANG0,  .name = "ANG0" },
1361         { .addr = CC1120_CHFILT_I2,     .name = "CHFILT_I2" },
1362         { .addr = CC1120_CHFILT_I1,     .name = "CHFILT_I1" },
1363         { .addr = CC1120_CHFILT_I0,     .name = "CHFILT_I0" },
1364         { .addr = CC1120_CHFILT_Q2,     .name = "CHFILT_Q2" },
1365         { .addr = CC1120_CHFILT_Q1,     .name = "CHFILT_Q1" },
1366         { .addr = CC1120_CHFILT_Q0,     .name = "CHFILT_Q0" },
1367         { .addr = CC1120_GPIO_STATUS,   .name = "GPIO_STATUS" },
1368         { .addr = CC1120_FSCAL_CTRL,    .name = "FSCAL_CTRL" },
1369         { .addr = CC1120_PHASE_ADJUST,  .name = "PHASE_ADJUST" },
1370         { .addr = CC1120_PARTNUMBER,    .name = "PARTNUMBER" },
1371         { .addr = CC1120_PARTVERSION,   .name = "PARTVERSION" },
1372         { .addr = CC1120_SERIAL_STATUS, .name = "SERIAL_STATUS" },
1373         { .addr = CC1120_RX_STATUS,     .name = "RX_STATUS" },
1374         { .addr = CC1120_TX_STATUS,     .name = "TX_STATUS" },
1375         { .addr = CC1120_MARC_STATUS1,  .name = "MARC_STATUS1" },
1376         { .addr = CC1120_MARC_STATUS0,  .name = "MARC_STATUS0" },
1377         { .addr = CC1120_PA_IFAMP_TEST, .name = "PA_IFAMP_TEST" },
1378         { .addr = CC1120_FSRF_TEST,     .name = "FSRF_TEST" },
1379         { .addr = CC1120_PRE_TEST,      .name = "PRE_TEST" },
1380         { .addr = CC1120_PRE_OVR,       .name = "PRE_OVR" },
1381         { .addr = CC1120_ADC_TEST,      .name = "ADC_TEST" },
1382         { .addr = CC1120_DVC_TEST,      .name = "DVC_TEST" },
1383         { .addr = CC1120_ATEST, .name = "ATEST" },
1384         { .addr = CC1120_ATEST_LVDS,    .name = "ATEST_LVDS" },
1385         { .addr = CC1120_ATEST_MODE,    .name = "ATEST_MODE" },
1386         { .addr = CC1120_XOSC_TEST1,    .name = "XOSC_TEST1" },
1387         { .addr = CC1120_XOSC_TEST0,    .name = "XOSC_TEST0" },
1388         { .addr = CC1120_RXFIRST,       .name = "RXFIRST" },
1389         { .addr = CC1120_TXFIRST,       .name = "TXFIRST" },
1390         { .addr = CC1120_RXLAST,        .name = "RXLAST" },
1391         { .addr = CC1120_TXLAST,        .name = "TXLAST" },
1392         { .addr = CC1120_NUM_TXBYTES,   .name = "NUM_TXBYTES" },
1393         { .addr = CC1120_NUM_RXBYTES,   .name = "NUM_RXBYTES" },
1394         { .addr = CC1120_FIFO_NUM_TXBYTES,      .name = "FIFO_NUM_TXBYTES" },
1395         { .addr = CC1120_FIFO_NUM_RXBYTES,      .name = "FIFO_NUM_RXBYTES" },
1396 };
1397
1398 #define AO_NUM_CC1120_REG       (sizeof ao_cc1120_reg / sizeof ao_cc1120_reg[0])
1399
1400 static void ao_radio_show(void) {
1401         uint8_t status = ao_radio_status();
1402         unsigned int    i;
1403
1404         ao_radio_get(0xff);
1405         status = ao_radio_status();
1406         printf ("Status:   %02x\n", status);
1407         printf ("CHIP_RDY: %d\n", (status >> CC1120_STATUS_CHIP_RDY) & 1);
1408         printf ("STATE:    %s\n", cc1120_state_name[(status >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK]);
1409         printf ("MARC:     %02x\n", ao_radio_get_marc_status());
1410
1411         for (i = 0; i < AO_NUM_CC1120_REG; i++)
1412                 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name);
1413
1414         printf("RX fast start: %u\n", rx_fast_start);
1415         printf("RX slow start: %u\n", rx_slow_start);
1416         printf("RX missed:     %u\n", rx_missed);
1417         ao_radio_put();
1418 }
1419
1420 static void ao_radio_beep(void) {
1421         ao_radio_rdf();
1422 }
1423
1424 static void ao_radio_packet(void) {
1425         static const uint8_t packet[] = {
1426 #if 1
1427                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1428                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1429                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1430                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1431 #else
1432                 3, 1, 2, 3
1433 #endif
1434         };
1435
1436         ao_radio_send(packet, sizeof (packet));
1437 }
1438
1439 void
1440 ao_radio_test_recv(void)
1441 {
1442         uint8_t bytes[34];
1443         uint8_t b;
1444
1445         if (ao_radio_recv(bytes, 34, 0)) {
1446                 if (bytes[33] & 0x80)
1447                         printf ("CRC OK");
1448                 else
1449                         printf ("CRC BAD");
1450                 printf (" RSSI %d", AO_RSSI_FROM_RADIO(bytes[32]));
1451                 for (b = 0; b < 32; b++)
1452                         printf (" %02x", bytes[b]);
1453                 printf ("\n");
1454         }
1455 }
1456
1457 #if HAS_APRS
1458 #include <ao_aprs.h>
1459
1460 static void
1461 ao_radio_aprs(void)
1462 {
1463         ao_packet_slave_stop();
1464         ao_aprs_send();
1465 }
1466 #endif
1467 #endif
1468
1469 static const struct ao_cmds ao_radio_cmds[] = {
1470         { ao_radio_test_cmd,    "C <1 start, 0 stop, none both>\0Radio carrier test" },
1471 #if CC1120_DEBUG
1472 #if HAS_APRS
1473         { ao_radio_aprs,        "G\0Send APRS packet" },
1474 #endif
1475         { ao_radio_show,        "R\0Show CC1120 status" },
1476         { ao_radio_beep,        "b\0Emit an RDF beacon" },
1477         { ao_radio_packet,      "p\0Send a test packet" },
1478         { ao_radio_test_recv,   "q\0Recv a test packet" },
1479 #endif
1480         { 0, NULL }
1481 };
1482
1483 void
1484 ao_radio_init(void)
1485 {
1486         ao_radio_configured = 0;
1487         ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN));
1488
1489 #if 0
1490         AO_CC1120_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));
1491         for (i = 0; i < 10000; i++) {
1492                 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
1493                         break;
1494         }
1495         AO_CC1120_SPI_CS_PORT->bsrr = (1 << AO_CC1120_SPI_CS_PIN);
1496         if (i == 10000)
1497                 ao_panic(AO_PANIC_SELF_TEST_CC1120);
1498 #endif
1499
1500         /* Enable the EXTI interrupt for the appropriate pin */
1501         ao_enable_port(AO_CC1120_INT_PORT);
1502         ao_exti_setup(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
1503                       AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
1504                       ao_radio_isr);
1505
1506         /* Enable the hacked up GPIO3 pin */
1507         ao_enable_port(AO_CC1120_MCU_WAKEUP_PORT);
1508         ao_exti_setup(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN,
1509                       AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
1510                       ao_radio_mcu_wakeup_isr);
1511
1512         ao_cmd_register(&ao_radio_cmds[0]);
1513 }