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