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