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