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