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