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