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