37d04927a0de0d15a1878a0ce8c1d32220cbae72
[fw/altos] / src / drivers / ao_cc1120.c
1 /*
2  * Copyright © 2012 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include <ao.h>
19 #include <ao_cc1120.h>
20 #include <ao_exti.h>
21 #include <ao_fec.h>
22 #include <ao_packet.h>
23
24 #define AO_RADIO_MAX_RECV       sizeof(struct ao_packet)
25 #define AO_RADIO_MAX_SEND       sizeof(struct ao_packet)
26
27 static uint8_t ao_radio_mutex;
28
29 static uint8_t ao_radio_wake;           /* radio ready. Also used as sleep address */
30 static uint8_t ao_radio_abort;          /* radio operation should abort */
31 static uint8_t ao_radio_mcu_wake;       /* MARC status change */
32 static uint8_t ao_radio_marc_status;    /* Last read MARC status value */
33 static uint8_t ao_radio_tx_finished;    /* MARC status indicates TX finished */
34
35 int8_t  ao_radio_rssi;                  /* Last received RSSI value */
36
37 #define CC1120_DEBUG    AO_FEC_DEBUG
38 #define CC1120_TRACE    0
39
40 extern const uint32_t   ao_radio_cal;
41
42 #define FOSC    32000000
43
44 #define ao_radio_select()       ao_spi_get_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS,AO_SPI_SPEED_4MHz)
45 #define ao_radio_deselect()     ao_spi_put_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS)
46 #define ao_radio_spi_send(d,l)  ao_spi_send((d), (l), AO_CC1120_SPI_BUS)
47 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1120_SPI_BUS)
48 #define ao_radio_spi_recv(d,l)  ao_spi_recv((d), (l), AO_CC1120_SPI_BUS)
49 #define ao_radio_duplex(o,i,l)  ao_spi_duplex((o), (i), (l), AO_CC1120_SPI_BUS)
50
51 static uint8_t
52 ao_radio_reg_read(uint16_t addr)
53 {
54         uint8_t data[2];
55         uint8_t d;
56
57 #if CC1120_TRACE
58         printf("\t\tao_radio_reg_read (%04x): ", addr); flush();
59 #endif
60         if (CC1120_IS_EXTENDED(addr)) {
61                 data[0] = ((1 << CC1120_READ)  |
62                            (0 << CC1120_BURST) |
63                            CC1120_EXTENDED);
64                 data[1] = addr;
65                 d = 2;
66         } else {
67                 data[0] = ((1 << CC1120_READ)  |
68                            (0 << CC1120_BURST) |
69                            addr);
70                 d = 1;
71         }
72         ao_radio_select();
73         ao_radio_spi_send(data, d);
74         ao_radio_spi_recv(data, 1);
75         ao_radio_deselect();
76 #if CC1120_TRACE
77         printf (" %02x\n", data[0]);
78 #endif
79         return data[0];
80 }
81
82 static void
83 ao_radio_reg_write(uint16_t addr, uint8_t value)
84 {
85         uint8_t data[3];
86         uint8_t d;
87
88 #if CC1120_TRACE
89         printf("\t\tao_radio_reg_write (%04x): %02x\n", addr, value);
90 #endif
91         if (CC1120_IS_EXTENDED(addr)) {
92                 data[0] = ((0 << CC1120_READ)  |
93                            (0 << CC1120_BURST) |
94                            CC1120_EXTENDED);
95                 data[1] = addr;
96                 d = 2;
97         } else {
98                 data[0] = ((0 << CC1120_READ)  |
99                            (0 << CC1120_BURST) |
100                            addr);
101                 d = 1;
102         }
103         data[d] = value;
104         ao_radio_select();
105         ao_radio_spi_send(data, d+1);
106         ao_radio_deselect();
107 }
108
109 static void
110 ao_radio_burst_read_start (uint16_t addr)
111 {
112         uint8_t data[2];
113         uint8_t d;
114
115         if (CC1120_IS_EXTENDED(addr)) {
116                 data[0] = ((1 << CC1120_READ)  |
117                            (1 << CC1120_BURST) |
118                            CC1120_EXTENDED);
119                 data[1] = addr;
120                 d = 2;
121         } else {
122                 data[0] = ((1 << CC1120_READ)  |
123                            (1 << CC1120_BURST) |
124                            addr);
125                 d = 1;
126         }
127         ao_radio_select();
128         ao_radio_spi_send(data, d);
129 }
130
131 static void
132 ao_radio_burst_read_stop (void)
133 {
134         ao_radio_deselect();
135 }
136
137
138 static uint8_t
139 ao_radio_strobe(uint8_t addr)
140 {
141         uint8_t in;
142
143 #if CC1120_TRACE
144         printf("\t\tao_radio_strobe (%02x): ", addr); flush();
145 #endif
146         ao_radio_select();
147         ao_radio_duplex(&addr, &in, 1);
148         ao_radio_deselect();
149 #if CC1120_TRACE
150         printf("%02x\n", in); flush();
151 #endif
152         return in;
153 }
154
155 static uint8_t
156 ao_radio_fifo_read(uint8_t *data, uint8_t len)
157 {
158         uint8_t addr = ((1 << CC1120_READ)  |
159                         (1 << CC1120_BURST) |
160                         CC1120_FIFO);
161         uint8_t status;
162
163         ao_radio_select();
164         ao_radio_duplex(&addr, &status, 1);
165         ao_radio_spi_recv(data, len);
166         ao_radio_deselect();
167         return status;
168 }
169
170 static uint8_t
171 ao_radio_fifo_write_start(void)
172 {
173         uint8_t addr = ((0 << CC1120_READ)  |
174                         (1 << CC1120_BURST) |
175                         CC1120_FIFO);
176         uint8_t status;
177
178         ao_radio_select();
179         ao_radio_duplex(&addr, &status, 1);
180         return status;
181 }
182
183 static inline uint8_t ao_radio_fifo_write_stop(uint8_t status) {
184         ao_radio_deselect();
185         return status;
186 }
187
188 static uint8_t
189 ao_radio_fifo_write(uint8_t *data, uint8_t len)
190 {
191         uint8_t status = ao_radio_fifo_write_start();
192         ao_radio_spi_send(data, len);
193         return ao_radio_fifo_write_stop(status);
194 }
195
196 static uint8_t
197 ao_radio_fifo_write_fixed(uint8_t data, uint8_t len)
198 {
199         uint8_t status = ao_radio_fifo_write_start();
200         ao_radio_spi_send_fixed(data, len);
201         return ao_radio_fifo_write_stop(status);
202 }
203
204 static uint8_t
205 ao_radio_tx_fifo_space(void)
206 {
207         return CC1120_FIFO_SIZE - ao_radio_reg_read(CC1120_NUM_TXBYTES);
208 }
209
210 static uint8_t
211 ao_radio_status(void)
212 {
213         return ao_radio_strobe (CC1120_SNOP);
214 }
215
216 void
217 ao_radio_recv_abort(void)
218 {
219         ao_radio_abort = 1;
220         ao_wakeup(&ao_radio_wake);
221 }
222
223 #define ao_radio_rdf_value 0x55
224
225 static uint8_t
226 ao_radio_get_marc_status(void)
227 {
228         return ao_radio_reg_read(CC1120_MARC_STATUS1);
229 }
230
231 static void
232 ao_radio_mcu_wakeup_isr(void)
233 {
234         ao_radio_mcu_wake = 1;
235         ao_wakeup(&ao_radio_wake);
236 }
237
238
239 static void
240 ao_radio_check_marc_status(void)
241 {
242         ao_radio_mcu_wake = 0;
243         ao_radio_marc_status = ao_radio_get_marc_status();
244         
245         /* Anyt other than 'tx/rx finished' means an error occurred */
246         if (ao_radio_marc_status & ~(CC1120_MARC_STATUS1_TX_FINISHED|CC1120_MARC_STATUS1_RX_FINISHED))
247                 ao_radio_abort = 1;
248         if (ao_radio_marc_status & (CC1120_MARC_STATUS1_TX_FINISHED))
249                 ao_radio_tx_finished = 1;
250 }
251
252 static void
253 ao_radio_isr(void)
254 {
255         ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
256         ao_radio_wake = 1;
257         ao_wakeup(&ao_radio_wake);
258 }
259
260 static void
261 ao_radio_start_tx(void)
262 {
263         ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);
264         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
265         ao_exti_enable(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN);
266         ao_radio_tx_finished = 0;
267         ao_radio_strobe(CC1120_STX);
268 }
269
270 static void
271 ao_radio_idle(void)
272 {
273         for (;;) {
274                 uint8_t state = ao_radio_strobe(CC1120_SIDLE);
275                 if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_IDLE)
276                         break;
277                 if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_TX_FIFO_ERROR)
278                         ao_radio_strobe(CC1120_SFTX);
279         }
280         /* Flush any pending TX bytes */
281         ao_radio_strobe(CC1120_SFTX);
282 }
283
284 /*
285  * Packet deviation is 20.5kHz
286  *
287  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
288  *
289  *      32e6Hz / (2 ** 24) * (256 + 80) * (2 ** 5) = 20508Hz
290  */
291
292 #define PACKET_DEV_E    5
293 #define PACKET_DEV_M    80
294
295 /*
296  * For our packet data, set the symbol rate to 38400 Baud
297  *
298  *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
299  *      Rdata = -------------------------------------- * fosc
300  *                           2 ** 39
301  *
302  *
303  *      DATARATE_M = 239914
304  *      DATARATE_E = 9
305  */
306 #define PACKET_DRATE_E  9
307 #define PACKET_DRATE_M  239914
308
309 static const uint16_t packet_setup[] = {
310         CC1120_DEVIATION_M,     PACKET_DEV_M,
311         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
312                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
313                                  (PACKET_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
314         CC1120_DRATE2,          ((PACKET_DRATE_E << CC1120_DRATE2_DATARATE_E) |
315                                  (((PACKET_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
316         CC1120_DRATE1,          ((PACKET_DRATE_M >> 8) & 0xff),
317         CC1120_DRATE0,          ((PACKET_DRATE_M >> 0) & 0xff),
318         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
319                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
320         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
321                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
322                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
323                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
324         CC1120_PKT_CFG0,        ((0 << CC1120_PKT_CFG0_RESERVED7) |
325                                  (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
326                                  (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
327                                  (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
328                                  (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
329         CC1120_PREAMBLE_CFG1,   ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
330                                  (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
331         AO_CC1120_MARC_GPIO_IOCFG,              CC1120_IOCFG_GPIO_CFG_MARC_MCU_WAKEUP,
332 };
333
334 static const uint16_t packet_tx_setup[] = {
335         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
336                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
337         AO_CC1120_INT_GPIO_IOCFG,               CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG,
338 };
339
340 static const uint16_t packet_rx_setup[] = {
341         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
342                                  (CC1120_PKT_CFG2_PKT_FORMAT_SYNCHRONOUS_SERIAL << CC1120_PKT_CFG2_PKT_FORMAT)),
343         AO_CC1120_INT_GPIO_IOCFG,               CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT,
344 };
345
346 /*
347  * RDF deviation is 5kHz
348  *
349  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
350  *
351  *      32e6Hz / (2 ** 24) * (256 + 71) * (2 ** 3) = 4989
352  */
353
354 #define RDF_DEV_E       3
355 #define RDF_DEV_M       71
356 #define RDF_PACKET_LEN  50
357
358 /*
359  * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
360  *
361  *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
362  *      Rdata = -------------------------------------- * fosc
363  *                           2 ** 39
364  *
365  *      DATARATE_M = 25166
366  *      DATARATE_E = 5
367  *
368  * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes
369  */
370 #define RDF_DRATE_E     5
371 #define RDF_DRATE_M     25166
372 #define RDF_PACKET_LEN  50
373
374 static const uint16_t rdf_setup[] = {
375         CC1120_DEVIATION_M,     RDF_DEV_M,
376         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
377                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
378                                  (RDF_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
379         CC1120_DRATE2,          ((RDF_DRATE_E << CC1120_DRATE2_DATARATE_E) |
380                                  (((RDF_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
381         CC1120_DRATE1,          ((RDF_DRATE_M >> 8) & 0xff),
382         CC1120_DRATE0,          ((RDF_DRATE_M >> 0) & 0xff),
383         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
384                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
385         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
386                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
387                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
388                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
389         CC1120_PKT_CFG0,        ((0 << CC1120_PKT_CFG0_RESERVED7) |
390                                  (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) |
391                                  (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
392                                  (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
393                                  (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
394         CC1120_PREAMBLE_CFG1,   ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_NONE << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
395                                  (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
396 };
397
398 /*
399  * APRS deviation is 3kHz
400  *
401  *      fdev = fosc >> 24 * (256 + dev_m) << dev_e
402  *
403  *      32e6Hz / (2 ** 24) * (256 + 137) * (2 ** 2) = 2998Hz
404  */
405
406 #define APRS_DEV_E      2
407 #define APRS_DEV_M      137
408
409 /*
410  * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate)
411  *
412  *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
413  *      Rdata = -------------------------------------- * fosc
414  *                           2 ** 39
415  *
416  *      DATARATE_M = 239914
417  *      DATARATE_E = 7
418  *
419  *      Rdata = 9599.998593330383301
420  *
421  */
422 #define APRS_DRATE_E    7
423 #define APRS_DRATE_M    239914
424
425 static const uint16_t aprs_setup[] = {
426         CC1120_DEVIATION_M,     APRS_DEV_M,
427         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
428                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
429                                  (APRS_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
430         CC1120_DRATE2,          ((APRS_DRATE_E << CC1120_DRATE2_DATARATE_E) |
431                                  (((APRS_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
432         CC1120_DRATE1,          ((APRS_DRATE_M >> 8) & 0xff),
433         CC1120_DRATE0,          ((APRS_DRATE_M >> 0) & 0xff),
434         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
435                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
436         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
437                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
438                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
439                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
440         CC1120_PREAMBLE_CFG1,   ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_NONE << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
441                                  (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
442 };
443
444 /*
445  * For Test mode, we want an unmodulated carrier. To do that, we
446  * set the deviation to zero and enable a preamble so that the radio
447  * turns on before we send any data
448  */
449
450 static const uint16_t test_setup[] = {
451         CC1120_DEVIATION_M,     0,
452         CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
453                                  (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
454                                  (0 << CC1120_MODCFG_DEV_E_DEV_E)),
455         CC1120_DRATE2,          ((APRS_DRATE_E << CC1120_DRATE2_DATARATE_E) |
456                                  (((APRS_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
457         CC1120_DRATE1,          ((APRS_DRATE_M >> 8) & 0xff),
458         CC1120_DRATE0,          ((APRS_DRATE_M >> 0) & 0xff),
459         CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
460                                  (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
461         CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
462                                  (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
463                                  (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
464                                  (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
465         CC1120_PREAMBLE_CFG1,   ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
466                                  (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
467 };
468
469 #define AO_PKT_CFG0_INFINITE ((0 << CC1120_PKT_CFG0_RESERVED7) |        \
470                               (CC1120_PKT_CFG0_LENGTH_CONFIG_INFINITE << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
471                               (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |      \
472                               (0 << CC1120_PKT_CFG0_UART_MODE_EN) |     \
473                               (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
474
475 #define AO_PKT_CFG0_FIXED ((0 << CC1120_PKT_CFG0_RESERVED7) |           \
476                            (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
477                            (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |         \
478                            (0 << CC1120_PKT_CFG0_UART_MODE_EN) |        \
479                            (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
480
481 static uint16_t ao_radio_mode;
482
483 #define AO_RADIO_MODE_BITS_PACKET       1
484 #define AO_RADIO_MODE_BITS_PACKET_TX    2
485 #define AO_RADIO_MODE_BITS_TX_BUF       4
486 #define AO_RADIO_MODE_BITS_TX_FINISH    8
487 #define AO_RADIO_MODE_BITS_PACKET_RX    16
488 #define AO_RADIO_MODE_BITS_RDF          32
489 #define AO_RADIO_MODE_BITS_APRS         64
490 #define AO_RADIO_MODE_BITS_TEST         128
491 #define AO_RADIO_MODE_BITS_INFINITE     256
492 #define AO_RADIO_MODE_BITS_FIXED        512
493
494 #define AO_RADIO_MODE_NONE              0
495 #define AO_RADIO_MODE_PACKET_TX_BUF     (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF)
496 #define AO_RADIO_MODE_PACKET_TX_FINISH  (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_FINISH)
497 #define AO_RADIO_MODE_PACKET_RX         (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_RX)
498 #define AO_RADIO_MODE_RDF               (AO_RADIO_MODE_BITS_RDF | AO_RADIO_MODE_BITS_TX_FINISH)
499 #define AO_RADIO_MODE_APRS_BUF          (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF)
500 #define AO_RADIO_MODE_APRS_LAST_BUF     (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_BUF)
501 #define AO_RADIO_MODE_APRS_FINISH       (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_FINISH)
502 #define AO_RADIO_MODE_TEST              (AO_RADIO_MODE_BITS_TEST | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF)
503
504 static void
505 ao_radio_set_mode(uint16_t new_mode)
506 {
507         uint16_t changes;
508         int i;
509
510         if (new_mode == ao_radio_mode)
511                 return;
512
513         changes = new_mode & (~ao_radio_mode);
514         if (changes & AO_RADIO_MODE_BITS_PACKET)
515                 for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2)
516                         ao_radio_reg_write(packet_setup[i], packet_setup[i+1]);
517
518         if (changes & AO_RADIO_MODE_BITS_PACKET_TX)
519                 for (i = 0; i < sizeof (packet_tx_setup) / sizeof (packet_tx_setup[0]); i += 2)
520                         ao_radio_reg_write(packet_tx_setup[i], packet_tx_setup[i+1]);
521                 
522         if (changes & AO_RADIO_MODE_BITS_TX_BUF)
523                 ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_TXFIFO_THR);
524
525         if (changes & AO_RADIO_MODE_BITS_TX_FINISH)
526                 ao_radio_reg_write(AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG);
527
528         if (changes & AO_RADIO_MODE_BITS_PACKET_RX)
529                 for (i = 0; i < sizeof (packet_rx_setup) / sizeof (packet_rx_setup[0]); i += 2)
530                         ao_radio_reg_write(packet_rx_setup[i], packet_rx_setup[i+1]);
531                 
532         if (changes & AO_RADIO_MODE_BITS_RDF)
533                 for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
534                         ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
535
536         if (changes & AO_RADIO_MODE_BITS_APRS)
537                 for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2)
538                         ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]);
539
540         if (changes & AO_RADIO_MODE_BITS_TEST)
541                 for (i = 0; i < sizeof (test_setup) / sizeof (test_setup[0]); i += 2)
542                         ao_radio_reg_write(test_setup[i], test_setup[i+1]);
543
544         if (changes & AO_RADIO_MODE_BITS_INFINITE)
545                 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_INFINITE);
546
547         if (changes & AO_RADIO_MODE_BITS_FIXED)
548                 ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_FIXED);
549
550         ao_radio_mode = new_mode;
551 }
552
553 static const uint16_t radio_setup[] = {
554 #include "ao_cc1120_CC1120.h"
555 };
556
557 static uint8_t  ao_radio_configured = 0;
558
559 static void
560 ao_radio_setup(void)
561 {
562         int     i;
563
564         ao_radio_strobe(CC1120_SRES);
565
566         for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
567                 ao_radio_reg_write(radio_setup[i], radio_setup[i+1]);
568
569         ao_radio_mode = 0;
570
571         ao_config_get();
572
573         ao_radio_configured = 1;
574 }
575
576 static void
577 ao_radio_set_len(uint8_t len)
578 {
579         static uint8_t  last_len;
580
581         if (len != last_len) {
582                 ao_radio_reg_write(CC1120_PKT_LEN, len);
583                 last_len = len;
584         }
585 }
586
587 static void
588 ao_radio_get(uint8_t len)
589 {
590         static uint32_t last_radio_setting;
591
592         ao_mutex_get(&ao_radio_mutex);
593
594         if (!ao_radio_configured)
595                 ao_radio_setup();
596         if (ao_config.radio_setting != last_radio_setting) {
597                 ao_radio_reg_write(CC1120_FREQ2, ao_config.radio_setting >> 16);
598                 ao_radio_reg_write(CC1120_FREQ1, ao_config.radio_setting >> 8);
599                 ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting);
600                 last_radio_setting = ao_config.radio_setting;
601         }
602         ao_radio_set_len(len);
603 }
604
605 #define ao_radio_put()  ao_mutex_put(&ao_radio_mutex)
606
607 static void
608 ao_rdf_start(uint8_t len)
609 {
610         ao_radio_abort = 0;
611         ao_radio_get(len);
612
613         ao_radio_set_mode(AO_RADIO_MODE_RDF);
614         ao_radio_wake = 0;
615
616 }
617
618 static void
619 ao_rdf_run(void)
620 {
621         ao_radio_start_tx();
622
623         ao_arch_block_interrupts();
624         while (!ao_radio_wake && !ao_radio_abort && !ao_radio_mcu_wake)
625                 ao_sleep(&ao_radio_wake);
626         ao_arch_release_interrupts();
627         if (ao_radio_mcu_wake)
628                 ao_radio_check_marc_status();
629         if (!ao_radio_wake)
630                 ao_radio_idle();
631         ao_radio_put();
632 }
633
634 void
635 ao_radio_rdf(void)
636 {
637         ao_rdf_start(AO_RADIO_RDF_LEN);
638
639         ao_radio_fifo_write_fixed(ao_radio_rdf_value, AO_RADIO_RDF_LEN);
640
641         ao_rdf_run();
642 }
643
644 void
645 ao_radio_continuity(uint8_t c)
646 {
647         uint8_t i;
648         uint8_t status;
649
650         ao_rdf_start(AO_RADIO_CONT_TOTAL_LEN);
651
652         status = ao_radio_fifo_write_start();
653         for (i = 0; i < 3; i++) {
654                 ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN);
655                 if (i < c)
656                         ao_radio_spi_send_fixed(ao_radio_rdf_value, AO_RADIO_CONT_TONE_LEN);
657                 else
658                         ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_TONE_LEN);
659         }
660         ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN);
661         status = ao_radio_fifo_write_stop(status);
662         (void) status;
663         ao_rdf_run();
664 }
665
666 void
667 ao_radio_rdf_abort(void)
668 {
669         ao_radio_abort = 1;
670         ao_wakeup(&ao_radio_wake);
671 }
672
673 static void
674 ao_radio_test_cmd(void)
675 {
676         uint8_t mode = 2;
677         static uint8_t radio_on;
678         ao_cmd_white();
679         if (ao_cmd_lex_c != '\n') {
680                 ao_cmd_decimal();
681                 mode = (uint8_t) ao_cmd_lex_u32;
682         }
683         mode++;
684         if ((mode & 2) && !radio_on) {
685 #if HAS_MONITOR
686                 ao_monitor_disable();
687 #endif
688 #if PACKET_HAS_SLAVE
689                 ao_packet_slave_stop();
690 #endif
691                 ao_radio_get(0xff);
692                 ao_radio_set_mode(AO_RADIO_MODE_TEST);
693                 ao_radio_strobe(CC1120_STX);
694 #if CC1120_TRACE
695                 { int t; 
696                         for (t = 0; t < 10; t++) {
697                                 printf ("status: %02x\n", ao_radio_status());
698                                 ao_delay(AO_MS_TO_TICKS(100));
699                         }
700                 }
701 #endif
702                 radio_on = 1;
703         }
704         if (mode == 3) {
705                 printf ("Hit a character to stop..."); flush();
706                 getchar();
707                 putchar('\n');
708         }
709         if ((mode & 1) && radio_on) {
710                 ao_radio_idle();
711                 ao_radio_put();
712                 radio_on = 0;
713 #if HAS_MONITOR
714                 ao_monitor_enable();
715 #endif
716         }
717 }
718
719 static void
720 ao_radio_wait_isr(uint16_t timeout)
721 {
722         if (timeout)
723                 ao_alarm(timeout);
724         ao_arch_block_interrupts();
725         while (!ao_radio_wake && !ao_radio_mcu_wake && !ao_radio_abort)
726                 if (ao_sleep(&ao_radio_wake))
727                         ao_radio_abort = 1;
728         ao_arch_release_interrupts();
729         if (timeout)
730                 ao_clear_alarm();
731         if (ao_radio_mcu_wake)
732                 ao_radio_check_marc_status();
733 }
734
735 static uint8_t
736 ao_radio_wait_tx(uint8_t wait_fifo)
737 {
738         uint8_t fifo_space = 0;
739
740         do {
741                 ao_radio_wait_isr(0);
742                 if (!wait_fifo)
743                         return 0;
744                 fifo_space = ao_radio_tx_fifo_space();
745         } while (!fifo_space && !ao_radio_abort);
746         return fifo_space;
747 }
748
749 static uint8_t  tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
750
751 void
752 ao_radio_send(const void *d, uint8_t size)
753 {
754         uint8_t         marc_status;
755         uint8_t         *e = tx_data;
756         uint8_t         encode_len;
757         uint8_t         this_len;
758         uint8_t         started = 0;
759         uint8_t         fifo_space;
760         uint8_t         q;
761
762         encode_len = ao_fec_encode(d, size, tx_data);
763
764         ao_radio_get(encode_len);
765
766         ao_radio_abort = 0;
767
768         /* Flush any pending TX bytes */
769         ao_radio_strobe(CC1120_SFTX);
770
771         started = 0;
772         fifo_space = CC1120_FIFO_SIZE;
773         while (encode_len) {
774                 this_len = encode_len;
775
776                 ao_radio_wake = 0;
777                 if (this_len > fifo_space) {
778                         this_len = fifo_space;
779                         ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF);
780                 } else {
781                         ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_FINISH);
782                 }
783
784                 ao_radio_fifo_write(e, this_len);
785                 e += this_len;
786                 encode_len -= this_len;
787
788                 if (!started) {
789                         ao_radio_start_tx();
790                         started = 1;
791                 } else {
792                         ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
793                 }
794                         
795                 fifo_space = ao_radio_wait_tx(encode_len != 0);
796                 if (ao_radio_abort) {
797                         ao_radio_idle();
798                         break;
799                 }
800         }
801         while (started && !ao_radio_abort && !ao_radio_tx_finished)
802                 ao_radio_wait_isr(0);
803         ao_radio_put();
804 }
805
806 #define AO_RADIO_LOTS   64
807
808 void
809 ao_radio_send_aprs(ao_radio_fill_func fill)
810 {
811         uint8_t buf[AO_RADIO_LOTS], *b;
812         int     cnt;
813         int     total = 0;
814         uint8_t done = 0;
815         uint8_t started = 0;
816         uint8_t fifo_space;
817
818         ao_radio_get(0xff);
819         fifo_space = CC1120_FIFO_SIZE;
820         while (!done) {
821                 cnt = (*fill)(buf, sizeof(buf));
822                 if (cnt < 0) {
823                         done = 1;
824                         cnt = -cnt;
825                 }
826                 total += cnt;
827
828                 /* At the last buffer, set the total length */
829                 if (done)
830                         ao_radio_set_len(total & 0xff);
831
832                 b = buf;
833                 while (cnt) {
834                         uint8_t this_len = cnt;
835
836                         /* Wait for some space in the fifo */
837                         while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
838                                 ao_radio_wake = 0;
839                                 ao_radio_wait_isr(0);
840                         }
841                         if (ao_radio_abort)
842                                 break;
843                         if (this_len > fifo_space)
844                                 this_len = fifo_space;
845
846                         cnt -= this_len;
847
848                         if (done) {
849                                 if (cnt)
850                                         ao_radio_set_mode(AO_RADIO_MODE_APRS_LAST_BUF);
851                                 else
852                                         ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH);
853                         } else
854                                 ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF);
855
856                         ao_radio_fifo_write(b, this_len);
857                         b += this_len;
858
859                         if (!started) {
860                                 ao_radio_start_tx();
861                                 started = 1;
862                         } else
863                                 ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
864                 }
865                 if (ao_radio_abort) {
866                         ao_radio_idle();
867                         break;
868                 }
869                 /* Wait for the transmitter to go idle */
870                 ao_radio_wake = 0;
871                 ao_radio_wait_isr(0);
872         }
873         ao_radio_put();
874 }
875
876 static uint8_t  rx_data[(AO_RADIO_MAX_RECV + 4) * 2 * 8];
877 static uint16_t rx_data_count;
878 static uint16_t rx_data_consumed;
879 static uint16_t rx_data_cur;
880 static uint8_t  rx_ignore;
881 static uint8_t  rx_waiting;
882
883 #if AO_PROFILE
884 static uint32_t rx_start_tick, rx_packet_tick, rx_done_tick, rx_last_done_tick;
885
886 uint32_t        ao_rx_start_tick, ao_rx_packet_tick, ao_rx_done_tick, ao_rx_last_done_tick;
887
888 #include <ao_profile.h>
889 #endif
890
891 static void
892 ao_radio_rx_isr(void)
893 {
894         uint8_t d;
895
896         d = AO_CC1120_SPI.dr;
897         AO_CC1120_SPI.dr = 0;
898         if (rx_ignore == 0) {
899                 if (rx_data_cur >= rx_data_count)
900                         ao_exti_disable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
901                 else
902                         rx_data[rx_data_cur++] = d;
903                 if (rx_waiting && rx_data_cur - rx_data_consumed >= AO_FEC_DECODE_BLOCK) {
904 #if AO_PROFILE
905                         if (!rx_packet_tick)
906                                 rx_packet_tick = ao_profile_tick();
907                         if (rx_data_cur < rx_data_count)
908                                 return;
909 #endif
910                         rx_waiting = 0;
911                         ao_wakeup(&ao_radio_wake);
912                 }
913         } else {
914                 --rx_ignore;
915         }
916 }
917
918 static uint16_t
919 ao_radio_rx_wait(void)
920 {
921         do {
922                 if (ao_radio_mcu_wake)
923                         ao_radio_check_marc_status();
924                 ao_alarm(AO_MS_TO_TICKS(100));
925                 ao_arch_block_interrupts();
926                 rx_waiting = 1;
927                 while (rx_data_cur - rx_data_consumed < AO_FEC_DECODE_BLOCK &&
928                        !ao_radio_abort &&
929                        !ao_radio_mcu_wake)
930                 {
931                         if (ao_sleep(&ao_radio_wake))
932                                 ao_radio_abort = 1;
933                 }
934                 rx_waiting = 0;
935                 ao_arch_release_interrupts();
936                 ao_clear_alarm();
937         } while (ao_radio_mcu_wake);
938         if (ao_radio_abort)
939                 return 0;
940         rx_data_consumed += AO_FEC_DECODE_BLOCK;
941 #if AO_PROFILE
942         return rx_data_cur - rx_data_consumed;
943 #endif
944         return AO_FEC_DECODE_BLOCK;
945 }
946
947 uint8_t
948 ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout)
949 {
950         uint8_t         len;
951         uint16_t        i;
952         uint8_t         radio_rssi = 0;
953         uint8_t         rssi0;
954         uint8_t         ret;
955         static int been_here = 0;
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         int     i;
1338
1339         ao_radio_configured = 0;
1340         ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN));
1341
1342 #if 0
1343         AO_CC1120_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));
1344         for (i = 0; i < 10000; i++) {
1345                 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
1346                         break;
1347         }
1348         AO_CC1120_SPI_CS_PORT->bsrr = (1 << AO_CC1120_SPI_CS_PIN);
1349         if (i == 10000)
1350                 ao_panic(AO_PANIC_SELF_TEST_CC1120);
1351 #endif
1352
1353         /* Enable the EXTI interrupt for the appropriate pin */
1354         ao_enable_port(AO_CC1120_INT_PORT);
1355         ao_exti_setup(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,
1356                       AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
1357                       ao_radio_isr);
1358
1359         /* Enable the hacked up GPIO3 pin */
1360         ao_enable_port(AO_CC1120_MCU_WAKEUP_PORT);
1361         ao_exti_setup(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN,
1362                       AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
1363                       ao_radio_mcu_wakeup_isr);
1364
1365         ao_cmd_register(&ao_radio_cmds[0]);
1366 }