altos: Use symbolic names for ublox packet id
[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 3kHz
396  *
397  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
398  *
399  *      32e6Hz / (2 ** 24) * (256 + 137) * (2 ** 2) = 2998Hz
400  */
401
402 #define APRS_DEV_E      2
403 #define APRS_DEV_M      137
404
405 /*
406  * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate)
407  *
408  *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
409  *      Rdata = -------------------------------------- * fosc
410  *                           2 ** 39
411  *
412  *      DATARATE_M = 239914
413  *      DATARATE_E = 7
414  *
415  *      Rdata = 9599.998593330383301
416  *
417  */
418 #define APRS_DRATE_E    7
419 #define APRS_DRATE_M    239914
420
421 static const uint16_t aprs_setup[] = {
422         CC1120_DEVIATION_M,     APRS_DEV_M,
423         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
424                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
425                                  (APRS_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
426         CC1120_DRATE2,          ((APRS_DRATE_E << CC1120_DRATE2_DATARATE_E) |
427                                  (((APRS_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
428         CC1120_DRATE1,          ((APRS_DRATE_M >> 8) & 0xff),
429         CC1120_DRATE0,          ((APRS_DRATE_M >> 0) & 0xff),
430         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
431                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
432         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
433                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
434                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
435                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
436 };
437
438 #define AO_PKT_CFG0_INFINITE ((0 << CC1120_PKT_CFG0_RESERVED7) |        \
439                               (CC1120_PKT_CFG0_LENGTH_CONFIG_INFINITE << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
440                               (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |      \
441                               (0 << CC1120_PKT_CFG0_UART_MODE_EN) |     \
442                               (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
443
444 #define AO_PKT_CFG0_FIXED ((0 << CC1120_PKT_CFG0_RESERVED7) |           \
445                            (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
446                            (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |         \
447                            (0 << CC1120_PKT_CFG0_UART_MODE_EN) |        \
448                            (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
449
450 static uint16_t ao_radio_mode;
451
452 #define AO_RADIO_MODE_BITS_PACKET       1
453 #define AO_RADIO_MODE_BITS_PACKET_TX    2
454 #define AO_RADIO_MODE_BITS_TX_BUF       4
455 #define AO_RADIO_MODE_BITS_TX_FINISH    8
456 #define AO_RADIO_MODE_BITS_PACKET_RX    16
457 #define AO_RADIO_MODE_BITS_RDF          32
458 #define AO_RADIO_MODE_BITS_APRS         64
459 #define AO_RADIO_MODE_BITS_INFINITE     128
460 #define AO_RADIO_MODE_BITS_FIXED        256
461
462 #define AO_RADIO_MODE_NONE              0
463 #define AO_RADIO_MODE_PACKET_TX_BUF     (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF)
464 #define AO_RADIO_MODE_PACKET_TX_FINISH  (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_FINISH)
465 #define AO_RADIO_MODE_PACKET_RX         (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_RX)
466 #define AO_RADIO_MODE_RDF               (AO_RADIO_MODE_BITS_RDF | AO_RADIO_MODE_BITS_TX_FINISH)
467 #define AO_RADIO_MODE_APRS_BUF          (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF)
468 #define AO_RADIO_MODE_APRS_LAST_BUF     (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_BUF)
469 #define AO_RADIO_MODE_APRS_FINISH       (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_FINISH)
470
471 static void
472 ao_radio_set_mode(uint16_t new_mode)
473 {
474         uint16_t changes;
475         int i;
476
477         if (new_mode == ao_radio_mode)
478                 return;
479
480         changes = new_mode & (~ao_radio_mode);
481         if (changes & AO_RADIO_MODE_BITS_PACKET)
482                 for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2)
483                         ao_radio_reg_write(packet_setup[i], packet_setup[i+1]);
484
485         if (changes & AO_RADIO_MODE_BITS_PACKET_TX)
486                 for (i = 0; i < sizeof (packet_tx_setup) / sizeof (packet_tx_setup[0]); i += 2)
487                         ao_radio_reg_write(packet_tx_setup[i], packet_tx_setup[i+1]);
488                 
489         if (changes & AO_RADIO_MODE_BITS_TX_BUF)
490                 ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_TXFIFO_THR);
491
492         if (changes & AO_RADIO_MODE_BITS_TX_FINISH)
493                 ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);
494
495         if (changes & AO_RADIO_MODE_BITS_PACKET_RX)
496                 for (i = 0; i < sizeof (packet_rx_setup) / sizeof (packet_rx_setup[0]); i += 2)
497                         ao_radio_reg_write(packet_rx_setup[i], packet_rx_setup[i+1]);
498                 
499         if (changes & AO_RADIO_MODE_BITS_RDF)
500                 for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
501                         ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
502
503         if (changes & AO_RADIO_MODE_BITS_APRS)
504                 for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2)
505                         ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]);
506
507         if (changes & AO_RADIO_MODE_BITS_INFINITE)
508                 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_INFINITE);
509
510         if (changes & AO_RADIO_MODE_BITS_FIXED)
511                 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_FIXED);
512
513         ao_radio_mode = new_mode;
514 }
515
516 static const uint16_t radio_setup[] = {
517 #include "ao_cc1120_CC1120.h"
518 };
519
520 static uint8_t  ao_radio_configured = 0;
521
522 static void
523 ao_radio_setup(void)
524 {
525         int     i;
526
527         ao_radio_strobe(CC1120_SRES);
528
529         for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
530                 ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
531
532         ao_radio_mode = 0;
533
534         ao_config_get();
535
536         ao_radio_configured = 1;
537 }
538
539 static void
540 ao_radio_set_len(uint8_t len)
541 {
542         static uint8_t  last_len;
543
544         if (len != last_len) {
545                 ao_radio_reg_write(CC1120_PKT_LEN, len);
546                 last_len = len;
547         }
548 }
549
550 static void
551 ao_radio_get(uint8_t len)
552 {
553         static uint32_t last_radio_setting;
554
555         ao_mutex_get(&ao_radio_mutex);
556
557         if (!ao_radio_configured)
558                 ao_radio_setup();
559         if (ao_config.radio_setting != last_radio_setting) {
560                 ao_radio_reg_write(CC1120_FREQ2, ao_config.radio_setting >> 16);
561                 ao_radio_reg_write(CC1120_FREQ1, ao_config.radio_setting >> 8);
562                 ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting);
563                 last_radio_setting = ao_config.radio_setting;
564         }
565         ao_radio_set_len(len);
566 }
567
568 #define ao_radio_put()  ao_mutex_put(&ao_radio_mutex)
569
570 static void
571 ao_rdf_start(uint8_t len)
572 {
573         ao_radio_abort = 0;
574         ao_radio_get(len);
575
576         ao_radio_set_mode(AO_RADIO_MODE_RDF);
577         ao_radio_wake = 0;
578
579 }
580
581 static void
582 ao_rdf_run(void)
583 {
584         ao_radio_start_tx();
585
586         ao_arch_block_interrupts();
587         while (!ao_radio_wake && !ao_radio_abort && !ao_radio_mcu_wake)
588                 ao_sleep(&ao_radio_wake);
589         ao_arch_release_interrupts();
590         if (ao_radio_mcu_wake)
591                 ao_radio_check_marc_status();
592         if (!ao_radio_wake)
593                 ao_radio_idle();
594         ao_radio_put();
595 }
596
597 void
598 ao_radio_rdf(void)
599 {
600         ao_rdf_start(AO_RADIO_RDF_LEN);
601
602         ao_radio_fifo_write_fixed(ao_radio_rdf_value, AO_RADIO_RDF_LEN);
603
604         ao_rdf_run();
605 }
606
607 void
608 ao_radio_continuity(uint8_t c)
609 {
610         uint8_t i;
611         uint8_t status;
612
613         ao_rdf_start(AO_RADIO_CONT_TOTAL_LEN);
614
615         status = ao_radio_fifo_write_start();
616         for (i = 0; i < 3; i++) {
617                 ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN);
618                 if (i < c)
619                         ao_radio_spi_send_fixed(ao_radio_rdf_value, AO_RADIO_CONT_TONE_LEN);
620                 else
621                         ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_TONE_LEN);
622         }
623         ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN);
624         status = ao_radio_fifo_write_stop(status);
625         (void) status;
626         ao_rdf_run();
627 }
628
629 void
630 ao_radio_rdf_abort(void)
631 {
632         ao_radio_abort = 1;
633         ao_wakeup(&ao_radio_wake);
634 }
635
636 static void
637 ao_radio_test_cmd(void)
638 {
639         uint8_t mode = 2;
640         static uint8_t radio_on;
641         ao_cmd_white();
642         if (ao_cmd_lex_c != '\n') {
643                 ao_cmd_decimal();
644                 mode = (uint8_t) ao_cmd_lex_u32;
645         }
646         mode++;
647         if ((mode & 2) && !radio_on) {
648 #if HAS_MONITOR
649                 ao_monitor_disable();
650 #endif
651 #if PACKET_HAS_SLAVE
652                 ao_packet_slave_stop();
653 #endif
654                 ao_radio_get(0xff);
655                 ao_radio_strobe(CC1120_STX);
656 #if CC1120_TRACE
657                 { int t; 
658                         for (t = 0; t < 10; t++) {
659                                 printf ("status: %02x\n", ao_radio_status());
660                                 ao_delay(AO_MS_TO_TICKS(100));
661                         }
662                 }
663 #endif
664                 radio_on = 1;
665         }
666         if (mode == 3) {
667                 printf ("Hit a character to stop..."); flush();
668                 getchar();
669                 putchar('\n');
670         }
671         if ((mode & 1) && radio_on) {
672                 ao_radio_idle();
673                 ao_radio_put();
674                 radio_on = 0;
675 #if HAS_MONITOR
676                 ao_monitor_enable();
677 #endif
678         }
679 }
680
681 static void
682 ao_radio_wait_isr(uint16_t timeout)
683 {
684         if (timeout)
685                 ao_alarm(timeout);
686         ao_arch_block_interrupts();
687         while (!ao_radio_wake && !ao_radio_mcu_wake && !ao_radio_abort)
688                 if (ao_sleep(&ao_radio_wake))
689                         ao_radio_abort = 1;
690         ao_arch_release_interrupts();
691         if (timeout)
692                 ao_clear_alarm();
693         if (ao_radio_mcu_wake)
694                 ao_radio_check_marc_status();
695 }
696
697 static uint8_t
698 ao_radio_wait_tx(uint8_t wait_fifo)
699 {
700         uint8_t fifo_space = 0;
701
702         do {
703                 ao_radio_wait_isr(0);
704                 if (!wait_fifo)
705                         return 0;
706                 fifo_space = ao_radio_tx_fifo_space();
707         } while (!fifo_space && !ao_radio_abort);
708         return fifo_space;
709 }
710
711 static uint8_t  tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
712
713 void
714 ao_radio_send(const void *d, uint8_t size)
715 {
716         uint8_t         marc_status;
717         uint8_t         *e = tx_data;
718         uint8_t         encode_len;
719         uint8_t         this_len;
720         uint8_t         started = 0;
721         uint8_t         fifo_space;
722         uint8_t         q;
723
724         encode_len = ao_fec_encode(d, size, tx_data);
725
726         ao_radio_get(encode_len);
727
728         ao_radio_abort = 0;
729
730         /* Flush any pending TX bytes */
731         ao_radio_strobe(CC1120_SFTX);
732
733         started = 0;
734         fifo_space = CC1120_FIFO_SIZE;
735         while (encode_len) {
736                 this_len = encode_len;
737
738                 ao_radio_wake = 0;
739                 if (this_len > fifo_space) {
740                         this_len = fifo_space;
741                         ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF);
742                 } else {
743                         ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_FINISH);
744                 }
745
746                 ao_radio_fifo_write(e, this_len);
747                 e += this_len;
748                 encode_len -= this_len;
749
750                 if (!started) {
751                         ao_radio_start_tx();
752                         started = 1;
753                 } else {
754                         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
755                 }
756                         
757                 fifo_space = ao_radio_wait_tx(encode_len != 0);
758                 if (ao_radio_abort) {
759                         ao_radio_idle();
760                         break;
761                 }
762         }
763         while (started && !ao_radio_abort && !ao_radio_tx_finished)
764                 ao_radio_wait_isr(0);
765         ao_radio_put();
766 }
767
768 #define AO_RADIO_LOTS   64
769
770 void
771 ao_radio_send_aprs(ao_radio_fill_func fill)
772 {
773         uint8_t buf[AO_RADIO_LOTS], *b;
774         int     cnt;
775         int     total = 0;
776         uint8_t done = 0;
777         uint8_t started = 0;
778         uint8_t fifo_space;
779
780         ao_radio_get(0xff);
781         fifo_space = CC1120_FIFO_SIZE;
782         while (!done) {
783                 cnt = (*fill)(buf, sizeof(buf));
784                 if (cnt < 0) {
785                         done = 1;
786                         cnt = -cnt;
787                 }
788                 total += cnt;
789
790                 /* At the last buffer, set the total length */
791                 if (done)
792                         ao_radio_set_len(total & 0xff);
793
794                 b = buf;
795                 while (cnt) {
796                         uint8_t this_len = cnt;
797
798                         /* Wait for some space in the fifo */
799                         while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
800                                 ao_radio_wake = 0;
801                                 ao_radio_wait_isr(0);
802                         }
803                         if (ao_radio_abort)
804                                 break;
805                         if (this_len > fifo_space)
806                                 this_len = fifo_space;
807
808                         cnt -= this_len;
809
810                         if (done) {
811                                 if (cnt)
812                                         ao_radio_set_mode(AO_RADIO_MODE_APRS_LAST_BUF);
813                                 else
814                                         ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH);
815                         } else
816                                 ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF);
817
818                         ao_radio_fifo_write(b, this_len);
819                         b += this_len;
820
821                         if (!started) {
822                                 ao_radio_start_tx();
823                                 started = 1;
824                         } else
825                                 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
826                 }
827                 if (ao_radio_abort) {
828                         ao_radio_idle();
829                         break;
830                 }
831                 /* Wait for the transmitter to go idle */
832                 ao_radio_wake = 0;
833                 ao_radio_wait_isr(0);
834         }
835         ao_radio_put();
836 }
837
838 static uint8_t  rx_data[(AO_RADIO_MAX_RECV + 4) * 2 * 8];
839 static uint16_t rx_data_count;
840 static uint16_t rx_data_consumed;
841 static uint16_t rx_data_cur;
842 static uint8_t  rx_ignore;
843 static uint8_t  rx_waiting;
844
845 #if AO_PROFILE
846 static uint32_t rx_start_tick, rx_packet_tick, rx_done_tick, rx_last_done_tick;
847
848 uint32_t        ao_rx_start_tick, ao_rx_packet_tick, ao_rx_done_tick, ao_rx_last_done_tick;
849
850 #include <ao_profile.h>
851 #endif
852
853 static void
854 ao_radio_rx_isr(void)
855 {
856         uint8_t d;
857
858         d = AO_CC1120_SPI.dr;
859         AO_CC1120_SPI.dr = 0;
860         if (rx_ignore == 0) {
861                 if (rx_data_cur >= rx_data_count)
862                         ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
863                 else
864                         rx_data[rx_data_cur++] = d;
865                 if (rx_waiting && rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) {
866 #if AO_PROFILE
867                         if (!rx_packet_tick)
868                                 rx_packet_tick = ao_profile_tick();
869                         if (rx_data_cur < rx_data_count)
870                                 return;
871 #endif
872                         rx_waiting = 0;
873                         ao_wakeup(&ao_radio_wake);
874                 }
875         } else {
876                 --rx_ignore;
877         }
878 }
879
880 static uint16_t
881 ao_radio_rx_wait(void)
882 {
883         do {
884                 if (ao_radio_mcu_wake)
885                         ao_radio_check_marc_status();
886                 ao_alarm(AO_MS_TO_TICKS(100));
887                 ao_arch_block_interrupts();
888                 rx_waiting = 1;
889                 while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
890                        !ao_radio_abort &&
891                        !ao_radio_mcu_wake)
892                 {
893                         if (ao_sleep(&ao_radio_wake))
894                                 ao_radio_abort = 1;
895                 }
896                 rx_waiting = 0;
897                 ao_arch_release_interrupts();
898                 ao_clear_alarm();
899         } while (ao_radio_mcu_wake);
900         if (ao_radio_abort)
901                 return 0;
902         rx_data_consumed += AO_FEC_DECODE_BLOCK;
903 #if AO_PROFILE
904         return rx_data_cur - rx_data_consumed;
905 #endif
906         return AO_FEC_DECODE_BLOCK;
907 }
908
909 uint8_t
910 ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout)
911 {
912         uint8_t         len;
913         uint16_t        i;
914         uint8_t         radio_rssi = 0;
915         uint8_t         rssi0;
916         uint8_t         ret;
917         static int been_here = 0;
918
919         size -= 2;                      /* status bytes */
920         if (size > AO_RADIO_MAX_RECV) {
921                 ao_delay(AO_SEC_TO_TICKS(1));
922                 return 0;
923         }
924 #if AO_PROFILE
925         rx_start_tick = ao_profile_tick();
926         rx_packet_tick = 0;
927 #endif
928         len = size + 2;                 /* CRC bytes */
929         len += 1 + ~(len & 1);          /* 1 or two pad bytes */
930         len *= 2;                       /* 1/2 rate convolution */
931         rx_data_count = len * 8;        /* bytes to bits */
932         rx_data_cur = 0;
933         rx_data_consumed = 0;
934         rx_ignore = 2;
935
936         /* Must be set before changing the frequency; any abort
937          * after the frequency is set needs to terminate the read
938          * so that the registers can be reprogrammed
939          */
940         ao_radio_abort = 0;
941
942         /* configure interrupt pin */
943         ao_radio_get(len);
944         ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX);
945
946         ao_radio_wake = 0;
947         ao_radio_mcu_wake = 0;
948
949         AO_CC1120_SPI.cr2 = 0;
950
951         /* clear any RXNE */
952         (void) AO_CC1120_SPI.dr;
953
954         /* Have the radio signal when the preamble quality goes high */
955         ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_PQT_REACHED);
956         ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
957                          AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_HIGH);
958         ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);
959         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
960         ao_exti_enable(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN);
961
962         ao_radio_strobe(CC1120_SRX);
963
964         /* Wait for the preamble to appear */
965         ao_radio_wait_isr(timeout);
966         if (ao_radio_abort) {
967                 ret = 0;
968                 goto abort;
969         }
970
971         ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT);
972         ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
973                          AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH);
974
975         ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr);
976         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
977
978         ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
979
980         ret = ao_fec_decode(rx_data, rx_data_count, d, size + 2, ao_radio_rx_wait);
981
982         ao_radio_burst_read_stop();
983
984 abort:
985         /* Convert from 'real' rssi to cc1111-style values */
986
987         rssi0 = ao_radio_reg_read(CC1120_RSSI0);
988         if (rssi0 & 1) {
989                 int8_t rssi = ao_radio_reg_read(CC1120_RSSI1);
990                 ao_radio_rssi = rssi;
991
992                 /* Bound it to the representable range */
993                 if (rssi > -11)
994                         rssi = -11;
995                 radio_rssi = AO_RADIO_FROM_RSSI (rssi);
996         }
997
998         ao_radio_strobe(CC1120_SIDLE);
999
1000         ao_radio_put();
1001
1002         /* Store the received RSSI value; the crc-OK byte is already done */
1003
1004         ((uint8_t *) d)[size] = radio_rssi;
1005
1006 #if AO_PROFILE
1007         rx_last_done_tick = rx_done_tick;
1008         rx_done_tick = ao_profile_tick();
1009
1010         ao_rx_start_tick = rx_start_tick;
1011         ao_rx_packet_tick = rx_packet_tick;
1012         ao_rx_done_tick = rx_done_tick;
1013         ao_rx_last_done_tick = rx_last_done_tick;
1014 #endif
1015
1016         return ret;
1017 }
1018
1019
1020 #if CC1120_DEBUG
1021 static char *cc1120_state_name[] = {
1022         [CC1120_STATUS_STATE_IDLE] = "IDLE",
1023         [CC1120_STATUS_STATE_RX] = "RX",
1024         [CC1120_STATUS_STATE_TX] = "TX",
1025         [CC1120_STATUS_STATE_FSTXON] = "FSTXON",
1026         [CC1120_STATUS_STATE_CALIBRATE] = "CALIBRATE",
1027         [CC1120_STATUS_STATE_SETTLING] = "SETTLING",
1028         [CC1120_STATUS_STATE_RX_FIFO_ERROR] = "RX_FIFO_ERROR",
1029         [CC1120_STATUS_STATE_TX_FIFO_ERROR] = "TX_FIFO_ERROR",
1030 };
1031
1032 struct ao_cc1120_reg {
1033         uint16_t        addr;
1034         char            *name;
1035 };
1036
1037 const static struct ao_cc1120_reg ao_cc1120_reg[] = {
1038         { .addr = CC1120_IOCFG3,        .name = "IOCFG3" },
1039         { .addr = CC1120_IOCFG2,        .name = "IOCFG2" },
1040         { .addr = CC1120_IOCFG1,        .name = "IOCFG1" },
1041         { .addr = CC1120_IOCFG0,        .name = "IOCFG0" },
1042         { .addr = CC1120_SYNC3, .name = "SYNC3" },
1043         { .addr = CC1120_SYNC2, .name = "SYNC2" },
1044         { .addr = CC1120_SYNC1, .name = "SYNC1" },
1045         { .addr = CC1120_SYNC0, .name = "SYNC0" },
1046         { .addr = CC1120_SYNC_CFG1,     .name = "SYNC_CFG1" },
1047         { .addr = CC1120_SYNC_CFG0,     .name = "SYNC_CFG0" },
1048         { .addr = CC1120_DEVIATION_M,   .name = "DEVIATION_M" },
1049         { .addr = CC1120_MODCFG_DEV_E,  .name = "MODCFG_DEV_E" },
1050         { .addr = CC1120_DCFILT_CFG,    .name = "DCFILT_CFG" },
1051         { .addr = CC1120_PREAMBLE_CFG1, .name = "PREAMBLE_CFG1" },
1052         { .addr = CC1120_PREAMBLE_CFG0, .name = "PREAMBLE_CFG0" },
1053         { .addr = CC1120_FREQ_IF_CFG,   .name = "FREQ_IF_CFG" },
1054         { .addr = CC1120_IQIC,  .name = "IQIC" },
1055         { .addr = CC1120_CHAN_BW,       .name = "CHAN_BW" },
1056         { .addr = CC1120_MDMCFG1,       .name = "MDMCFG1" },
1057         { .addr = CC1120_MDMCFG0,       .name = "MDMCFG0" },
1058         { .addr = CC1120_DRATE2,        .name = "DRATE2" },
1059         { .addr = CC1120_DRATE1,        .name = "DRATE1" },
1060         { .addr = CC1120_DRATE0,        .name = "DRATE0" },
1061         { .addr = CC1120_AGC_REF,       .name = "AGC_REF" },
1062         { .addr = CC1120_AGC_CS_THR,    .name = "AGC_CS_THR" },
1063         { .addr = CC1120_AGC_GAIN_ADJUST,       .name = "AGC_GAIN_ADJUST" },
1064         { .addr = CC1120_AGC_CFG3,      .name = "AGC_CFG3" },
1065         { .addr = CC1120_AGC_CFG2,      .name = "AGC_CFG2" },
1066         { .addr = CC1120_AGC_CFG1,      .name = "AGC_CFG1" },
1067         { .addr = CC1120_AGC_CFG0,      .name = "AGC_CFG0" },
1068         { .addr = CC1120_FIFO_CFG,      .name = "FIFO_CFG" },
1069         { .addr = CC1120_DEV_ADDR,      .name = "DEV_ADDR" },
1070         { .addr = CC1120_SETTLING_CFG,  .name = "SETTLING_CFG" },
1071         { .addr = CC1120_FS_CFG,        .name = "FS_CFG" },
1072         { .addr = CC1120_WOR_CFG1,      .name = "WOR_CFG1" },
1073         { .addr = CC1120_WOR_CFG0,      .name = "WOR_CFG0" },
1074         { .addr = CC1120_WOR_EVENT0_MSB,        .name = "WOR_EVENT0_MSB" },
1075         { .addr = CC1120_WOR_EVENT0_LSB,        .name = "WOR_EVENT0_LSB" },
1076         { .addr = CC1120_PKT_CFG2,      .name = "PKT_CFG2" },
1077         { .addr = CC1120_PKT_CFG1,      .name = "PKT_CFG1" },
1078         { .addr = CC1120_PKT_CFG0,      .name = "PKT_CFG0" },
1079         { .addr = CC1120_RFEND_CFG1,    .name = "RFEND_CFG1" },
1080         { .addr = CC1120_RFEND_CFG0,    .name = "RFEND_CFG0" },
1081         { .addr = CC1120_PA_CFG2,       .name = "PA_CFG2" },
1082         { .addr = CC1120_PA_CFG1,       .name = "PA_CFG1" },
1083         { .addr = CC1120_PA_CFG0,       .name = "PA_CFG0" },
1084         { .addr = CC1120_PKT_LEN,       .name = "PKT_LEN" },
1085         { .addr = CC1120_IF_MIX_CFG,    .name = "IF_MIX_CFG" },
1086         { .addr = CC1120_FREQOFF_CFG,   .name = "FREQOFF_CFG" },
1087         { .addr = CC1120_TOC_CFG,       .name = "TOC_CFG" },
1088         { .addr = CC1120_MARC_SPARE,    .name = "MARC_SPARE" },
1089         { .addr = CC1120_ECG_CFG,       .name = "ECG_CFG" },
1090         { .addr = CC1120_SOFT_TX_DATA_CFG,      .name = "SOFT_TX_DATA_CFG" },
1091         { .addr = CC1120_EXT_CTRL,      .name = "EXT_CTRL" },
1092         { .addr = CC1120_RCCAL_FINE,    .name = "RCCAL_FINE" },
1093         { .addr = CC1120_RCCAL_COARSE,  .name = "RCCAL_COARSE" },
1094         { .addr = CC1120_RCCAL_OFFSET,  .name = "RCCAL_OFFSET" },
1095         { .addr = CC1120_FREQOFF1,      .name = "FREQOFF1" },
1096         { .addr = CC1120_FREQOFF0,      .name = "FREQOFF0" },
1097         { .addr = CC1120_FREQ2, .name = "FREQ2" },
1098         { .addr = CC1120_FREQ1, .name = "FREQ1" },
1099         { .addr = CC1120_FREQ0, .name = "FREQ0" },
1100         { .addr = CC1120_IF_ADC2,       .name = "IF_ADC2" },
1101         { .addr = CC1120_IF_ADC1,       .name = "IF_ADC1" },
1102         { .addr = CC1120_IF_ADC0,       .name = "IF_ADC0" },
1103         { .addr = CC1120_FS_DIG1,       .name = "FS_DIG1" },
1104         { .addr = CC1120_FS_DIG0,       .name = "FS_DIG0" },
1105         { .addr = CC1120_FS_CAL3,       .name = "FS_CAL3" },
1106         { .addr = CC1120_FS_CAL2,       .name = "FS_CAL2" },
1107         { .addr = CC1120_FS_CAL1,       .name = "FS_CAL1" },
1108         { .addr = CC1120_FS_CAL0,       .name = "FS_CAL0" },
1109         { .addr = CC1120_FS_CHP,        .name = "FS_CHP" },
1110         { .addr = CC1120_FS_DIVTWO,     .name = "FS_DIVTWO" },
1111         { .addr = CC1120_FS_DSM1,       .name = "FS_DSM1" },
1112         { .addr = CC1120_FS_DSM0,       .name = "FS_DSM0" },
1113         { .addr = CC1120_FS_DVC1,       .name = "FS_DVC1" },
1114         { .addr = CC1120_FS_DVC0,       .name = "FS_DVC0" },
1115         { .addr = CC1120_FS_LBI,        .name = "FS_LBI" },
1116         { .addr = CC1120_FS_PFD,        .name = "FS_PFD" },
1117         { .addr = CC1120_FS_PRE,        .name = "FS_PRE" },
1118         { .addr = CC1120_FS_REG_DIV_CML,        .name = "FS_REG_DIV_CML" },
1119         { .addr = CC1120_FS_SPARE,      .name = "FS_SPARE" },
1120         { .addr = CC1120_FS_VCO4,       .name = "FS_VCO4" },
1121         { .addr = CC1120_FS_VCO3,       .name = "FS_VCO3" },
1122         { .addr = CC1120_FS_VCO2,       .name = "FS_VCO2" },
1123         { .addr = CC1120_FS_VCO1,       .name = "FS_VCO1" },
1124         { .addr = CC1120_FS_VCO0,       .name = "FS_VCO0" },
1125         { .addr = CC1120_GBIAS6,        .name = "GBIAS6" },
1126         { .addr = CC1120_GBIAS5,        .name = "GBIAS5" },
1127         { .addr = CC1120_GBIAS4,        .name = "GBIAS4" },
1128         { .addr = CC1120_GBIAS3,        .name = "GBIAS3" },
1129         { .addr = CC1120_GBIAS2,        .name = "GBIAS2" },
1130         { .addr = CC1120_GBIAS1,        .name = "GBIAS1" },
1131         { .addr = CC1120_GBIAS0,        .name = "GBIAS0" },
1132         { .addr = CC1120_IFAMP, .name = "IFAMP" },
1133         { .addr = CC1120_LNA,   .name = "LNA" },
1134         { .addr = CC1120_RXMIX, .name = "RXMIX" },
1135         { .addr = CC1120_XOSC5, .name = "XOSC5" },
1136         { .addr = CC1120_XOSC4, .name = "XOSC4" },
1137         { .addr = CC1120_XOSC3, .name = "XOSC3" },
1138         { .addr = CC1120_XOSC2, .name = "XOSC2" },
1139         { .addr = CC1120_XOSC1, .name = "XOSC1" },
1140         { .addr = CC1120_XOSC0, .name = "XOSC0" },
1141         { .addr = CC1120_ANALOG_SPARE,  .name = "ANALOG_SPARE" },
1142         { .addr = CC1120_PA_CFG3,       .name = "PA_CFG3" },
1143         { .addr = CC1120_WOR_TIME1,     .name = "WOR_TIME1" },
1144         { .addr = CC1120_WOR_TIME0,     .name = "WOR_TIME0" },
1145         { .addr = CC1120_WOR_CAPTURE1,  .name = "WOR_CAPTURE1" },
1146         { .addr = CC1120_WOR_CAPTURE0,  .name = "WOR_CAPTURE0" },
1147         { .addr = CC1120_BIST,  .name = "BIST" },
1148         { .addr = CC1120_DCFILTOFFSET_I1,       .name = "DCFILTOFFSET_I1" },
1149         { .addr = CC1120_DCFILTOFFSET_I0,       .name = "DCFILTOFFSET_I0" },
1150         { .addr = CC1120_DCFILTOFFSET_Q1,       .name = "DCFILTOFFSET_Q1" },
1151         { .addr = CC1120_DCFILTOFFSET_Q0,       .name = "DCFILTOFFSET_Q0" },
1152         { .addr = CC1120_IQIE_I1,       .name = "IQIE_I1" },
1153         { .addr = CC1120_IQIE_I0,       .name = "IQIE_I0" },
1154         { .addr = CC1120_IQIE_Q1,       .name = "IQIE_Q1" },
1155         { .addr = CC1120_IQIE_Q0,       .name = "IQIE_Q0" },
1156         { .addr = CC1120_RSSI1, .name = "RSSI1" },
1157         { .addr = CC1120_RSSI0, .name = "RSSI0" },
1158         { .addr = CC1120_MARCSTATE,     .name = "MARCSTATE" },
1159         { .addr = CC1120_LQI_VAL,       .name = "LQI_VAL" },
1160         { .addr = CC1120_PQT_SYNC_ERR,  .name = "PQT_SYNC_ERR" },
1161         { .addr = CC1120_DEM_STATUS,    .name = "DEM_STATUS" },
1162         { .addr = CC1120_FREQOFF_EST1,  .name = "FREQOFF_EST1" },
1163         { .addr = CC1120_FREQOFF_EST0,  .name = "FREQOFF_EST0" },
1164         { .addr = CC1120_AGC_GAIN3,     .name = "AGC_GAIN3" },
1165         { .addr = CC1120_AGC_GAIN2,     .name = "AGC_GAIN2" },
1166         { .addr = CC1120_AGC_GAIN1,     .name = "AGC_GAIN1" },
1167         { .addr = CC1120_AGC_GAIN0,     .name = "AGC_GAIN0" },
1168         { .addr = CC1120_SOFT_RX_DATA_OUT,      .name = "SOFT_RX_DATA_OUT" },
1169         { .addr = CC1120_SOFT_TX_DATA_IN,       .name = "SOFT_TX_DATA_IN" },
1170         { .addr = CC1120_ASK_SOFT_RX_DATA,      .name = "ASK_SOFT_RX_DATA" },
1171         { .addr = CC1120_RNDGEN,        .name = "RNDGEN" },
1172         { .addr = CC1120_MAGN2, .name = "MAGN2" },
1173         { .addr = CC1120_MAGN1, .name = "MAGN1" },
1174         { .addr = CC1120_MAGN0, .name = "MAGN0" },
1175         { .addr = CC1120_ANG1,  .name = "ANG1" },
1176         { .addr = CC1120_ANG0,  .name = "ANG0" },
1177         { .addr = CC1120_CHFILT_I2,     .name = "CHFILT_I2" },
1178         { .addr = CC1120_CHFILT_I1,     .name = "CHFILT_I1" },
1179         { .addr = CC1120_CHFILT_I0,     .name = "CHFILT_I0" },
1180         { .addr = CC1120_CHFILT_Q2,     .name = "CHFILT_Q2" },
1181         { .addr = CC1120_CHFILT_Q1,     .name = "CHFILT_Q1" },
1182         { .addr = CC1120_CHFILT_Q0,     .name = "CHFILT_Q0" },
1183         { .addr = CC1120_GPIO_STATUS,   .name = "GPIO_STATUS" },
1184         { .addr = CC1120_FSCAL_CTRL,    .name = "FSCAL_CTRL" },
1185         { .addr = CC1120_PHASE_ADJUST,  .name = "PHASE_ADJUST" },
1186         { .addr = CC1120_PARTNUMBER,    .name = "PARTNUMBER" },
1187         { .addr = CC1120_PARTVERSION,   .name = "PARTVERSION" },
1188         { .addr = CC1120_SERIAL_STATUS, .name = "SERIAL_STATUS" },
1189         { .addr = CC1120_RX_STATUS,     .name = "RX_STATUS" },
1190         { .addr = CC1120_TX_STATUS,     .name = "TX_STATUS" },
1191         { .addr = CC1120_MARC_STATUS1,  .name = "MARC_STATUS1" },
1192         { .addr = CC1120_MARC_STATUS0,  .name = "MARC_STATUS0" },
1193         { .addr = CC1120_PA_IFAMP_TEST, .name = "PA_IFAMP_TEST" },
1194         { .addr = CC1120_FSRF_TEST,     .name = "FSRF_TEST" },
1195         { .addr = CC1120_PRE_TEST,      .name = "PRE_TEST" },
1196         { .addr = CC1120_PRE_OVR,       .name = "PRE_OVR" },
1197         { .addr = CC1120_ADC_TEST,      .name = "ADC_TEST" },
1198         { .addr = CC1120_DVC_TEST,      .name = "DVC_TEST" },
1199         { .addr = CC1120_ATEST, .name = "ATEST" },
1200         { .addr = CC1120_ATEST_LVDS,    .name = "ATEST_LVDS" },
1201         { .addr = CC1120_ATEST_MODE,    .name = "ATEST_MODE" },
1202         { .addr = CC1120_XOSC_TEST1,    .name = "XOSC_TEST1" },
1203         { .addr = CC1120_XOSC_TEST0,    .name = "XOSC_TEST0" },
1204         { .addr = CC1120_RXFIRST,       .name = "RXFIRST" },
1205         { .addr = CC1120_TXFIRST,       .name = "TXFIRST" },
1206         { .addr = CC1120_RXLAST,        .name = "RXLAST" },
1207         { .addr = CC1120_TXLAST,        .name = "TXLAST" },
1208         { .addr = CC1120_NUM_TXBYTES,   .name = "NUM_TXBYTES" },
1209         { .addr = CC1120_NUM_RXBYTES,   .name = "NUM_RXBYTES" },
1210         { .addr = CC1120_FIFO_NUM_TXBYTES,      .name = "FIFO_NUM_TXBYTES" },
1211         { .addr = CC1120_FIFO_NUM_RXBYTES,      .name = "FIFO_NUM_RXBYTES" },
1212 };
1213
1214 #define AO_NUM_CC1120_REG       (sizeof ao_cc1120_reg / sizeof ao_cc1120_reg[0])
1215
1216 static void ao_radio_show(void) {
1217         uint8_t status = ao_radio_status();
1218         int     i;
1219
1220         ao_radio_get(0xff);
1221         status = ao_radio_status();
1222         printf ("Status:   %02x\n", status);
1223         printf ("CHIP_RDY: %d\n", (status >> CC1120_STATUS_CHIP_RDY) & 1);
1224         printf ("STATE:    %s\n", cc1120_state_name[(status >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK]);
1225         printf ("MARC:     %02x\n", ao_radio_get_marc_status());
1226
1227         for (i = 0; i < AO_NUM_CC1120_REG; i++)
1228                 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name);
1229         ao_radio_put();
1230 }
1231
1232 static void ao_radio_beep(void) {
1233         ao_radio_rdf();
1234 }
1235
1236 static void ao_radio_packet(void) {
1237         static const uint8_t packet[] = {
1238 #if 1
1239                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
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 #else
1244                 3, 1, 2, 3
1245 #endif
1246         };
1247
1248         ao_radio_send(packet, sizeof (packet));
1249 }
1250
1251 void
1252 ao_radio_test_recv()
1253 {
1254         uint8_t bytes[34];
1255         uint8_t b;
1256
1257         if (ao_radio_recv(bytes, 34)) {
1258                 if (bytes[33] & 0x80)
1259                         printf ("CRC OK");
1260                 else
1261                         printf ("CRC BAD");
1262                 printf (" RSSI %d", AO_RSSI_FROM_RADIO(bytes[32]));
1263                 for (b = 0; b < 32; b++)
1264                         printf (" %02x", bytes[b]);
1265                 printf ("\n");
1266         }
1267 }
1268
1269 #if HAS_APRS
1270 #include <ao_aprs.h>
1271
1272 static void
1273 ao_radio_aprs()
1274 {
1275         ao_packet_slave_stop();
1276         ao_aprs_send();
1277 }
1278 #endif
1279
1280 #endif
1281
1282 static const struct ao_cmds ao_radio_cmds[] = {
1283         { ao_radio_test_cmd,    "C <1 start, 0 stop, none both>\0Radio carrier test" },
1284 #if CC1120_DEBUG
1285 #if HAS_APRS
1286         { ao_radio_aprs,        "G\0Send APRS packet" },
1287 #endif
1288         { ao_radio_show,        "R\0Show CC1120 status" },
1289         { ao_radio_beep,        "b\0Emit an RDF beacon" },
1290         { ao_radio_packet,      "p\0Send a test packet" },
1291         { ao_radio_test_recv,   "q\0Recv a test packet" },
1292 #endif
1293         { 0, NULL }
1294 };
1295
1296 void
1297 ao_radio_init(void)
1298 {
1299         int     i;
1300
1301         ao_radio_configured = 0;
1302         ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN));
1303
1304 #if 0
1305         AO_CC1120_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));
1306         for (i = 0; i < 10000; i++) {
1307                 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
1308                         break;
1309         }
1310         AO_CC1120_SPI_CS_PORT->bsrr = (1 << AO_CC1120_SPI_CS_PIN);
1311         if (i == 10000)
1312                 ao_panic(AO_PANIC_SELF_TEST_CC1120);
1313 #endif
1314
1315         /* Enable the EXTI interrupt for the appropriate pin */
1316         ao_enable_port(AO_CC1120_INT_PORT);
1317         ao_exti_setup(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
1318                       AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
1319                       ao_radio_isr);
1320
1321         /* Enable the hacked up GPIO3 pin */
1322         ao_enable_port(AO_CC1120_MCU_WAKEUP_PORT);
1323         ao_exti_setup(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN,
1324                       AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
1325                       ao_radio_mcu_wakeup_isr);
1326
1327         ao_cmd_register(&ao_radio_cmds[0]);
1328 }