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