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