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