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