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