da5bbeba6d27799dc4ded5e6bec7219a0d10b527
[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 uint8_t ao_radio_fifo_write_stop(uint8_t status) {
187         ao_radio_deselect();
188         return status;
189 }
190
191 static uint8_t
192 ao_radio_fifo_write(uint8_t *data, uint8_t len)
193 {
194         uint8_t status = ao_radio_fifo_write_start();
195         ao_radio_spi_send(data, len);
196         return ao_radio_fifo_write_stop(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         return ao_radio_fifo_write_stop(status);
205 }
206
207 static uint8_t
208 ao_radio_int_pin(void)
209 {
210         return ao_gpio_get(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, AO_CC1120_INT);
211 }
212
213 #if CC1120_DEBUG
214 static uint8_t
215 ao_radio_status(void)
216 {
217         return ao_radio_strobe (CC1120_SNOP);
218 }
219 #endif
220
221 void
222 ao_radio_recv_abort(void)
223 {
224         ao_radio_abort = 1;
225         ao_wakeup(&ao_radio_wake);
226 }
227
228 #define ao_radio_rdf_value 0x55
229
230 static uint8_t
231 ao_radio_get_marc_status(void)
232 {
233         return ao_radio_reg_read(CC1120_MARC_STATUS1);
234 }
235
236 static void
237 ao_radio_mcu_wakeup_isr(void)
238 {
239         ao_radio_mcu_wake = 1;
240         ao_wakeup(&ao_radio_wake);
241 }
242
243
244 static void
245 ao_radio_check_marc_status(void)
246 {
247         ao_radio_mcu_wake = 0;
248         ao_radio_marc_status = ao_radio_get_marc_status();
249
250         /* Anyt other than 'tx/rx finished' means an error occurred */
251         if (ao_radio_marc_status & ~(CC1120_MARC_STATUS1_TX_FINISHED|CC1120_MARC_STATUS1_RX_FINISHED))
252                 ao_radio_abort = 1;
253         if (ao_radio_marc_status & (CC1120_MARC_STATUS1_TX_FINISHED))
254                 ao_radio_tx_finished = 1;
255 }
256
257 static void
258 ao_radio_isr(void)
259 {
260         ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
261         ao_radio_wake = 1;
262         ao_wakeup(&ao_radio_wake);
263 }
264
265 static void
266 ao_radio_enable_isr(void)
267 {
268         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
269         ao_exti_enable(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN);
270 }
271
272 static void
273 ao_radio_start_tx(void)
274 {
275         ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);
276         ao_radio_tx_finished = 0;
277         ao_radio_strobe(CC1120_STX);
278 }
279
280 static void
281 ao_radio_idle(void)
282 {
283         for (;;) {
284                 uint8_t state = (ao_radio_strobe(CC1120_SIDLE) >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK;
285                 if (state == CC1120_STATUS_STATE_IDLE)
286                         break;
287                 if (state == CC1120_STATUS_STATE_TX_FIFO_ERROR)
288                         ao_radio_strobe(CC1120_SFTX);
289                 if (state == CC1120_STATUS_STATE_RX_FIFO_ERROR)
290                         ao_radio_strobe(CC1120_SFRX);
291         }
292         /* Flush any pending TX bytes */
293         ao_radio_strobe(CC1120_SFTX);
294 }
295
296 /*
297  * Packet deviation
298  *
299  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
300  *
301  * Deviation for 38400 baud should be 20.5kHz:
302  *
303  *      32e6Hz / (2 ** 24) * (256 + 80) * (2 ** 5) = 20508Hz
304  *
305  * Deviation for 9600 baud should be 5.125kHz:
306  *
307  *      32e6Hz / (2 ** 24) * (256 + 80) * (2 ** 3) = 5127Hz
308  *
309  * Deviation for 2400 baud should be 1.28125kHz, but cc1111 and
310  * cc115l can't do that, so we'll use 1.5kHz instead:
311  *
312  *      32e6Hz / (2 ** 24) * (256 + 137) * (2 ** 1) = 1499Hz
313  */
314
315 #define PACKET_DEV_M_384        80
316 #define PACKET_DEV_E_384        5
317
318 #define PACKET_DEV_M_96         80
319 #define PACKET_DEV_E_96         3
320
321 #define PACKET_DEV_M_24         137
322 #define PACKET_DEV_E_24         1
323
324 /*
325  * For our packet data
326  *
327  *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
328  *      Rdata = -------------------------------------- * fosc
329  *                           2 ** 39
330  *
331  * Given the bit period of the baseband, T, the bandwidth of the
332  * baseband signal is B = 1/(2T).  The overall bandwidth of the
333  * modulated signal is then Channel bandwidth = 2Δf + 2B.
334  *
335  * 38400 -- 2 * 20500 + 38400 = 79.4 kHz
336  *  9600 -- 2 * 5.125 +  9600 = 19.9 kHz
337  *  2400 -- 2 * 1.5   +  2400 =  5.4 khz
338  *
339  * Symbol rate 38400 Baud:
340  *
341  *      DATARATE_M = 239914
342  *      DATARATE_E = 9
343  *      CHANBW = 79.4 (round to 100)
344  *
345  * Symbol rate 9600 Baud:
346  *
347  *      DATARATE_M = 239914
348  *      DATARATE_E = 7
349  *      CHANBW = 19.9 (round to 20)
350  *
351  * Symbol rate 2400 Baud:
352  *
353  *      DATARATE_M = 239914
354  *      DATARATE_E = 5
355  *      CHANBW = 5.0 (round to 8.0)
356  */
357
358 #define PACKET_DRATE_M  239914
359
360 #define PACKET_DRATE_E_384      9
361
362 /* 200 / 2 = 100 */
363 #define PACKET_CHAN_BW_384      ((0 << CC1120_CHAN_BW_CHFILT_BYPASS) | \
364                                  (CC1120_CHAN_BW_ADC_CIC_DECFACT_20 << CC1120_CHAN_BW_ADC_CIC_DECFACT) | \
365                                  (2 << CC1120_CHAN_BW_BB_CIC_DECFACT))
366
367 #define PACKET_DRATE_E_96       7
368 /* 200 / 10 = 20 */
369 #define PACKET_CHAN_BW_96       ((0 << CC1120_CHAN_BW_CHFILT_BYPASS) | \
370                                  (CC1120_CHAN_BW_ADC_CIC_DECFACT_20 << CC1120_CHAN_BW_ADC_CIC_DECFACT) | \
371                                  (10 << CC1120_CHAN_BW_BB_CIC_DECFACT))
372
373 #define PACKET_DRATE_E_24       5
374 /* 200 / 25 = 8 */
375 #define PACKET_CHAN_BW_24       ((0 << CC1120_CHAN_BW_CHFILT_BYPASS) | \
376                                  (CC1120_CHAN_BW_ADC_CIC_DECFACT_20 << CC1120_CHAN_BW_ADC_CIC_DECFACT) | \
377                                  (25 << CC1120_CHAN_BW_BB_CIC_DECFACT))
378
379 static const uint16_t packet_setup[] = {
380         CC1120_DRATE1,          ((PACKET_DRATE_M >> 8) & 0xff),
381         CC1120_DRATE0,          ((PACKET_DRATE_M >> 0) & 0xff),
382         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
383                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
384         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
385                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
386                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
387                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
388         CC1120_PKT_CFG0,        ((0 << CC1120_PKT_CFG0_RESERVED7) |
389                                  (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
390                                  (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
391                                  (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
392                                  (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
393         CC1120_PREAMBLE_CFG1,   ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
394                                  (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
395         AO_CC1120_MARC_GPIO_IOCFG,              CC1120_IOCFG_GPIO_CFG_MARC_MCU_WAKEUP,
396 };
397
398 static const uint16_t packet_setup_384[] = {
399         CC1120_DEVIATION_M,     PACKET_DEV_M_384,
400         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
401                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
402                                  (PACKET_DEV_E_384 << CC1120_MODCFG_DEV_E_DEV_E)),
403         CC1120_DRATE2,          ((PACKET_DRATE_E_384 << CC1120_DRATE2_DATARATE_E) |
404                                  (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
405         CC1120_CHAN_BW,         PACKET_CHAN_BW_384,
406         CC1120_PA_CFG0,         0x7b,
407 };
408
409 static const uint16_t packet_setup_96[] = {
410         CC1120_DEVIATION_M,     PACKET_DEV_M_96,
411         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
412                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
413                                  (PACKET_DEV_E_96 << CC1120_MODCFG_DEV_E_DEV_E)),
414         CC1120_DRATE2,          ((PACKET_DRATE_E_96 << CC1120_DRATE2_DATARATE_E) |
415                                  (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
416         CC1120_CHAN_BW,         PACKET_CHAN_BW_96,
417         CC1120_PA_CFG0,         0x7d,
418 };
419
420 static const uint16_t packet_setup_24[] = {
421         CC1120_DEVIATION_M,     PACKET_DEV_M_24,
422         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
423                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
424                                  (PACKET_DEV_E_24 << CC1120_MODCFG_DEV_E_DEV_E)),
425         CC1120_DRATE2,          ((PACKET_DRATE_E_24 << CC1120_DRATE2_DATARATE_E) |
426                                  (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
427         CC1120_CHAN_BW,         PACKET_CHAN_BW_24,
428         CC1120_PA_CFG0,         0x7e,
429 };
430
431 #define AO_CC1120_TX_BUFFER     64
432
433 static const uint16_t packet_tx_setup[] = {
434         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
435                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
436         CC1120_FIFO_CFG,        ((0 << CC1120_FIFO_CFG_CRC_AUTOFLUSH) |
437                                  (AO_CC1120_TX_BUFFER << CC1120_FIFO_CFG_FIFO_THR)),
438 };
439
440 static const uint16_t packet_rx_setup[] = {
441         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
442                                  (CC1120_PKT_CFG2_PKT_FORMAT_SYNCHRONOUS_SERIAL << CC1120_PKT_CFG2_PKT_FORMAT)),
443         AO_CC1120_INT_GPIO_IOCFG,               CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT,
444 };
445
446 /*
447  * RDF deviation is 5kHz
448  *
449  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
450  *
451  *      32e6Hz / (2 ** 24) * (256 + 71) * (2 ** 3) = 4989
452  */
453
454 #define RDF_DEV_E       3
455 #define RDF_DEV_M       71
456 #define RDF_PACKET_LEN  50
457
458 /*
459  * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
460  *
461  *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
462  *      Rdata = -------------------------------------- * fosc
463  *                           2 ** 39
464  *
465  *      DATARATE_M = 25166
466  *      DATARATE_E = 5
467  *
468  * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes
469  */
470 #define RDF_DRATE_E     5
471 #define RDF_DRATE_M     25166
472 #define RDF_PACKET_LEN  50
473
474 static const uint16_t rdf_setup[] = {
475         CC1120_DEVIATION_M,     RDF_DEV_M,
476         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
477                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
478                                  (RDF_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
479         CC1120_DRATE2,          ((RDF_DRATE_E << CC1120_DRATE2_DATARATE_E) |
480                                  (((RDF_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
481         CC1120_DRATE1,          ((RDF_DRATE_M >> 8) & 0xff),
482         CC1120_DRATE0,          ((RDF_DRATE_M >> 0) & 0xff),
483         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
484                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
485         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
486                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
487                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
488                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
489         CC1120_PKT_CFG0,        ((0 << CC1120_PKT_CFG0_RESERVED7) |
490                                  (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
491                                  (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
492                                  (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
493                                  (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
494         CC1120_PREAMBLE_CFG1,   ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_NONE << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
495                                  (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
496         CC1120_PA_CFG0,         0x7e,
497 };
498
499 /*
500  * APRS deviation is 3kHz
501  *
502  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
503  *
504  *      32e6Hz / (2 ** 24) * (256 + 137) * (2 ** 2) = 2998Hz
505  */
506
507 #define APRS_DEV_E      2
508 #define APRS_DEV_M      137
509
510 /*
511  * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate)
512  *
513  *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
514  *      Rdata = -------------------------------------- * fosc
515  *                           2 ** 39
516  *
517  *      DATARATE_M = 239914
518  *      DATARATE_E = 7
519  *
520  *      Rdata = 9599.998593330383301
521  *
522  */
523 #define APRS_DRATE_E    7
524 #define APRS_DRATE_M    239914
525
526 static const uint16_t aprs_setup[] = {
527         CC1120_DEVIATION_M,     APRS_DEV_M,
528         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
529                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
530                                  (APRS_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
531         CC1120_DRATE2,          ((APRS_DRATE_E << CC1120_DRATE2_DATARATE_E) |
532                                  (((APRS_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
533         CC1120_DRATE1,          ((APRS_DRATE_M >> 8) & 0xff),
534         CC1120_DRATE0,          ((APRS_DRATE_M >> 0) & 0xff),
535         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
536                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
537         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
538                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
539                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
540                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
541         CC1120_PREAMBLE_CFG1,   ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_NONE << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
542                                  (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
543         CC1120_PA_CFG0,         0x7d,
544         CC1120_FIFO_CFG,        ((0 << CC1120_FIFO_CFG_CRC_AUTOFLUSH) |
545                                  (AO_CC1120_TX_BUFFER << CC1120_FIFO_CFG_FIFO_THR)),
546 };
547
548 /*
549  * For Test mode, we want an unmodulated carrier. To do that, we
550  * set the deviation to zero and enable a preamble so that the radio
551  * turns on before we send any data
552  */
553
554 static const uint16_t test_setup[] = {
555         CC1120_DEVIATION_M,     0,
556         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
557                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
558                                  (0 << CC1120_MODCFG_DEV_E_DEV_E)),
559         CC1120_DRATE2,          ((APRS_DRATE_E << CC1120_DRATE2_DATARATE_E) |
560                                  (((APRS_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
561         CC1120_DRATE1,          ((APRS_DRATE_M >> 8) & 0xff),
562         CC1120_DRATE0,          ((APRS_DRATE_M >> 0) & 0xff),
563         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
564                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
565         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
566                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
567                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
568                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
569         CC1120_PREAMBLE_CFG1,   ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
570                                  (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
571 };
572
573 #define AO_PKT_CFG0_INFINITE ((0 << CC1120_PKT_CFG0_RESERVED7) |        \
574                               (CC1120_PKT_CFG0_LENGTH_CONFIG_INFINITE << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
575                               (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |      \
576                               (0 << CC1120_PKT_CFG0_UART_MODE_EN) |     \
577                               (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
578
579 #define AO_PKT_CFG0_FIXED ((0 << CC1120_PKT_CFG0_RESERVED7) |           \
580                            (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
581                            (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |         \
582                            (0 << CC1120_PKT_CFG0_UART_MODE_EN) |        \
583                            (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
584
585 static uint16_t ao_radio_mode;
586
587 #define AO_RADIO_MODE_BITS_PACKET       1
588 #define AO_RADIO_MODE_BITS_PACKET_TX    2
589 #define AO_RADIO_MODE_BITS_TX_BUF       4
590 #define AO_RADIO_MODE_BITS_TX_FINISH    8
591 #define AO_RADIO_MODE_BITS_PACKET_RX    16
592 #define AO_RADIO_MODE_BITS_RDF          32
593 #define AO_RADIO_MODE_BITS_APRS         64
594 #define AO_RADIO_MODE_BITS_TEST         128
595 #define AO_RADIO_MODE_BITS_INFINITE     256
596 #define AO_RADIO_MODE_BITS_FIXED        512
597
598 #define AO_RADIO_MODE_NONE              0
599 #define AO_RADIO_MODE_PACKET_TX_BUF     (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF)
600 #define AO_RADIO_MODE_PACKET_TX_FINISH  (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_FINISH)
601 #define AO_RADIO_MODE_PACKET_RX         (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_RX)
602 #define AO_RADIO_MODE_RDF               (AO_RADIO_MODE_BITS_RDF | AO_RADIO_MODE_BITS_TX_FINISH)
603 #define AO_RADIO_MODE_APRS_BUF          (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF)
604 #define AO_RADIO_MODE_APRS_LAST_BUF     (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_BUF)
605 #define AO_RADIO_MODE_APRS_FINISH       (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_FINISH)
606 #define AO_RADIO_MODE_TEST              (AO_RADIO_MODE_BITS_TEST | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF)
607
608 static void
609 _ao_radio_set_regs(const uint16_t *regs, int nreg)
610 {
611         int i;
612
613         for (i = 0; i < nreg; i++) {
614                 ao_radio_reg_write(regs[0], regs[1]);
615                 regs += 2;
616         }
617 }
618
619 #define ao_radio_set_regs(setup) _ao_radio_set_regs(setup, (sizeof (setup) / sizeof(setup[0])) >> 1)
620
621 static void
622 ao_radio_set_mode(uint16_t new_mode)
623 {
624         uint16_t changes;
625
626         if (new_mode == ao_radio_mode)
627                 return;
628
629         changes = new_mode & (~ao_radio_mode);
630
631         if (changes & AO_RADIO_MODE_BITS_PACKET) {
632                 ao_radio_set_regs(packet_setup);
633
634                 switch (ao_config.radio_rate) {
635                 default:
636                 case AO_RADIO_RATE_38400:
637                         ao_radio_set_regs(packet_setup_384);
638                         break;
639                 case AO_RADIO_RATE_9600:
640                         ao_radio_set_regs(packet_setup_96);
641                         break;
642                 case AO_RADIO_RATE_2400:
643                         ao_radio_set_regs(packet_setup_24);
644                         break;
645                 }
646         }
647
648         if (changes & AO_RADIO_MODE_BITS_PACKET_TX)
649                 ao_radio_set_regs(packet_tx_setup);
650
651         if (changes & AO_RADIO_MODE_BITS_TX_BUF)
652                 ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_TXFIFO_THR);
653
654         if (changes & AO_RADIO_MODE_BITS_TX_FINISH)
655                 ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);
656
657         if (changes & AO_RADIO_MODE_BITS_PACKET_RX)
658                 ao_radio_set_regs(packet_rx_setup);
659
660         if (changes & AO_RADIO_MODE_BITS_RDF)
661                 ao_radio_set_regs(rdf_setup);
662
663         if (changes & AO_RADIO_MODE_BITS_APRS)
664                 ao_radio_set_regs(aprs_setup);
665
666         if (changes & AO_RADIO_MODE_BITS_TEST)
667                 ao_radio_set_regs(test_setup);
668
669         if (changes & AO_RADIO_MODE_BITS_INFINITE)
670                 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_INFINITE);
671
672         if (changes & AO_RADIO_MODE_BITS_FIXED)
673                 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_FIXED);
674
675         ao_radio_mode = new_mode;
676 }
677
678 static const uint16_t radio_setup[] = {
679 #include "ao_cc1120_CC1120.h"
680 };
681
682 static uint8_t  ao_radio_configured = 0;
683
684 static void
685 ao_radio_setup(void)
686 {
687         ao_radio_strobe(CC1120_SRES);
688
689         ao_radio_set_regs(radio_setup);
690
691         ao_radio_mode = 0;
692
693         ao_config_get();
694
695         ao_radio_configured = 1;
696 }
697
698 static void
699 ao_radio_set_len(uint8_t len)
700 {
701         static uint8_t  last_len;
702
703         if (len != last_len) {
704                 ao_radio_reg_write(CC1120_PKT_LEN, len);
705                 last_len = len;
706         }
707 }
708
709 static void
710 ao_radio_get(uint8_t len)
711 {
712         static uint32_t last_radio_setting;
713         static uint8_t  last_radio_rate;
714
715         ao_mutex_get(&ao_radio_mutex);
716
717         if (!ao_radio_configured)
718                 ao_radio_setup();
719         if (ao_config.radio_setting != last_radio_setting) {
720                 ao_radio_reg_write(CC1120_FREQ2, ao_config.radio_setting >> 16);
721                 ao_radio_reg_write(CC1120_FREQ1, ao_config.radio_setting >> 8);
722                 ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting);
723                 last_radio_setting = ao_config.radio_setting;
724         }
725         if (ao_config.radio_rate != last_radio_rate) {
726                 ao_radio_mode &= ~AO_RADIO_MODE_BITS_PACKET;
727                 last_radio_rate = ao_config.radio_rate;
728         }
729         ao_radio_set_len(len);
730 }
731
732 #define ao_radio_put()  ao_mutex_put(&ao_radio_mutex)
733
734 static void
735 ao_rdf_start(uint8_t len)
736 {
737         ao_radio_abort = 0;
738         ao_radio_get(len);
739
740         ao_radio_set_mode(AO_RADIO_MODE_RDF);
741         ao_radio_wake = 0;
742
743 }
744
745 static void
746 ao_rdf_run(void)
747 {
748         ao_radio_start_tx();
749
750         ao_arch_block_interrupts();
751         while (!ao_radio_wake && !ao_radio_abort && !ao_radio_mcu_wake) {
752                 ao_radio_enable_isr();
753                 ao_sleep(&ao_radio_wake);
754         }
755         ao_arch_release_interrupts();
756         if (ao_radio_mcu_wake)
757                 ao_radio_check_marc_status();
758         if (!ao_radio_wake)
759                 ao_radio_idle();
760         ao_radio_put();
761 }
762
763 void
764 ao_radio_rdf(void)
765 {
766         ao_rdf_start(AO_RADIO_RDF_LEN);
767
768         ao_radio_fifo_write_fixed(ao_radio_rdf_value, AO_RADIO_RDF_LEN);
769
770         ao_rdf_run();
771 }
772
773 void
774 ao_radio_continuity(uint8_t c)
775 {
776         uint8_t i;
777         uint8_t status;
778
779         ao_rdf_start(AO_RADIO_CONT_TOTAL_LEN);
780
781         status = 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         status = ao_radio_fifo_write_stop(status);
791         (void) status;
792         ao_rdf_run();
793 }
794
795 void
796 ao_radio_rdf_abort(void)
797 {
798         ao_radio_abort = 1;
799         ao_wakeup(&ao_radio_wake);
800 }
801
802 static void
803 ao_radio_test_cmd(void)
804 {
805         uint8_t mode = 2;
806         static uint8_t radio_on;
807         ao_cmd_white();
808         if (ao_cmd_lex_c != '\n') {
809                 ao_cmd_decimal();
810                 mode = (uint8_t) ao_cmd_lex_u32;
811         }
812         mode++;
813         if ((mode & 2) && !radio_on) {
814 #if HAS_MONITOR
815                 ao_monitor_disable();
816 #endif
817 #if PACKET_HAS_SLAVE
818                 ao_packet_slave_stop();
819 #endif
820                 ao_radio_get(0xff);
821                 ao_radio_set_mode(AO_RADIO_MODE_TEST);
822                 ao_radio_strobe(CC1120_STX);
823 #if CC1120_TRACE
824                 { int t;
825                         for (t = 0; t < 10; t++) {
826                                 printf ("status: %02x\n", ao_radio_status());
827                                 ao_delay(AO_MS_TO_TICKS(100));
828                         }
829                 }
830 #endif
831                 radio_on = 1;
832         }
833         if (mode == 3) {
834                 printf ("Hit a character to stop..."); flush();
835                 getchar();
836                 putchar('\n');
837         }
838         if ((mode & 1) && radio_on) {
839                 ao_radio_idle();
840                 ao_radio_put();
841                 radio_on = 0;
842 #if HAS_MONITOR
843                 ao_monitor_enable();
844 #endif
845         }
846 }
847
848 static void
849 ao_radio_wait_isr(uint16_t timeout)
850 {
851         ao_arch_block_interrupts();
852         while (!ao_radio_wake && !ao_radio_mcu_wake && !ao_radio_abort)
853                 if (ao_sleep_for(&ao_radio_wake, timeout))
854                         ao_radio_abort = 1;
855         ao_arch_release_interrupts();
856         if (ao_radio_mcu_wake)
857                 ao_radio_check_marc_status();
858 }
859
860 static void
861 ao_radio_wait_fifo(void)
862 {
863         while (ao_radio_int_pin() != 0 && !ao_radio_abort) {
864                 ao_radio_wake = 0;
865                 ao_radio_enable_isr();
866                 ao_radio_wait_isr(0);
867         }
868 }
869
870 static uint8_t  tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
871
872 void
873 ao_radio_send(const void *d, uint8_t size)
874 {
875         uint8_t         *e = tx_data;
876         uint8_t         encode_len;
877         uint8_t         this_len;
878         uint8_t         started = 0;
879
880         encode_len = ao_fec_encode(d, size, tx_data);
881
882         ao_radio_get(encode_len);
883
884         ao_radio_abort = 0;
885
886         /* Flush any pending TX bytes */
887         ao_radio_strobe(CC1120_SFTX);
888
889         while (encode_len) {
890                 this_len = encode_len;
891
892                 if (started) {
893                         ao_radio_wait_fifo();
894                         if (ao_radio_abort)
895                                 break;
896                 }
897
898                 if (this_len > AO_CC1120_TX_BUFFER) {
899                         this_len = AO_CC1120_TX_BUFFER;
900                         ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF);
901                 } else {
902                         ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_FINISH);
903                 }
904
905                 ao_radio_fifo_write(e, this_len);
906                 e += this_len;
907                 encode_len -= this_len;
908
909                 if (!started) {
910                         ao_radio_start_tx();
911                         started = 1;
912                 }
913         }
914         while (started && !ao_radio_abort && !ao_radio_tx_finished) {
915                 ao_radio_wake = 0;
916                 ao_radio_enable_isr();
917                 ao_radio_wait_isr(0);
918         }
919         if (ao_radio_abort)
920                 ao_radio_idle();
921         ao_radio_put();
922 }
923
924 void
925 ao_radio_send_aprs(ao_radio_fill_func fill)
926 {
927         uint8_t buf[AO_CC1120_TX_BUFFER];
928         int     cnt;
929         int     total = 0;
930         uint8_t done = 0;
931         uint8_t started = 0;
932
933         ao_radio_get(0xff);
934
935         ao_radio_abort = 0;
936
937         ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);
938         while (!done) {
939                 cnt = (*fill)(buf, sizeof(buf));
940                 if (cnt < 0) {
941                         done = 1;
942                         cnt = -cnt;
943                 }
944                 total += cnt;
945
946                 /* Wait for some space in the fifo */
947                 if (started) {
948                         ao_radio_wait_fifo();
949                         if (ao_radio_abort)
950                                 break;
951                 }
952
953                 if (done) {
954                         ao_radio_set_len(total & 0xff);
955                         ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH);
956                 } else
957                         ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF);
958
959                 ao_radio_fifo_write(buf, cnt);
960
961                 if (!started) {
962                         ao_radio_start_tx();
963                         started = 1;
964                 }
965         }
966         /* Wait for the transmitter to go idle */
967         while (started && ao_radio_int_pin() != 0 && !ao_radio_abort) {
968                 ao_radio_wake = 0;
969                 ao_radio_enable_isr();
970                 ao_radio_wait_isr(0);
971         }
972         if (ao_radio_abort)
973                 ao_radio_idle();
974         ao_radio_put();
975 }
976
977 static uint8_t  rx_data[(AO_RADIO_MAX_RECV + 4) * 2 * 8];
978 static uint16_t rx_data_count;
979 static uint16_t rx_data_consumed;
980 static uint16_t rx_data_cur;
981 static uint8_t  rx_ignore;
982 static uint8_t  rx_waiting;
983 static uint8_t  rx_starting;
984 static uint8_t  rx_task_id;
985 static uint32_t rx_fast_start;
986 static uint32_t rx_slow_start;
987 static uint32_t rx_missed;
988
989 #if AO_PROFILE
990 static uint32_t rx_start_tick, rx_packet_tick, rx_done_tick, rx_last_done_tick;
991
992 uint32_t        ao_rx_start_tick, ao_rx_packet_tick, ao_rx_done_tick, ao_rx_last_done_tick;
993
994 #include <ao_profile.h>
995 #endif
996
997 static void
998 ao_radio_rx_isr(void)
999 {
1000         uint8_t d;
1001
1002         if (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(__xdata 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         ao_packet_slave_stop();
1450         ao_aprs_send();
1451 }
1452 #endif
1453 #endif
1454
1455 static const struct ao_cmds ao_radio_cmds[] = {
1456         { ao_radio_test_cmd,    "C <1 start, 0 stop, none both>\0Radio carrier test" },
1457 #if CC1120_DEBUG
1458 #if HAS_APRS
1459         { ao_radio_aprs,        "G\0Send APRS packet" },
1460 #endif
1461         { ao_radio_show,        "R\0Show CC1120 status" },
1462         { ao_radio_beep,        "b\0Emit an RDF beacon" },
1463         { ao_radio_packet,      "p\0Send a test packet" },
1464         { ao_radio_test_recv,   "q\0Recv a test packet" },
1465 #endif
1466         { 0, NULL }
1467 };
1468
1469 void
1470 ao_radio_init(void)
1471 {
1472         ao_radio_configured = 0;
1473         ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN));
1474
1475 #if 0
1476         AO_CC1120_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));
1477         for (i = 0; i < 10000; i++) {
1478                 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
1479                         break;
1480         }
1481         AO_CC1120_SPI_CS_PORT->bsrr = (1 << AO_CC1120_SPI_CS_PIN);
1482         if (i == 10000)
1483                 ao_panic(AO_PANIC_SELF_TEST_CC1120);
1484 #endif
1485
1486         /* Enable the EXTI interrupt for the appropriate pin */
1487         ao_enable_port(AO_CC1120_INT_PORT);
1488         ao_exti_setup(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
1489                       AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
1490                       ao_radio_isr);
1491
1492         /* Enable the hacked up GPIO3 pin */
1493         ao_enable_port(AO_CC1120_MCU_WAKEUP_PORT);
1494         ao_exti_setup(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN,
1495                       AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
1496                       ao_radio_mcu_wakeup_isr);
1497
1498         ao_cmd_register(&ao_radio_cmds[0]);
1499 }