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