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