Merge remote-tracking branch 'origin/master' into micropeak-logging
[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_1MHz)
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(void)
675 {
676         ao_arch_block_interrupts();
677         while (!ao_radio_wake && !ao_radio_mcu_wake && !ao_radio_abort)
678                 ao_sleep(&ao_radio_wake);
679         ao_arch_release_interrupts();
680         if (ao_radio_mcu_wake)
681                 ao_radio_check_marc_status();
682 }
683
684 static uint8_t
685 ao_radio_wait_tx(uint8_t wait_fifo)
686 {
687         uint8_t fifo_space = 0;
688
689         do {
690                 ao_radio_wait_isr();
691                 if (!wait_fifo)
692                         return 0;
693                 fifo_space = ao_radio_tx_fifo_space();
694         } while (!fifo_space && !ao_radio_abort);
695         return fifo_space;
696 }
697
698 static uint8_t  tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
699
700 void
701 ao_radio_send(const void *d, uint8_t size)
702 {
703         uint8_t         marc_status;
704         uint8_t         *e = tx_data;
705         uint8_t         encode_len;
706         uint8_t         this_len;
707         uint8_t         started = 0;
708         uint8_t         fifo_space;
709
710         encode_len = ao_fec_encode(d, size, tx_data);
711
712         ao_radio_get(encode_len);
713
714         started = 0;
715         fifo_space = CC1120_FIFO_SIZE;
716         while (encode_len) {
717                 this_len = encode_len;
718
719                 ao_radio_wake = 0;
720                 if (this_len > fifo_space) {
721                         this_len = fifo_space;
722                         ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF);
723                 } else {
724                         ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_FINISH);
725                 }
726
727                 ao_radio_fifo_write(e, this_len);
728                 e += this_len;
729                 encode_len -= this_len;
730
731                 if (!started) {
732                         ao_radio_start_tx();
733                         started = 1;
734                 } else {
735                         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
736                 }
737                         
738                 fifo_space = ao_radio_wait_tx(encode_len != 0);
739                 if (ao_radio_abort) {
740                         ao_radio_idle();
741                         break;
742                 }
743         }
744         ao_radio_put();
745 }
746
747 #define AO_RADIO_LOTS   64
748
749 void
750 ao_radio_send_lots(ao_radio_fill_func fill)
751 {
752         uint8_t buf[AO_RADIO_LOTS], *b;
753         int     cnt;
754         int     total = 0;
755         uint8_t done = 0;
756         uint8_t started = 0;
757         uint8_t fifo_space;
758
759         ao_radio_get(0xff);
760         fifo_space = CC1120_FIFO_SIZE;
761         while (!done) {
762                 cnt = (*fill)(buf, sizeof(buf));
763                 if (cnt < 0) {
764                         done = 1;
765                         cnt = -cnt;
766                 }
767                 total += cnt;
768
769                 /* At the last buffer, set the total length */
770                 if (done)
771                         ao_radio_set_len(total & 0xff);
772
773                 b = buf;
774                 while (cnt) {
775                         uint8_t this_len = cnt;
776
777                         /* Wait for some space in the fifo */
778                         while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
779                                 ao_radio_wake = 0;
780                                 ao_radio_wait_isr();
781                         }
782                         if (ao_radio_abort)
783                                 break;
784                         if (this_len > fifo_space)
785                                 this_len = fifo_space;
786
787                         cnt -= this_len;
788
789                         if (done) {
790                                 if (cnt)
791                                         ao_radio_set_mode(AO_RADIO_MODE_APRS_LAST_BUF);
792                                 else
793                                         ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH);
794                         } else
795                                 ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF);
796
797                         ao_radio_fifo_write(b, this_len);
798                         b += this_len;
799
800                         if (!started) {
801                                 ao_radio_start_tx();
802                                 started = 1;
803                         } else
804                                 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
805                 }
806                 if (ao_radio_abort) {
807                         ao_radio_idle();
808                         break;
809                 }
810                 /* Wait for the transmitter to go idle */
811                 ao_radio_wake = 0;
812                 ao_radio_wait_isr();
813         }
814         ao_radio_put();
815 }
816
817 static uint8_t  rx_data[(AO_RADIO_MAX_RECV + 4) * 2 * 8];
818 static uint16_t rx_data_count;
819 static uint16_t rx_data_consumed;
820 static uint16_t rx_data_cur;
821 static uint8_t  rx_ignore;
822 static uint8_t  rx_waiting;
823
824 #if AO_PROFILE
825 static uint32_t rx_start_tick, rx_packet_tick, rx_done_tick, rx_last_done_tick;
826
827 uint32_t        ao_rx_start_tick, ao_rx_packet_tick, ao_rx_done_tick, ao_rx_last_done_tick;
828
829 #include <ao_profile.h>
830 #endif
831
832 static void
833 ao_radio_rx_isr(void)
834 {
835         uint8_t d;
836
837         d = stm_spi2.dr;
838         stm_spi2.dr = 0;
839         if (rx_ignore == 0) {
840                 if (rx_data_cur >= rx_data_count)
841                         ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
842                 else
843                         rx_data[rx_data_cur++] = d;
844                 if (rx_waiting && rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) {
845 #if AO_PROFILE
846                         if (!rx_packet_tick)
847                                 rx_packet_tick = ao_profile_tick();
848                         if (rx_data_cur < rx_data_count)
849                                 return;
850 #endif
851                         rx_waiting = 0;
852                         ao_wakeup(&ao_radio_wake);
853                 }
854         } else {
855                 --rx_ignore;
856         }
857 }
858
859 static uint16_t
860 ao_radio_rx_wait(void)
861 {
862         do {
863                 if (ao_radio_mcu_wake)
864                         ao_radio_check_marc_status();
865                 ao_arch_block_interrupts();
866                 rx_waiting = 1;
867                 while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
868                        !ao_radio_abort &&
869                        !ao_radio_mcu_wake)
870                 {
871                         if (ao_sleep(&ao_radio_wake))
872                                 ao_radio_abort = 1;
873                 }
874                 rx_waiting = 0;
875                 ao_arch_release_interrupts();
876         } while (ao_radio_mcu_wake);
877         if (ao_radio_abort)
878                 return 0;
879         rx_data_consumed += AO_FEC_DECODE_BLOCK;
880 #if AO_PROFILE
881         return rx_data_cur - rx_data_consumed;
882 #endif
883         return AO_FEC_DECODE_BLOCK;
884 }
885
886 uint8_t
887 ao_radio_recv(__xdata void *d, uint8_t size)
888 {
889         uint8_t         len;
890         uint16_t        i;
891         uint8_t         rssi;
892         uint8_t         ret;
893         static int been_here = 0;
894
895         size -= 2;                      /* status bytes */
896         if (size > AO_RADIO_MAX_RECV) {
897                 ao_delay(AO_SEC_TO_TICKS(1));
898                 return 0;
899         }
900 #if AO_PROFILE
901         rx_start_tick = ao_profile_tick();
902         rx_packet_tick = 0;
903 #endif
904         len = size + 2;                 /* CRC bytes */
905         len += 1 + ~(len & 1);          /* 1 or two pad bytes */
906         len *= 2;                       /* 1/2 rate convolution */
907         rx_data_count = len * 8;        /* bytes to bits */
908         rx_data_cur = 0;
909         rx_data_consumed = 0;
910         rx_ignore = 2;
911
912         /* Must be set before changing the frequency; any abort
913          * after the frequency is set needs to terminate the read
914          * so that the registers can be reprogrammed
915          */
916         ao_radio_abort = 0;
917
918         /* configure interrupt pin */
919         ao_radio_get(len);
920         ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX);
921
922         ao_radio_wake = 0;
923         ao_radio_mcu_wake = 0;
924
925         stm_spi2.cr2 = 0;
926
927         /* clear any RXNE */
928         (void) stm_spi2.dr;
929
930         /* Have the radio signal when the preamble quality goes high */
931         ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_PQT_REACHED);
932         ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
933                          AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_HIGH);
934         ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);
935         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
936         ao_exti_enable(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN);
937
938         ao_radio_strobe(CC1120_SRX);
939
940         /* Wait for the preamble to appear */
941         ao_radio_wait_isr();
942         if (ao_radio_abort)
943                 goto abort;
944
945         ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT);
946         ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
947                          AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH);
948
949         ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
950         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
951
952         ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
953
954         ret = ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);
955
956         ao_radio_burst_read_stop();
957
958 abort:
959         ao_radio_strobe(CC1120_SIDLE);
960
961         /* Convert from 'real' rssi to cc1111-style values */
962
963         rssi = AO_RADIO_FROM_RSSI(ao_radio_reg_read(CC1120_RSSI1));
964
965         ao_radio_put();
966
967         /* Store the received RSSI value; the crc-OK byte is already done */
968
969         ((uint8_t *) d)[size] = (uint8_t) rssi;
970
971 #if AO_PROFILE
972         rx_last_done_tick = rx_done_tick;
973         rx_done_tick = ao_profile_tick();
974
975         ao_rx_start_tick = rx_start_tick;
976         ao_rx_packet_tick = rx_packet_tick;
977         ao_rx_done_tick = rx_done_tick;
978         ao_rx_last_done_tick = rx_last_done_tick;
979 #endif
980
981         return ret;
982 }
983
984
985 #if CC1120_DEBUG
986 static char *cc1120_state_name[] = {
987         [CC1120_STATUS_STATE_IDLE] = "IDLE",
988         [CC1120_STATUS_STATE_RX] = "RX",
989         [CC1120_STATUS_STATE_TX] = "TX",
990         [CC1120_STATUS_STATE_FSTXON] = "FSTXON",
991         [CC1120_STATUS_STATE_CALIBRATE] = "CALIBRATE",
992         [CC1120_STATUS_STATE_SETTLING] = "SETTLING",
993         [CC1120_STATUS_STATE_RX_FIFO_ERROR] = "RX_FIFO_ERROR",
994         [CC1120_STATUS_STATE_TX_FIFO_ERROR] = "TX_FIFO_ERROR",
995 };
996
997 struct ao_cc1120_reg {
998         uint16_t        addr;
999         char            *name;
1000 };
1001
1002 const static struct ao_cc1120_reg ao_cc1120_reg[] = {
1003         { .addr = CC1120_IOCFG3,        .name = "IOCFG3" },
1004         { .addr = CC1120_IOCFG2,        .name = "IOCFG2" },
1005         { .addr = CC1120_IOCFG1,        .name = "IOCFG1" },
1006         { .addr = CC1120_IOCFG0,        .name = "IOCFG0" },
1007         { .addr = CC1120_SYNC3, .name = "SYNC3" },
1008         { .addr = CC1120_SYNC2, .name = "SYNC2" },
1009         { .addr = CC1120_SYNC1, .name = "SYNC1" },
1010         { .addr = CC1120_SYNC0, .name = "SYNC0" },
1011         { .addr = CC1120_SYNC_CFG1,     .name = "SYNC_CFG1" },
1012         { .addr = CC1120_SYNC_CFG0,     .name = "SYNC_CFG0" },
1013         { .addr = CC1120_DEVIATION_M,   .name = "DEVIATION_M" },
1014         { .addr = CC1120_MODCFG_DEV_E,  .name = "MODCFG_DEV_E" },
1015         { .addr = CC1120_DCFILT_CFG,    .name = "DCFILT_CFG" },
1016         { .addr = CC1120_PREAMBLE_CFG1, .name = "PREAMBLE_CFG1" },
1017         { .addr = CC1120_PREAMBLE_CFG0, .name = "PREAMBLE_CFG0" },
1018         { .addr = CC1120_FREQ_IF_CFG,   .name = "FREQ_IF_CFG" },
1019         { .addr = CC1120_IQIC,  .name = "IQIC" },
1020         { .addr = CC1120_CHAN_BW,       .name = "CHAN_BW" },
1021         { .addr = CC1120_MDMCFG1,       .name = "MDMCFG1" },
1022         { .addr = CC1120_MDMCFG0,       .name = "MDMCFG0" },
1023         { .addr = CC1120_DRATE2,        .name = "DRATE2" },
1024         { .addr = CC1120_DRATE1,        .name = "DRATE1" },
1025         { .addr = CC1120_DRATE0,        .name = "DRATE0" },
1026         { .addr = CC1120_AGC_REF,       .name = "AGC_REF" },
1027         { .addr = CC1120_AGC_CS_THR,    .name = "AGC_CS_THR" },
1028         { .addr = CC1120_AGC_GAIN_ADJUST,       .name = "AGC_GAIN_ADJUST" },
1029         { .addr = CC1120_AGC_CFG3,      .name = "AGC_CFG3" },
1030         { .addr = CC1120_AGC_CFG2,      .name = "AGC_CFG2" },
1031         { .addr = CC1120_AGC_CFG1,      .name = "AGC_CFG1" },
1032         { .addr = CC1120_AGC_CFG0,      .name = "AGC_CFG0" },
1033         { .addr = CC1120_FIFO_CFG,      .name = "FIFO_CFG" },
1034         { .addr = CC1120_DEV_ADDR,      .name = "DEV_ADDR" },
1035         { .addr = CC1120_SETTLING_CFG,  .name = "SETTLING_CFG" },
1036         { .addr = CC1120_FS_CFG,        .name = "FS_CFG" },
1037         { .addr = CC1120_WOR_CFG1,      .name = "WOR_CFG1" },
1038         { .addr = CC1120_WOR_CFG0,      .name = "WOR_CFG0" },
1039         { .addr = CC1120_WOR_EVENT0_MSB,        .name = "WOR_EVENT0_MSB" },
1040         { .addr = CC1120_WOR_EVENT0_LSB,        .name = "WOR_EVENT0_LSB" },
1041         { .addr = CC1120_PKT_CFG2,      .name = "PKT_CFG2" },
1042         { .addr = CC1120_PKT_CFG1,      .name = "PKT_CFG1" },
1043         { .addr = CC1120_PKT_CFG0,      .name = "PKT_CFG0" },
1044         { .addr = CC1120_RFEND_CFG1,    .name = "RFEND_CFG1" },
1045         { .addr = CC1120_RFEND_CFG0,    .name = "RFEND_CFG0" },
1046         { .addr = CC1120_PA_CFG2,       .name = "PA_CFG2" },
1047         { .addr = CC1120_PA_CFG1,       .name = "PA_CFG1" },
1048         { .addr = CC1120_PA_CFG0,       .name = "PA_CFG0" },
1049         { .addr = CC1120_PKT_LEN,       .name = "PKT_LEN" },
1050         { .addr = CC1120_IF_MIX_CFG,    .name = "IF_MIX_CFG" },
1051         { .addr = CC1120_FREQOFF_CFG,   .name = "FREQOFF_CFG" },
1052         { .addr = CC1120_TOC_CFG,       .name = "TOC_CFG" },
1053         { .addr = CC1120_MARC_SPARE,    .name = "MARC_SPARE" },
1054         { .addr = CC1120_ECG_CFG,       .name = "ECG_CFG" },
1055         { .addr = CC1120_SOFT_TX_DATA_CFG,      .name = "SOFT_TX_DATA_CFG" },
1056         { .addr = CC1120_EXT_CTRL,      .name = "EXT_CTRL" },
1057         { .addr = CC1120_RCCAL_FINE,    .name = "RCCAL_FINE" },
1058         { .addr = CC1120_RCCAL_COARSE,  .name = "RCCAL_COARSE" },
1059         { .addr = CC1120_RCCAL_OFFSET,  .name = "RCCAL_OFFSET" },
1060         { .addr = CC1120_FREQOFF1,      .name = "FREQOFF1" },
1061         { .addr = CC1120_FREQOFF0,      .name = "FREQOFF0" },
1062         { .addr = CC1120_FREQ2, .name = "FREQ2" },
1063         { .addr = CC1120_FREQ1, .name = "FREQ1" },
1064         { .addr = CC1120_FREQ0, .name = "FREQ0" },
1065         { .addr = CC1120_IF_ADC2,       .name = "IF_ADC2" },
1066         { .addr = CC1120_IF_ADC1,       .name = "IF_ADC1" },
1067         { .addr = CC1120_IF_ADC0,       .name = "IF_ADC0" },
1068         { .addr = CC1120_FS_DIG1,       .name = "FS_DIG1" },
1069         { .addr = CC1120_FS_DIG0,       .name = "FS_DIG0" },
1070         { .addr = CC1120_FS_CAL3,       .name = "FS_CAL3" },
1071         { .addr = CC1120_FS_CAL2,       .name = "FS_CAL2" },
1072         { .addr = CC1120_FS_CAL1,       .name = "FS_CAL1" },
1073         { .addr = CC1120_FS_CAL0,       .name = "FS_CAL0" },
1074         { .addr = CC1120_FS_CHP,        .name = "FS_CHP" },
1075         { .addr = CC1120_FS_DIVTWO,     .name = "FS_DIVTWO" },
1076         { .addr = CC1120_FS_DSM1,       .name = "FS_DSM1" },
1077         { .addr = CC1120_FS_DSM0,       .name = "FS_DSM0" },
1078         { .addr = CC1120_FS_DVC1,       .name = "FS_DVC1" },
1079         { .addr = CC1120_FS_DVC0,       .name = "FS_DVC0" },
1080         { .addr = CC1120_FS_LBI,        .name = "FS_LBI" },
1081         { .addr = CC1120_FS_PFD,        .name = "FS_PFD" },
1082         { .addr = CC1120_FS_PRE,        .name = "FS_PRE" },
1083         { .addr = CC1120_FS_REG_DIV_CML,        .name = "FS_REG_DIV_CML" },
1084         { .addr = CC1120_FS_SPARE,      .name = "FS_SPARE" },
1085         { .addr = CC1120_FS_VCO4,       .name = "FS_VCO4" },
1086         { .addr = CC1120_FS_VCO3,       .name = "FS_VCO3" },
1087         { .addr = CC1120_FS_VCO2,       .name = "FS_VCO2" },
1088         { .addr = CC1120_FS_VCO1,       .name = "FS_VCO1" },
1089         { .addr = CC1120_FS_VCO0,       .name = "FS_VCO0" },
1090         { .addr = CC1120_GBIAS6,        .name = "GBIAS6" },
1091         { .addr = CC1120_GBIAS5,        .name = "GBIAS5" },
1092         { .addr = CC1120_GBIAS4,        .name = "GBIAS4" },
1093         { .addr = CC1120_GBIAS3,        .name = "GBIAS3" },
1094         { .addr = CC1120_GBIAS2,        .name = "GBIAS2" },
1095         { .addr = CC1120_GBIAS1,        .name = "GBIAS1" },
1096         { .addr = CC1120_GBIAS0,        .name = "GBIAS0" },
1097         { .addr = CC1120_IFAMP, .name = "IFAMP" },
1098         { .addr = CC1120_LNA,   .name = "LNA" },
1099         { .addr = CC1120_RXMIX, .name = "RXMIX" },
1100         { .addr = CC1120_XOSC5, .name = "XOSC5" },
1101         { .addr = CC1120_XOSC4, .name = "XOSC4" },
1102         { .addr = CC1120_XOSC3, .name = "XOSC3" },
1103         { .addr = CC1120_XOSC2, .name = "XOSC2" },
1104         { .addr = CC1120_XOSC1, .name = "XOSC1" },
1105         { .addr = CC1120_XOSC0, .name = "XOSC0" },
1106         { .addr = CC1120_ANALOG_SPARE,  .name = "ANALOG_SPARE" },
1107         { .addr = CC1120_PA_CFG3,       .name = "PA_CFG3" },
1108         { .addr = CC1120_WOR_TIME1,     .name = "WOR_TIME1" },
1109         { .addr = CC1120_WOR_TIME0,     .name = "WOR_TIME0" },
1110         { .addr = CC1120_WOR_CAPTURE1,  .name = "WOR_CAPTURE1" },
1111         { .addr = CC1120_WOR_CAPTURE0,  .name = "WOR_CAPTURE0" },
1112         { .addr = CC1120_BIST,  .name = "BIST" },
1113         { .addr = CC1120_DCFILTOFFSET_I1,       .name = "DCFILTOFFSET_I1" },
1114         { .addr = CC1120_DCFILTOFFSET_I0,       .name = "DCFILTOFFSET_I0" },
1115         { .addr = CC1120_DCFILTOFFSET_Q1,       .name = "DCFILTOFFSET_Q1" },
1116         { .addr = CC1120_DCFILTOFFSET_Q0,       .name = "DCFILTOFFSET_Q0" },
1117         { .addr = CC1120_IQIE_I1,       .name = "IQIE_I1" },
1118         { .addr = CC1120_IQIE_I0,       .name = "IQIE_I0" },
1119         { .addr = CC1120_IQIE_Q1,       .name = "IQIE_Q1" },
1120         { .addr = CC1120_IQIE_Q0,       .name = "IQIE_Q0" },
1121         { .addr = CC1120_RSSI1, .name = "RSSI1" },
1122         { .addr = CC1120_RSSI0, .name = "RSSI0" },
1123         { .addr = CC1120_MARCSTATE,     .name = "MARCSTATE" },
1124         { .addr = CC1120_LQI_VAL,       .name = "LQI_VAL" },
1125         { .addr = CC1120_PQT_SYNC_ERR,  .name = "PQT_SYNC_ERR" },
1126         { .addr = CC1120_DEM_STATUS,    .name = "DEM_STATUS" },
1127         { .addr = CC1120_FREQOFF_EST1,  .name = "FREQOFF_EST1" },
1128         { .addr = CC1120_FREQOFF_EST0,  .name = "FREQOFF_EST0" },
1129         { .addr = CC1120_AGC_GAIN3,     .name = "AGC_GAIN3" },
1130         { .addr = CC1120_AGC_GAIN2,     .name = "AGC_GAIN2" },
1131         { .addr = CC1120_AGC_GAIN1,     .name = "AGC_GAIN1" },
1132         { .addr = CC1120_AGC_GAIN0,     .name = "AGC_GAIN0" },
1133         { .addr = CC1120_SOFT_RX_DATA_OUT,      .name = "SOFT_RX_DATA_OUT" },
1134         { .addr = CC1120_SOFT_TX_DATA_IN,       .name = "SOFT_TX_DATA_IN" },
1135         { .addr = CC1120_ASK_SOFT_RX_DATA,      .name = "ASK_SOFT_RX_DATA" },
1136         { .addr = CC1120_RNDGEN,        .name = "RNDGEN" },
1137         { .addr = CC1120_MAGN2, .name = "MAGN2" },
1138         { .addr = CC1120_MAGN1, .name = "MAGN1" },
1139         { .addr = CC1120_MAGN0, .name = "MAGN0" },
1140         { .addr = CC1120_ANG1,  .name = "ANG1" },
1141         { .addr = CC1120_ANG0,  .name = "ANG0" },
1142         { .addr = CC1120_CHFILT_I2,     .name = "CHFILT_I2" },
1143         { .addr = CC1120_CHFILT_I1,     .name = "CHFILT_I1" },
1144         { .addr = CC1120_CHFILT_I0,     .name = "CHFILT_I0" },
1145         { .addr = CC1120_CHFILT_Q2,     .name = "CHFILT_Q2" },
1146         { .addr = CC1120_CHFILT_Q1,     .name = "CHFILT_Q1" },
1147         { .addr = CC1120_CHFILT_Q0,     .name = "CHFILT_Q0" },
1148         { .addr = CC1120_GPIO_STATUS,   .name = "GPIO_STATUS" },
1149         { .addr = CC1120_FSCAL_CTRL,    .name = "FSCAL_CTRL" },
1150         { .addr = CC1120_PHASE_ADJUST,  .name = "PHASE_ADJUST" },
1151         { .addr = CC1120_PARTNUMBER,    .name = "PARTNUMBER" },
1152         { .addr = CC1120_PARTVERSION,   .name = "PARTVERSION" },
1153         { .addr = CC1120_SERIAL_STATUS, .name = "SERIAL_STATUS" },
1154         { .addr = CC1120_RX_STATUS,     .name = "RX_STATUS" },
1155         { .addr = CC1120_TX_STATUS,     .name = "TX_STATUS" },
1156         { .addr = CC1120_MARC_STATUS1,  .name = "MARC_STATUS1" },
1157         { .addr = CC1120_MARC_STATUS0,  .name = "MARC_STATUS0" },
1158         { .addr = CC1120_PA_IFAMP_TEST, .name = "PA_IFAMP_TEST" },
1159         { .addr = CC1120_FSRF_TEST,     .name = "FSRF_TEST" },
1160         { .addr = CC1120_PRE_TEST,      .name = "PRE_TEST" },
1161         { .addr = CC1120_PRE_OVR,       .name = "PRE_OVR" },
1162         { .addr = CC1120_ADC_TEST,      .name = "ADC_TEST" },
1163         { .addr = CC1120_DVC_TEST,      .name = "DVC_TEST" },
1164         { .addr = CC1120_ATEST, .name = "ATEST" },
1165         { .addr = CC1120_ATEST_LVDS,    .name = "ATEST_LVDS" },
1166         { .addr = CC1120_ATEST_MODE,    .name = "ATEST_MODE" },
1167         { .addr = CC1120_XOSC_TEST1,    .name = "XOSC_TEST1" },
1168         { .addr = CC1120_XOSC_TEST0,    .name = "XOSC_TEST0" },
1169         { .addr = CC1120_RXFIRST,       .name = "RXFIRST" },
1170         { .addr = CC1120_TXFIRST,       .name = "TXFIRST" },
1171         { .addr = CC1120_RXLAST,        .name = "RXLAST" },
1172         { .addr = CC1120_TXLAST,        .name = "TXLAST" },
1173         { .addr = CC1120_NUM_TXBYTES,   .name = "NUM_TXBYTES" },
1174         { .addr = CC1120_NUM_RXBYTES,   .name = "NUM_RXBYTES" },
1175         { .addr = CC1120_FIFO_NUM_TXBYTES,      .name = "FIFO_NUM_TXBYTES" },
1176         { .addr = CC1120_FIFO_NUM_RXBYTES,      .name = "FIFO_NUM_RXBYTES" },
1177 };
1178
1179 #define AO_NUM_CC1120_REG       (sizeof ao_cc1120_reg / sizeof ao_cc1120_reg[0])
1180
1181 static void ao_radio_show(void) {
1182         uint8_t status = ao_radio_status();
1183         int     i;
1184
1185         ao_radio_get(0xff);
1186         status = ao_radio_status();
1187         printf ("Status:   %02x\n", status);
1188         printf ("CHIP_RDY: %d\n", (status >> CC1120_STATUS_CHIP_RDY) & 1);
1189         printf ("STATE:    %s\n", cc1120_state_name[(status >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK]);
1190         printf ("MARC:     %02x\n", ao_radio_get_marc_status());
1191
1192         for (i = 0; i < AO_NUM_CC1120_REG; i++)
1193                 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name);
1194         ao_radio_put();
1195 }
1196
1197 static void ao_radio_beep(void) {
1198         ao_radio_rdf();
1199 }
1200
1201 static void ao_radio_packet(void) {
1202         static const uint8_t packet[] = {
1203 #if 1
1204                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1205                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1206                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1207                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1208 #else
1209                 3, 1, 2, 3
1210 #endif
1211         };
1212
1213         ao_radio_send(packet, sizeof (packet));
1214 }
1215
1216 void
1217 ao_radio_test_recv()
1218 {
1219         uint8_t bytes[34];
1220         uint8_t b;
1221
1222         if (ao_radio_recv(bytes, 34)) {
1223                 if (bytes[33] & 0x80)
1224                         printf ("CRC OK");
1225                 else
1226                         printf ("CRC BAD");
1227                 printf (" RSSI %d", AO_RSSI_FROM_RADIO(bytes[32]));
1228                 for (b = 0; b < 32; b++)
1229                         printf (" %02x", bytes[b]);
1230                 printf ("\n");
1231         }
1232 }
1233
1234 #if HAS_APRS
1235 #include <ao_aprs.h>
1236
1237 static void
1238 ao_radio_aprs()
1239 {
1240         ao_packet_slave_stop();
1241         ao_aprs_send();
1242 }
1243 #endif
1244
1245 #endif
1246
1247 static const struct ao_cmds ao_radio_cmds[] = {
1248         { ao_radio_test_cmd,    "C <1 start, 0 stop, none both>\0Radio carrier test" },
1249 #if CC1120_DEBUG
1250 #if HAS_APRS
1251         { ao_radio_aprs,        "G\0Send APRS packet" },
1252 #endif
1253         { ao_radio_show,        "R\0Show CC1120 status" },
1254         { ao_radio_beep,        "b\0Emit an RDF beacon" },
1255         { ao_radio_packet,      "p\0Send a test packet" },
1256         { ao_radio_test_recv,   "q\0Recv a test packet" },
1257 #endif
1258         { 0, NULL }
1259 };
1260
1261 void
1262 ao_radio_init(void)
1263 {
1264         int     i;
1265
1266         ao_radio_configured = 0;
1267         ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN));
1268
1269 #if 0
1270         AO_CC1120_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));
1271         for (i = 0; i < 10000; i++) {
1272                 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
1273                         break;
1274         }
1275         AO_CC1120_SPI_CS_PORT->bsrr = (1 << AO_CC1120_SPI_CS_PIN);
1276         if (i == 10000)
1277                 ao_panic(AO_PANIC_SELF_TEST_CC1120);
1278 #endif
1279
1280         /* Enable the EXTI interrupt for the appropriate pin */
1281         ao_enable_port(AO_CC1120_INT_PORT);
1282         ao_exti_setup(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
1283                       AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
1284                       ao_radio_isr);
1285
1286         /* Enable the hacked up GPIO3 pin */
1287         ao_enable_port(AO_CC1120_MCU_WAKEUP_PORT);
1288         ao_exti_setup(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN,
1289                       AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
1290                       ao_radio_mcu_wakeup_isr);
1291
1292         ao_cmd_register(&ao_radio_cmds[0]);
1293 }