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