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