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