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