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