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