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