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