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