altos/test: Adjust CRC error rate after FEC fix
[fw/altos] / src / drivers / ao_cc115l.c
1 /*
2  * Copyright © 2013 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; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include <ao.h>
20 #include <ao_cc115l.h>
21 #include <ao_exti.h>
22 #include <ao_telemetry.h>
23 #include <ao_fec.h>
24
25 #define AO_RADIO_MAX_SEND       sizeof (struct ao_telemetry_generic)
26
27 uint8_t ao_radio_mutex;
28
29 static uint8_t ao_radio_fifo;           /* fifo drained interrupt received */
30 static uint8_t ao_radio_done;           /* tx done interrupt received */
31 static uint8_t ao_radio_wake;           /* sleep address for radio interrupts */
32 static uint8_t ao_radio_abort;          /* radio operation should abort */
33
34 /* Debugging commands */
35 #define CC115L_DEBUG    0
36
37 /* Runtime tracing */
38 #define CC115L_TRACE    0
39
40 #define FOSC    26000000
41
42 #define AO_CC115L_SPI_SPEED     ao_spi_speed(AO_CC115L_SPI_BUS, 6500000)        /* for back-to-back access */
43
44 #define ao_radio_select()       ao_spi_get_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS,AO_CC115L_SPI_SPEED)
45 #define ao_radio_deselect()     ao_spi_put_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS)
46 #define ao_radio_spi_send(d,l)  ao_spi_send((d), (l), AO_CC115L_SPI_BUS)
47 #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC115L_SPI_BUS)
48 #define ao_radio_spi_recv(d,l)  ao_spi_recv((d), (l), AO_CC115L_SPI_BUS)
49 #define ao_radio_duplex(o,i,l)  ao_spi_duplex((o), (i), (l), AO_CC115L_SPI_BUS)
50
51 struct ao_cc115l_reg {
52         uint16_t        addr;
53         char            *name;
54 };
55
56 #if CC115L_TRACE
57
58 static const struct ao_cc115l_reg ao_cc115l_reg[];
59 static const char *cc115l_state_name[];
60
61 enum ao_cc115l_trace_type {
62         trace_strobe,
63         trace_read,
64         trace_write,
65         trace_dma,
66         trace_line,
67 };
68
69 struct ao_cc115l_trace {
70         enum ao_cc115l_trace_type       type;
71         int16_t                         addr;
72         int16_t                         value;
73         const char                      *comment;
74 };
75
76 #define NUM_TRACE       32
77
78 static struct ao_cc115l_trace   trace[NUM_TRACE];
79 static int                      trace_i;
80 static int                      trace_disable;
81
82 static void trace_add(enum ao_cc115l_trace_type type, int16_t addr, int16_t value, const char *comment)
83 {
84         if (trace_disable)
85                 return;
86         switch (type) {
87         case trace_read:
88         case trace_write:
89                 comment = ao_cc115l_reg[addr].name;
90                 break;
91         case trace_strobe:
92                 comment = cc115l_state_name[(value >> 4) & 0x7];
93                 break;
94         default:
95                 break;
96         }
97         trace[trace_i].type = type;
98         trace[trace_i].addr = addr;
99         trace[trace_i].value = value;
100         trace[trace_i].comment = comment;
101         if (++trace_i == NUM_TRACE)
102                 trace_i = 0;
103 }
104 #else
105 #define trace_add(t,a,v,c)
106 #endif
107
108 static uint8_t
109 ao_radio_reg_read(uint8_t addr)
110 {
111         uint8_t data[1];
112
113         data[0] = ((1 << CC115L_READ)  |
114                    (0 << CC115L_BURST) |
115                    addr);
116         ao_radio_select();
117         ao_radio_spi_send(data, 1);
118         ao_radio_spi_recv(data, 1);
119         ao_radio_deselect();
120         trace_add(trace_read, addr, data[0], NULL);
121         return data[0];
122 }
123
124 static void
125 ao_radio_reg_write(uint8_t addr, uint8_t value)
126 {
127         uint8_t data[2];
128
129         trace_add(trace_write, addr, value, NULL);
130         data[0] = ((0 << CC115L_READ)  |
131                    (0 << CC115L_BURST) |
132                    addr);
133         data[1] = value;
134         ao_radio_select();
135         ao_radio_spi_send(data, 2);
136         ao_radio_deselect();
137 }
138
139 #if UNUSED
140 static void
141 ao_radio_burst_read_start (uint16_t addr)
142 {
143         uint8_t data[1];
144
145         data[0] = ((1 << CC115L_READ)  |
146                    (1 << CC115L_BURST) |
147                    addr);
148         ao_radio_select();
149         ao_radio_spi_send(data, 1);
150 }
151
152 static void
153 ao_radio_burst_read_stop (void)
154 {
155         ao_radio_deselect();
156 }
157 #endif
158
159
160 static uint8_t
161 ao_radio_strobe(uint8_t addr)
162 {
163         uint8_t in;
164
165         ao_radio_select();
166         ao_radio_duplex(&addr, &in, 1);
167         ao_radio_deselect();
168         trace_add(trace_strobe, addr, in, NULL);
169         return in;
170 }
171
172 static uint8_t
173 ao_radio_fifo_write_start(void)
174 {
175         uint8_t addr = ((0 << CC115L_READ)  |
176                         (1 << CC115L_BURST) |
177                         CC115L_FIFO);
178         uint8_t status;
179
180         ao_radio_select();
181         ao_radio_duplex(&addr, &status, 1);
182         return status;
183 }
184
185 static inline uint8_t ao_radio_fifo_write_stop(uint8_t status) {
186         ao_radio_deselect();
187         return status;
188 }
189
190 static uint8_t
191 ao_radio_fifo_write(uint8_t *data, uint8_t len)
192 {
193         uint8_t status = ao_radio_fifo_write_start();
194         trace_add(trace_dma, CC115L_FIFO, len, NULL);
195         ao_radio_spi_send(data, len);
196         return ao_radio_fifo_write_stop(status);
197 }
198
199 static uint8_t
200 ao_radio_tx_fifo_space(void)
201 {
202         return CC115L_FIFO_SIZE - (ao_radio_reg_read(CC115L_TXBYTES) & CC115L_TXBYTES_NUM_TX_BYTES_MASK);
203 }
204
205 #if CC115L_DEBUG
206 static uint8_t
207 ao_radio_status(void)
208 {
209         return ao_radio_strobe (CC115L_SNOP);
210 }
211
212 static uint8_t
213 ao_radio_get_marcstate(void)
214 {
215         return ao_radio_reg_read(CC115L_MARCSTATE) & CC115L_MARCSTATE_MASK;
216 }
217 #endif
218
219 #define ao_radio_rdf_value 0x55
220
221 static void
222 ao_radio_done_isr(void)
223 {
224         ao_exti_disable(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN);
225         trace_add(trace_line, __LINE__, 0, "done_isr");
226         ao_radio_done = 1;
227         ao_wakeup(&ao_radio_wake);
228 }
229
230 static void
231 ao_radio_fifo_isr(void)
232 {
233         ao_exti_disable(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN);
234         trace_add(trace_line, __LINE__, 0, "fifo_isr");
235         ao_radio_fifo = 1;
236         ao_wakeup(&ao_radio_wake);
237 }
238
239 static void
240 ao_radio_idle(void)
241 {
242         ao_radio_pa_off();
243         for (;;) {
244                 uint8_t state = ao_radio_strobe(CC115L_SIDLE);
245                 if ((state >> CC115L_STATUS_STATE) == CC115L_STATUS_STATE_IDLE)
246                         break;
247                 if ((state >> CC115L_STATUS_STATE) == CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW)
248                         ao_radio_strobe(CC115L_SFTX);
249         }
250         /* Flush any pending TX bytes */
251         ao_radio_strobe(CC115L_SFTX);
252         /* Make sure the RF calibration is current */
253         ao_radio_strobe(CC115L_SCAL);
254 }
255
256 /*
257  * Packet deviation
258  *
259  *      fdev = fosc >> 17 * (8 + dev_m) << dev_e
260  *
261  * For 38400 baud, use 20.5kHz:
262  *
263  *      26e6 / (2 ** 17) * (8 + 5) * (2 ** 3) = 20630Hz
264  *
265  * For 9600 baud, use 5.125kHz:
266  *
267  *      26e6 / (2 ** 17) * (8 + 5) * (2 ** 1) = 5157Hz
268  *
269  * For 2400 baud, use 1.5kHz:
270  *
271  *      26e6 / (2 ** 17) * (8 + 0) * (2 ** 0) = 1587Hz
272  */
273
274 #define PACKET_DEV_E_384        3
275 #define PACKET_DEV_M_384        5
276
277 #define PACKET_DEV_E_96         1
278 #define PACKET_DEV_M_96         5
279
280 #define PACKET_DEV_E_24         0
281 #define PACKET_DEV_M_24         0
282
283 /*
284  * For our packet data:
285  *
286  *              (256 + DATARATE_M) * 2 ** DATARATE_E
287  *      Rdata = -------------------------------------- * fosc
288  *                           2 ** 28
289  *
290  * For 38400 baud:
291  *
292  *              (256 + 131) * (2 ** 10) / (2**28) * 26e6 = 38383
293  *
294  *      DATARATE_M = 131
295  *      DATARATE_E_384 = 10
296  *      DATARATE_E_96 = 8
297  *      DATARATE_E_24 = 6
298  */
299 #define PACKET_DRATE_M          131
300
301 #define PACKET_DRATE_E_384      10
302 #define PACKET_DRATE_E_96       8
303 #define PACKET_DRATE_E_24       6
304
305 static const struct {
306         uint8_t         mdmcfg4;
307         uint8_t         deviatn;
308 } packet_rate_setup[] = {
309         [AO_RADIO_RATE_38400] = {
310                 .mdmcfg4 = ((0xf << 4) |
311                             (PACKET_DRATE_E_384 << CC115L_MDMCFG4_DRATE_E)),
312                 .deviatn = ((PACKET_DEV_E_384 << CC115L_DEVIATN_DEVIATION_E) |
313                             (PACKET_DEV_M_384 << CC115L_DEVIATN_DEVIATION_M)),
314         },
315
316         [AO_RADIO_RATE_9600] = {
317                 .mdmcfg4 = ((0xf << 4) |
318                             (PACKET_DRATE_E_96 << CC115L_MDMCFG4_DRATE_E)),
319                 .deviatn = ((PACKET_DEV_E_96 << CC115L_DEVIATN_DEVIATION_E) |
320                             (PACKET_DEV_M_96 << CC115L_DEVIATN_DEVIATION_M)),
321         },
322
323         [AO_RADIO_RATE_2400] = {
324                 .mdmcfg4 = ((0xf << 4) |
325                             (PACKET_DRATE_E_24 << CC115L_MDMCFG4_DRATE_E)),
326                 .deviatn = ((PACKET_DEV_E_24 << CC115L_DEVIATN_DEVIATION_E) |
327                             (PACKET_DEV_M_24 << CC115L_DEVIATN_DEVIATION_M)),
328         },
329 };
330
331 static const uint16_t packet_setup[] = {
332         CC115L_MDMCFG3,         (PACKET_DRATE_M),
333         CC115L_MDMCFG2,         ((CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
334                                  (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
335                                  (CC115L_MDMCFG2_SYNC_MODE_16BITS << CC115L_MDMCFG2_SYNC_MODE)),
336 };
337
338
339 /*
340  * RDF deviation is 3kHz
341  *
342  *      fdev = fosc >> 17 * (8 + dev_m) << dev_e
343  *
344  *      26e6 / (2 ** 17) * (8 + 7) * (2 ** 0) = 2975
345  */
346
347 #define RDF_DEV_E       0
348 #define RDF_DEV_M       7
349
350 /*
351  * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
352  *
353  *              (256 + DATARATE_M) * 2 ** DATARATE_E
354  *      Rdata = -------------------------------------- * fosc
355  *                           2 ** 28
356  *
357  *              (256 + 67) * (2 ** 6) / (2**28) * 26e6 = 2002
358  *
359  *      DATARATE_M = 67
360  *      DATARATE_E = 6
361  */
362 #define RDF_DRATE_E     6
363 #define RDF_DRATE_M     67
364
365 static const uint16_t rdf_setup[] = {
366         CC115L_DEVIATN,         ((RDF_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
367                                  (RDF_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
368         CC115L_MDMCFG4,         ((0xf << 4) |
369                                  (RDF_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
370         CC115L_MDMCFG3,         (RDF_DRATE_M),
371         CC115L_MDMCFG2,         ((CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
372                                  (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
373                                  (CC115L_MDMCFG2_SYNC_MODE_NONE << CC115L_MDMCFG2_SYNC_MODE)),
374 };
375
376 /*
377  * APRS deviation is 3kHz
378  *
379  * 26e6 / (2 ** 17) * (8 + 7) * (2 ** 0) = 2975
380  */
381
382 #define APRS_DEV_E      0
383 #define APRS_DEV_M      7
384
385 /*
386  * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate)
387  *
388  *              (256 + DATARATE_M) * 2 ** DATARATE_E
389  *      Rdata = -------------------------------------- * fosc
390  *                           2 ** 28
391  *
392  *              (256 + 131) * (2 ** 8) / (2**28) * 26e6 = 9596
393  *
394  *      DATARATE_M = 131
395  *      DATARATE_E = 8
396  *
397  */
398 #define APRS_DRATE_E    8
399 #define APRS_DRATE_M    131
400
401 static const uint16_t aprs_setup[] = {
402         CC115L_DEVIATN,         ((APRS_DEV_E << CC115L_DEVIATN_DEVIATION_E) |
403                                  (APRS_DEV_M << CC115L_DEVIATN_DEVIATION_M)),
404         CC115L_MDMCFG4,         ((0xf << 4) |
405                                  (APRS_DRATE_E << CC115L_MDMCFG4_DRATE_E)),
406         CC115L_MDMCFG3,         (APRS_DRATE_M),
407         CC115L_MDMCFG2,         ((CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |
408                                  (0 << CC115L_MDMCFG2_MANCHESTER_EN) |
409                                  (CC115L_MDMCFG2_SYNC_MODE_NONE << CC115L_MDMCFG2_SYNC_MODE)),
410 };
411
412 #define AO_PKTCTRL0_INFINITE    ((CC115L_PKTCTRL0_PKT_FORMAT_NORMAL << CC115L_PKTCTRL0_PKT_FORMAT) | \
413                                  (0 << CC115L_PKTCTRL0_PKT_CRC_EN) |                                    \
414                                  (CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_INFINITE << CC115L_PKTCTRL0_PKT_LENGTH_CONFIG))
415 #define AO_PKTCTRL0_FIXED       ((CC115L_PKTCTRL0_PKT_FORMAT_NORMAL << CC115L_PKTCTRL0_PKT_FORMAT) | \
416                                  (0 << CC115L_PKTCTRL0_PKT_CRC_EN) |                                    \
417                                  (CC115L_PKTCTRL0_PKT_LENGTH_CONFIG_FIXED << CC115L_PKTCTRL0_PKT_LENGTH_CONFIG))
418
419 static uint16_t ao_radio_mode;
420
421
422 /*
423  * These set the data rate and modulation parameters
424  */
425 #define AO_RADIO_MODE_BITS_PACKET_TX    1
426 #define AO_RADIO_MODE_BITS_RDF          2
427 #define AO_RADIO_MODE_BITS_APRS         4
428
429 /*
430  * Flips between infinite packet mode and fixed packet mode;
431  * we use infinite mode until the sender gives us the
432  * last chunk of data
433  */
434 #define AO_RADIO_MODE_BITS_INFINITE     40
435 #define AO_RADIO_MODE_BITS_FIXED        80
436
437 #define AO_RADIO_MODE_NONE              0
438
439 #define AO_RADIO_MODE_RDF               AO_RADIO_MODE_BITS_RDF
440 #define AO_RADIO_MODE_PACKET_TX         AO_RADIO_MODE_BITS_PACKET_TX
441 #define AO_RADIO_MODE_APRS              AO_RADIO_MODE_BITS_APRS
442
443 static void
444 ao_radio_set_mode(uint16_t new_mode)
445 {
446         uint16_t changes;
447         unsigned int i;
448
449         if (new_mode == ao_radio_mode)
450                 return;
451
452         changes = (uint16_t) (new_mode & (~ao_radio_mode));
453         if (changes & AO_RADIO_MODE_BITS_PACKET_TX) {
454                 ao_radio_reg_write(CC115L_MDMCFG4, packet_rate_setup[ao_config.radio_rate].mdmcfg4);
455                 ao_radio_reg_write(CC115L_DEVIATN, packet_rate_setup[ao_config.radio_rate].deviatn);
456
457                 for (i = 0; i < sizeof (packet_setup) / sizeof (packet_setup[0]); i += 2)
458                         ao_radio_reg_write((uint8_t) packet_setup[i], (uint8_t) packet_setup[i+1]);
459         }
460
461         if (changes & AO_RADIO_MODE_BITS_RDF)
462                 for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
463                         ao_radio_reg_write((uint8_t) rdf_setup[i], (uint8_t) rdf_setup[i+1]);
464
465         if (changes & AO_RADIO_MODE_BITS_APRS)
466                 for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2)
467                         ao_radio_reg_write((uint8_t) aprs_setup[i], (uint8_t) aprs_setup[i+1]);
468
469         if (changes & AO_RADIO_MODE_BITS_INFINITE)
470                 ao_radio_reg_write(CC115L_PKTCTRL0, AO_PKTCTRL0_INFINITE);
471
472         if (changes & AO_RADIO_MODE_BITS_FIXED)
473                 ao_radio_reg_write(CC115L_PKTCTRL0, AO_PKTCTRL0_FIXED);
474
475         ao_radio_mode = new_mode;
476 }
477
478 /***************************************************************
479  *  SmartRF Studio(tm) Export
480  *
481  *  Radio register settings specifed with address, value
482  *
483  *  RF device: CC115L
484  *
485  ***************************************************************/
486
487 static const uint16_t radio_setup[] = {
488
489         /* High when FIFO is above threshold, low when fifo is below threshold */
490         AO_CC115L_FIFO_INT_GPIO_IOCFG,      CC115L_IOCFG_GPIO_CFG_TXFIFO_THR,
491
492         /* High when transmitter is running, low when off */
493         AO_CC115L_DONE_INT_GPIO_IOCFG,      CC115L_IOCFG_GPIO_CFG_PA_PD | (1 << CC115L_IOCFG_GPIO_INV),
494
495         CC115L_FIFOTHR,                     0x47,       /* TX FIFO Thresholds */
496         CC115L_MDMCFG1,                                 /* Modem Configuration */
497                 ((CC115L_MDMCFG1_NUM_PREAMBLE_4 << CC115L_MDMCFG1_NUM_PREAMBLE) |
498                  (1 << CC115L_MDMCFG1_CHANSPC_E)),
499         CC115L_MDMCFG0,                     248,        /* Channel spacing M value (100kHz channels) */
500         CC115L_MCSM1,                       0x30,       /* Main Radio Control State Machine Configuration */
501         CC115L_MCSM0,                       0x38,       /* Main Radio Control State Machine Configuration */
502         CC115L_RESERVED_0X20,               0xfb,       /* Use setting from SmartRF Studio */
503         CC115L_FREND0,                      0x10,       /* Front End TX Configuration */
504         CC115L_FSCAL3,                      0xe9,       /* Frequency Synthesizer Calibration */
505         CC115L_FSCAL2,                      0x2a,       /* Frequency Synthesizer Calibration */
506         CC115L_FSCAL1,                      0x00,       /* Frequency Synthesizer Calibration */
507         CC115L_FSCAL0,                      0x1f,       /* Frequency Synthesizer Calibration */
508         CC115L_RESERVED_0X29,               0x59,       /* RESERVED */
509         CC115L_RESERVED_0X2A,               0x7f,       /* RESERVED */
510         CC115L_RESERVED_0X2B,               0x3f,       /* RESERVED */
511         CC115L_TEST2,                       0x81,       /* Various Test Settings */
512         CC115L_TEST1,                       0x35,       /* Various Test Settings */
513         CC115L_TEST0,                       0x09,       /* Various Test Settings */
514 };
515
516 static uint8_t  ao_radio_configured = 0;
517
518 #if HAS_RADIO_POWER
519 #define RADIO_POWER     ao_config.radio_power
520 #else
521
522 #if 0
523 #define RADIO_POWER     0x03    /* -31.75dBm on the test board */
524 #endif
525
526 #define RADIO_POWER     0xc0    /* full power */
527
528 #endif
529
530 static void
531 ao_radio_setup(void)
532 {
533         unsigned int    i;
534
535         ao_radio_strobe(CC115L_SRES);
536         ao_delay(AO_MS_TO_TICKS(10));
537
538         for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2)
539                 ao_radio_reg_write((uint8_t) radio_setup[i], (uint8_t) radio_setup[i+1]);
540
541         ao_radio_mode = 0;
542
543         ao_config_get();
544
545         ao_radio_reg_write(CC115L_PA, RADIO_POWER);
546
547         ao_radio_strobe(CC115L_SCAL);
548
549         ao_radio_configured = 1;
550 }
551
552 static void
553 ao_radio_set_len(uint8_t len)
554 {
555         static uint8_t  last_len;
556
557         if (len != last_len) {
558                 ao_radio_reg_write(CC115L_PKTLEN, len);
559                 last_len = len;
560         }
561 }
562
563 static void
564 ao_radio_get(void)
565 {
566         static uint32_t last_radio_setting;
567         static uint8_t  last_radio_rate;
568
569         ao_mutex_get(&ao_radio_mutex);
570         if (!ao_radio_configured)
571                 ao_radio_setup();
572         if (ao_config.radio_setting != last_radio_setting) {
573                 ao_radio_reg_write(CC115L_FREQ2, (uint8_t) (ao_config.radio_setting >> 16));
574                 ao_radio_reg_write(CC115L_FREQ1, (uint8_t) (ao_config.radio_setting >> 8));
575                 ao_radio_reg_write(CC115L_FREQ0, (uint8_t) (ao_config.radio_setting));
576                 last_radio_setting = ao_config.radio_setting;
577                 /* Make sure the RF calibration is current */
578                 ao_radio_strobe(CC115L_SCAL);
579         }
580         if (ao_config.radio_rate != last_radio_rate) {
581                 ao_radio_mode &= (uint16_t) ~AO_RADIO_MODE_BITS_PACKET_TX;
582                 last_radio_rate = ao_config.radio_rate;
583         }
584 }
585
586 static void
587 _ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode);
588
589 #define ao_radio_put()  ao_mutex_put(&ao_radio_mutex)
590
591 struct ao_radio_tone {
592         uint8_t value;
593         uint8_t len;
594 };
595
596 struct ao_radio_tone *ao_radio_tone;
597 uint8_t ao_radio_tone_count;
598 uint8_t ao_radio_tone_current;
599 uint8_t ao_radio_tone_offset;
600
601 static int16_t
602 ao_radio_tone_fill(uint8_t *buf, int16_t len)
603 {
604         int16_t ret = 0;
605
606         while (len) {
607                 int16_t                 this_time;
608                 struct ao_radio_tone    *t;
609
610                 /* Figure out how many to send of the current value */
611                 t = &ao_radio_tone[ao_radio_tone_current];
612                 this_time = t->len - ao_radio_tone_offset;
613                 if (this_time > len)
614                         this_time = len;
615
616                 /* queue the data */
617                 memset(buf, t->value, (size_t) this_time);
618
619                 /* mark as sent */
620                 len -= this_time;
621                 ao_radio_tone_offset += (uint8_t) this_time;
622                 ret += this_time;
623
624                 if (ao_radio_tone_offset >= t->len) {
625                         ao_radio_tone_offset = 0;
626                         ao_radio_tone_current++;
627                         if (ao_radio_tone_current >= ao_radio_tone_count) {
628                                 trace_add(trace_line, __LINE__, ret, "done with tone");
629                                 return -ret;
630                         }
631                 }
632         }
633         trace_add(trace_line, __LINE__, ret, "got some tone");
634         return ret;
635 }
636
637 static void
638 ao_radio_tone_run(struct ao_radio_tone *tones, int ntones)
639 {
640         ao_radio_get();
641         ao_radio_tone = tones;
642         ao_radio_tone_current = 0;
643         ao_radio_tone_offset = 0;
644         ao_radio_tone_count = (uint8_t) ntones;
645         _ao_radio_send_lots(ao_radio_tone_fill, AO_RADIO_MODE_RDF);
646         ao_radio_put();
647 }
648
649 void
650 ao_radio_rdf(void)
651 {
652         struct ao_radio_tone    tone;
653
654         tone.value = ao_radio_rdf_value;
655         tone.len = AO_RADIO_RDF_LEN;
656         ao_radio_tone_run(&tone, 1);
657 }
658
659 void
660 ao_radio_continuity(uint8_t c)
661 {
662         struct ao_radio_tone    tones[7];
663         uint8_t count = 0;
664         uint8_t i;
665
666         for (i = 0; i < 3; i++) {
667                 tones[count].value = 0x00;
668                 tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
669                 count++;
670                 if (i < c)
671                         tones[count].value = ao_radio_rdf_value;
672                 else
673                         tones[count].value = 0x00;
674                 tones[count].len = AO_RADIO_CONT_TONE_LEN;
675                 count++;
676         }
677         tones[count].value = 0x00;
678         tones[count].len = AO_RADIO_CONT_PAUSE_LEN;
679         count++;
680         ao_radio_tone_run(tones, count);
681 }
682
683 void
684 ao_radio_rdf_abort(void)
685 {
686         ao_radio_abort = 1;
687         ao_wakeup(&ao_radio_wake);
688 }
689
690 #define POWER_STEP      0x08
691
692 static void
693 ao_radio_stx(void)
694 {
695         ao_radio_pa_on();
696         ao_radio_strobe(CC115L_STX);
697 }
698
699 static void
700 ao_radio_test_cmd(void)
701 {
702         uint8_t mode = 2;
703         static uint8_t radio_on;
704         ao_cmd_white();
705         if (ao_cmd_lex_c != '\n')
706                 mode = (uint8_t) ao_cmd_decimal();
707         mode++;
708         if ((mode & 2) && !radio_on) {
709 #if HAS_MONITOR
710                 ao_monitor_disable();
711 #endif
712 #if PACKET_HAS_SLAVE
713                 ao_packet_slave_stop();
714 #endif
715                 ao_radio_get();
716                 ao_radio_strobe(CC115L_SFTX);
717                 ao_radio_set_len(0xff);
718                 ao_radio_set_mode(AO_RADIO_MODE_RDF);
719                 ao_radio_stx();
720                 radio_on = 1;
721         }
722         if (mode == 3) {
723                 printf ("Hit a character to stop..."); flush();
724                 getchar();
725                 putchar('\n');
726         }
727         if ((mode & 1) && radio_on) {
728                 ao_radio_idle();
729                 ao_radio_put();
730                 radio_on = 0;
731 #if HAS_MONITOR
732                 ao_monitor_enable();
733 #endif
734         }
735 }
736
737 #if CC115L_TRACE
738 static inline int16_t
739 ao_radio_gpio_bits(void)
740 {
741         return ((ao_gpio_get(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN, AO_CC115L_DONE_INT) << 1) |
742                 ao_gpio_get(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN, AO_CC115L_FIFO_INT));
743 }
744 #endif
745
746 static void
747 ao_radio_wait_fifo(void)
748 {
749         ao_arch_block_interrupts();
750         while (!ao_radio_fifo && !ao_radio_done && !ao_radio_abort) {
751                 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_fifo");
752                 ao_sleep(&ao_radio_wake);
753         }
754         ao_arch_release_interrupts();
755         trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits");
756         trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo");
757         trace_add(trace_line, __LINE__, ao_radio_done, "wake done");
758         trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort");
759 }
760
761 static void
762 ao_radio_wait_done(void)
763 {
764         ao_arch_block_interrupts();
765         while (!ao_radio_done && !ao_radio_abort) {
766                 trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wait_done");
767                 ao_sleep(&ao_radio_wake);
768         }
769         ao_arch_release_interrupts();
770         trace_add(trace_line, __LINE__, ao_radio_gpio_bits(), "wake bits");
771         trace_add(trace_line, __LINE__, ao_radio_fifo, "wake fifo");
772         trace_add(trace_line, __LINE__, ao_radio_done, "wake done");
773         trace_add(trace_line, __LINE__, ao_radio_abort, "wake abort");
774 }
775
776 static uint8_t  tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
777
778 static uint8_t  *ao_radio_send_buf;
779 static int16_t  ao_radio_send_len;
780
781 static int16_t
782 ao_radio_send_fill(uint8_t *buf, int16_t len)
783 {
784         int16_t this_time;
785
786         this_time = ao_radio_send_len;
787         if (this_time > len)
788                 this_time = len;
789         memcpy(buf, ao_radio_send_buf, (size_t) this_time);
790         ao_radio_send_buf += this_time;
791         ao_radio_send_len -= this_time;
792         if (ao_radio_send_len == 0)
793                 return -this_time;
794         return this_time;
795 }
796
797 void
798 ao_radio_send(const void *d, uint8_t size)
799 {
800         ao_radio_get();
801         ao_radio_send_len = ao_fec_encode(d, size, tx_data);
802         ao_radio_send_buf = tx_data;
803         _ao_radio_send_lots(ao_radio_send_fill, AO_RADIO_MODE_PACKET_TX);
804         ao_radio_put();
805 }
806
807 #define AO_RADIO_LOTS   64
808
809 static void
810 _ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode)
811 {
812         uint8_t buf[AO_RADIO_LOTS], *b;
813         int     cnt;
814         int     total = 0;
815         uint8_t done = 0;
816         uint8_t started = 0;
817         uint8_t fifo_space;
818
819         fifo_space = CC115L_FIFO_SIZE;
820         ao_radio_abort = 0;
821
822         ao_radio_strobe(CC115L_SFTX);
823
824         ao_radio_done = 0;
825         ao_radio_fifo = 0;
826         while (!done) {
827                 cnt = (*fill)(buf, sizeof(buf));
828                 trace_add(trace_line, __LINE__, cnt, "send data count");
829                 if (cnt < 0) {
830                         done = 1;
831                         cnt = -cnt;
832                 }
833                 total += cnt;
834
835                 /* At the last buffer, set the total length */
836                 if (done) {
837                         ao_radio_set_len((uint8_t) (total & 0xff));
838                         ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_FIXED);
839                 } else {
840                         ao_radio_set_len(0xff);
841                         ao_radio_set_mode(mode | AO_RADIO_MODE_BITS_INFINITE);
842                 }
843
844                 b = buf;
845                 while (cnt) {
846                         uint8_t this_len = (uint8_t) cnt;
847
848                         /* Wait for some space in the fifo */
849                         while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
850                                 trace_add(trace_line, __LINE__, this_len, "wait for space");
851                                 ao_radio_wait_fifo();
852                         }
853                         if (ao_radio_abort || ao_radio_done)
854                                 break;
855                         trace_add(trace_line, __LINE__, fifo_space, "got space");
856                         if (this_len > fifo_space)
857                                 this_len = fifo_space;
858
859                         cnt -= this_len;
860
861                         ao_radio_done = 0;
862                         ao_radio_fifo = 0;
863                         ao_radio_fifo_write(b, this_len);
864                         b += this_len;
865
866                         ao_exti_enable(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN);
867                         ao_exti_enable(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN);
868
869                         if (!started) {
870                                 ao_radio_stx();
871                                 started = 1;
872                         }
873                 }
874                 if (ao_radio_abort || ao_radio_done)
875                         break;
876         }
877         if (ao_radio_abort)
878                 ao_radio_idle();
879         ao_radio_wait_done();
880         ao_radio_pa_off();
881 }
882
883 void
884 ao_radio_send_aprs(ao_radio_fill_func fill)
885 {
886         ao_radio_get();
887         _ao_radio_send_lots(fill, AO_RADIO_MODE_APRS);
888         ao_radio_put();
889 }
890
891 #if CC115L_DEBUG
892 static const char *cc115l_state_name[] = {
893         [CC115L_STATUS_STATE_IDLE] = "IDLE",
894         [CC115L_STATUS_STATE_TX] = "TX",
895         [CC115L_STATUS_STATE_FSTXON] = "FSTXON",
896         [CC115L_STATUS_STATE_CALIBRATE] = "CALIBRATE",
897         [CC115L_STATUS_STATE_SETTLING] = "SETTLING",
898         [CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW] = "TX_FIFO_UNDERFLOW",
899 };
900
901 static const struct ao_cc115l_reg ao_cc115l_reg[] = {
902         { .addr = CC115L_IOCFG2, .name = "IOCFG2" },
903         { .addr = CC115L_IOCFG1, .name = "IOCFG1" },
904         { .addr = CC115L_IOCFG0, .name = "IOCFG0" },
905         { .addr = CC115L_FIFOTHR, .name = "FIFOTHR" },
906         { .addr = CC115L_SYNC1, .name = "SYNC1" },
907         { .addr = CC115L_SYNC0, .name = "SYNC0" },
908         { .addr = CC115L_PKTLEN, .name = "PKTLEN" },
909         { .addr = CC115L_PKTCTRL0, .name = "PKTCTRL0" },
910         { .addr = CC115L_CHANNR, .name = "CHANNR" },
911         { .addr = CC115L_FSCTRL0, .name = "FSCTRL0" },
912         { .addr = CC115L_FREQ2, .name = "FREQ2" },
913         { .addr = CC115L_FREQ1, .name = "FREQ1" },
914         { .addr = CC115L_FREQ0, .name = "FREQ0" },
915         { .addr = CC115L_MDMCFG4, .name = "MDMCFG4" },
916         { .addr = CC115L_MDMCFG3, .name = "MDMCFG3" },
917         { .addr = CC115L_MDMCFG2, .name = "MDMCFG2" },
918         { .addr = CC115L_MDMCFG1, .name = "MDMCFG1" },
919         { .addr = CC115L_MDMCFG0, .name = "MDMCFG0" },
920         { .addr = CC115L_DEVIATN, .name = "DEVIATN" },
921         { .addr = CC115L_MCSM1, .name = "MCSM1" },
922         { .addr = CC115L_MCSM0, .name = "MCSM0" },
923         { .addr = CC115L_RESERVED_0X20, .name = "RESERVED_0X20" },
924         { .addr = CC115L_FREND0, .name = "FREND0" },
925         { .addr = CC115L_FSCAL3, .name = "FSCAL3" },
926         { .addr = CC115L_FSCAL2, .name = "FSCAL2" },
927         { .addr = CC115L_FSCAL1, .name = "FSCAL1" },
928         { .addr = CC115L_FSCAL0, .name = "FSCAL0" },
929         { .addr = CC115L_RESERVED_0X29, .name = "RESERVED_0X29" },
930         { .addr = CC115L_RESERVED_0X2A, .name = "RESERVED_0X2A" },
931         { .addr = CC115L_RESERVED_0X2B, .name = "RESERVED_0X2B" },
932         { .addr = CC115L_TEST2, .name = "TEST2" },
933         { .addr = CC115L_TEST1, .name = "TEST1" },
934         { .addr = CC115L_TEST0, .name = "TEST0" },
935         { .addr = CC115L_PARTNUM, .name = "PARTNUM" },
936         { .addr = CC115L_VERSION, .name = "VERSION" },
937         { .addr = CC115L_MARCSTATE, .name = "MARCSTATE" },
938         { .addr = CC115L_PKTSTATUS, .name = "PKTSTATUS" },
939         { .addr = CC115L_TXBYTES, .name = "TXBYTES" },
940         { .addr = CC115L_PA, .name = "PA" },
941 };
942
943 #define AO_NUM_CC115L_REG       (sizeof ao_cc115l_reg / sizeof ao_cc115l_reg[0])
944
945 static void ao_radio_show(void) {
946         uint8_t status = ao_radio_status();
947         unsigned int    i;
948
949         ao_radio_get();
950         status = ao_radio_status();
951         printf ("Status:   %02x\n", status);
952         printf ("CHIP_RDY: %d\n", (status >> CC115L_STATUS_CHIP_RDY) & 1);
953         printf ("STATE:    %s\n", cc115l_state_name[(status >> CC115L_STATUS_STATE) & CC115L_STATUS_STATE_MASK]);
954         printf ("MARC:     %02x\n", ao_radio_get_marcstate());
955
956         for (i = 0; i < AO_NUM_CC115L_REG; i++)
957                 printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc115l_reg[i].addr), ao_cc115l_reg[i].name);
958         ao_radio_put();
959 }
960
961 static void ao_radio_beep(void) {
962         ao_radio_rdf();
963 }
964
965 static void ao_radio_packet(void) {
966         static const uint8_t packet[] = {
967 #if 1
968                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
969                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
970                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
971                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
972 #else
973                 3, 1, 2, 3
974 #endif
975         };
976
977         ao_radio_send(packet, sizeof (packet));
978 }
979
980
981 #if HAS_APRS
982 #include <ao_aprs.h>
983
984 static void
985 ao_radio_aprs()
986 {
987 #if PACKET_HAS_SLAVE
988         ao_packet_slave_stop();
989 #endif
990         ao_aprs_send();
991 }
992 #endif
993 #endif /* CC115L_DEBUG */
994
995 static const struct ao_cmds ao_radio_cmds[] = {
996         { ao_radio_test_cmd,    "C <1 start, 0 stop, none both>\0Radio carrier test" },
997 #if CC115L_DEBUG
998 #if HAS_APRS
999         { ao_radio_aprs,        "G\0Send APRS packet" },
1000 #endif
1001         { ao_radio_show,        "R\0Show CC115L status" },
1002         { ao_radio_beep,        "b\0Emit an RDF beacon" },
1003         { ao_radio_packet,      "p\0Send a test packet" },
1004 #endif
1005         { 0, NULL }
1006 };
1007
1008 void
1009 ao_radio_init(void)
1010 {
1011 #if 0
1012         int     i;
1013 #endif
1014
1015         ao_radio_configured = 0;
1016         ao_spi_init_cs (AO_CC115L_SPI_CS_PORT, (1 << AO_CC115L_SPI_CS_PIN));
1017
1018 #if 0
1019         AO_CC115L_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC115L_SPI_CS_PIN));
1020         for (i = 0; i < 10000; i++) {
1021                 if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
1022                         break;
1023         }
1024         AO_CC115L_SPI_CS_PORT->bsrr = (1 << AO_CC115L_SPI_CS_PIN);
1025         if (i == 10000)
1026                 ao_panic(AO_PANIC_SELF_TEST_CC115L);
1027 #endif
1028
1029         /* Enable the fifo threhold interrupt pin */
1030         ao_enable_port(AO_CC115L_FIFO_INT_PORT);
1031         ao_exti_setup(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN,
1032                       AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH,
1033                       ao_radio_fifo_isr);
1034
1035         /* Enable the tx done interrupt pin */
1036         ao_enable_port(AO_CC115L_DONE_INT_PORT);
1037         ao_exti_setup(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN,
1038                       AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED,
1039                       ao_radio_done_isr);
1040
1041         ao_radio_pa_init();
1042
1043         ao_cmd_register(&ao_radio_cmds[0]);
1044 }