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