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