altos/cc1111: Add 2400 and 9600 baud telemetry rate support
[fw/altos] / src / cc1111 / ao_radio.c
1 /*
2  * Copyright © 2009 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 #if HAS_PAD
20 #include <ao_pad.h>
21 #endif
22
23 /* Values from SmartRF® Studio for:
24  *
25  * Deviation:   20.507812 kHz
26  * Datarate:    38.360596 kBaud
27  * Modulation:  GFSK
28  * RF Freq:     434.549927 MHz
29  * Channel:     99.975586 kHz
30  * Channel:     0
31  * RX filter:   93.75 kHz
32  */
33
34 /*
35  * For IF freq of 140.62kHz, the IF value is:
36  *
37  * 140.62e3 / (24e6 / 2**10) = 6
38  */
39
40 #define IF_FREQ_CONTROL 6
41
42 /*
43  *  http://www.ntia.doc.gov/files/ntia/publications/84-168.pdf
44  *
45  * Necessary bandwidth for a FSK modulated signal:
46  *
47  *      bw = 2.6d + 0.55b       1.5 < m < 5.5
48  *      bw = 2.1d + 1.9b        5.5 < m < 20
49  *
50  *      b is the modulation rate in bps
51  *      d is the peak deviation (from the center)
52  *
53  *      m = 2d / b
54  *
55  * 20.5 kHz deviation 38.4kbps signal:
56  *
57  *      m = 41 / 38.4, which is < 5.5:
58  *
59  *      bw = 2.6 * 20.5 + 0.55 * 38.4 = 74.42kHz
60  *
61  *      M = 1, E = 3, bw = 75kHz
62  *
63  * 20.5 kHz deviation, 9.6kbps signal
64  *
65  *      m = 41 / 9.6, which is < 5.5:
66  *
67  *      bw = 2.6 * 20.5 + 0.55 * 9.6 = 58.58kHz
68  *
69  *      M = 2, E = 3, bw = 62.5kHz
70  *
71  * 20.5kHz deviation, 2.4kbps signal
72  *
73  *      m = 41 / 2.4, which is > 5.5:
74  *
75  *      bw = 2.1 * 20.5 + 1.9 * 2.4 = 47.61kHz
76  *
77  *      M = 3, E = 3, bw = 53.6kHz
78  *
79  * For channel bandwidth of 93.75 kHz, the CHANBW_E and CHANBW_M values are
80  *
81  * BW = 24e6 / (8 * (4 + M) * 2 ** E)
82  *
83  * So, M = 0 and E = 3
84  */
85
86 #define CHANBW_M_384    1
87 #define CHANBW_M_96     2
88 #define CHANBW_M_24     3
89 #define CHANBW_E        3
90
91 /*
92  * For a symbol rate of 38360kBaud, the DRATE_E and DRATE_M values are:
93  *
94  * R = (256 + M) * 2** E * 24e6 / 2**28
95  *
96  * So for 38360kBaud, M is 163 and E is 10
97  */
98
99 #define DRATE_M         163
100
101 #define DRATE_E_384     10
102
103 /* For 9600 baud, M is 163 and E is 8
104  */
105
106 #define DRATE_E_96      8
107
108 /* For 2400 baud, M is 163 and E is 6
109  */
110
111 #define DRATE_E_24      6
112
113 /*
114  * For a channel deviation of 20.5kHz, the DEVIATION_E and DEVIATION_M values are:
115  *
116  * F = 24e6/2**17 * (8 + DEVIATION_M) * 2**DEVIATION_E
117  *
118  * So M is 6 and E is 3
119  */
120
121 #define DEVIATION_M     6
122 #define DEVIATION_E     3
123
124 /*
125  * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone),
126  * so the DRATE_E and DRATE_M values are:
127  *
128  * M is 94 and E is 6
129  *
130  * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes
131  */
132
133 #define RDF_DRATE_E     6
134 #define RDF_DRATE_M     94
135 #define RDF_PACKET_LEN  50
136
137 /*
138  * RDF deviation should match the normal NFM value of 5kHz
139  *
140  * M is 6 and E is 1
141  *
142  */
143
144 #define RDF_DEVIATION_M 6
145 #define RDF_DEVIATION_E 1
146
147 /* This are from the table for 433MHz */
148
149 #define RF_POWER_M30_DBM        0x12
150 #define RF_POWER_M20_DBM        0x0e
151 #define RF_POWER_M15_DBM        0x1d
152 #define RF_POWER_M10_DBM        0x34
153 #define RF_POWER_M5_DBM         0x2c
154 #define RF_POWER_0_DBM          0x60
155 #define RF_POWER_5_DBM          0x84
156 #define RF_POWER_7_DBM          0xc8
157 #define RF_POWER_10_DBM         0xc0
158
159 #define RF_POWER                RF_POWER_10_DBM
160
161 static __code uint8_t radio_setup[] = {
162         RF_PA_TABLE7_OFF,       RF_POWER,
163         RF_PA_TABLE6_OFF,       RF_POWER,
164         RF_PA_TABLE5_OFF,       RF_POWER,
165         RF_PA_TABLE4_OFF,       RF_POWER,
166         RF_PA_TABLE3_OFF,       RF_POWER,
167         RF_PA_TABLE2_OFF,       RF_POWER,
168         RF_PA_TABLE1_OFF,       RF_POWER,
169         RF_PA_TABLE0_OFF,       RF_POWER,
170
171         RF_FSCTRL1_OFF,         (IF_FREQ_CONTROL << RF_FSCTRL1_FREQ_IF_SHIFT),
172         RF_FSCTRL0_OFF,         (0 << RF_FSCTRL0_FREQOFF_SHIFT),
173
174         RF_MDMCFG3_OFF,         (DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT),
175         RF_MDMCFG2_OFF,         (RF_MDMCFG2_DEM_DCFILT_ON |
176                                  RF_MDMCFG2_MOD_FORMAT_GFSK |
177                                  RF_MDMCFG2_SYNC_MODE_15_16),
178         RF_MDMCFG1_OFF,         (RF_MDMCFG1_FEC_EN |
179                                  RF_MDMCFG1_NUM_PREAMBLE_4 |
180                                  (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)),
181         RF_MDMCFG0_OFF,         (17 << RF_MDMCFG0_CHANSPC_M_SHIFT),
182
183         RF_CHANNR_OFF,          0,
184
185         RF_DEVIATN_OFF,         ((DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) |
186                                  (DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)),
187
188         /* SmartRF says set LODIV_BUF_CURRENT_TX to 0
189          * And, we're not using power ramping, so use PA_POWER 0
190          */
191         RF_FREND0_OFF,          ((1 << RF_FREND0_LODIV_BUF_CURRENT_TX_SHIFT) |
192                                  (0 << RF_FREND0_PA_POWER_SHIFT)),
193
194         RF_FREND1_OFF,          ((1 << RF_FREND1_LNA_CURRENT_SHIFT) |
195                                  (1 << RF_FREND1_LNA2MIX_CURRENT_SHIFT) |
196                                  (1 << RF_FREND1_LODIV_BUF_CURRENT_RX_SHIFT) |
197                                  (2 << RF_FREND1_MIX_CURRENT_SHIFT)),
198
199         RF_FSCAL3_OFF,          0xE9,
200         RF_FSCAL2_OFF,          0x0A,
201         RF_FSCAL1_OFF,          0x00,
202         RF_FSCAL0_OFF,          0x1F,
203
204         RF_TEST2_OFF,           RF_TEST2_RX_LOW_DATA_RATE_MAGIC,
205         RF_TEST1_OFF,           RF_TEST1_RX_LOW_DATA_RATE_MAGIC,
206         RF_TEST0_OFF,           0x09,
207
208         /* default sync values */
209         RF_SYNC1_OFF,           0xD3,
210         RF_SYNC0_OFF,           0x91,
211
212         /* max packet length */
213         RF_PKTCTRL1_OFF,        ((1 << PKTCTRL1_PQT_SHIFT)|
214                                  PKTCTRL1_APPEND_STATUS|
215                                  PKTCTRL1_ADR_CHK_NONE),
216         RF_PKTCTRL0_OFF,        (RF_PKTCTRL0_WHITE_DATA|
217                                  RF_PKTCTRL0_PKT_FORMAT_NORMAL|
218                                  RF_PKTCTRL0_CRC_EN|
219                                  RF_PKTCTRL0_LENGTH_CONFIG_FIXED),
220         RF_ADDR_OFF,            0x00,
221         RF_MCSM2_OFF,           (RF_MCSM2_RX_TIME_END_OF_PACKET),
222         RF_MCSM1_OFF,           (RF_MCSM1_CCA_MODE_RSSI_BELOW_UNLESS_RECEIVING|
223                                  RF_MCSM1_RXOFF_MODE_IDLE|
224                                  RF_MCSM1_TXOFF_MODE_IDLE),
225         RF_MCSM0_OFF,           (RF_MCSM0_FS_AUTOCAL_FROM_IDLE|
226                                  RF_MCSM0_MAGIC_3|
227                                  RF_MCSM0_CLOSE_IN_RX_0DB),
228         RF_FOCCFG_OFF,          (RF_FOCCFG_FOC_PRE_K_3K,
229                                  RF_FOCCFG_FOC_POST_K_PRE_K,
230                                  RF_FOCCFG_FOC_LIMIT_BW_OVER_4),
231         RF_BSCFG_OFF,           (RF_BSCFG_BS_PRE_K_2K|
232                                  RF_BSCFG_BS_PRE_KP_3KP|
233                                  RF_BSCFG_BS_POST_KI_PRE_KI|
234                                  RF_BSCFG_BS_POST_KP_PRE_KP|
235                                  RF_BSCFG_BS_LIMIT_0),
236         RF_AGCCTRL2_OFF,        (RF_AGCCTRL2_MAX_DVGA_GAIN_ALL|
237                                  RF_AGCCTRL2_MAX_LNA_GAIN_0|
238                                  RF_AGCCTRL2_MAGN_TARGET_33dB),
239         RF_AGCCTRL1_OFF,        (RF_AGCCTRL1_AGC_LNA_PRIORITY_0 |
240                                  RF_AGCCTRL1_CARRIER_SENSE_REL_THR_DISABLE |
241                                  RF_AGCCTRL1_CARRIER_SENSE_ABS_THR_0DB),
242         RF_AGCCTRL0_OFF,        (RF_AGCCTRL0_HYST_LEVEL_NONE |
243                                  RF_AGCCTRL0_WAIT_TIME_8 |
244                                  RF_AGCCTRL0_AGC_FREEZE_NORMAL |
245                                  RF_AGCCTRL0_FILTER_LENGTH_8),
246         RF_IOCFG2_OFF,          0x00,
247         RF_IOCFG1_OFF,          0x00,
248         RF_IOCFG0_OFF,          0x00,
249 };
250
251 static __code uint8_t rdf_setup[] = {
252         RF_MDMCFG4_OFF,         ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
253                                  (CHANBW_M_384 << RF_MDMCFG4_CHANBW_M_SHIFT) |
254                                  (RDF_DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)),
255         RF_MDMCFG3_OFF,         (RDF_DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT),
256         RF_MDMCFG2_OFF,         (RF_MDMCFG2_DEM_DCFILT_OFF |
257                                  RF_MDMCFG2_MOD_FORMAT_GFSK |
258                                  RF_MDMCFG2_SYNC_MODE_NONE),
259         RF_MDMCFG1_OFF,         (RF_MDMCFG1_FEC_DIS |
260                                  RF_MDMCFG1_NUM_PREAMBLE_2 |
261                                  (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)),
262
263         RF_DEVIATN_OFF,         ((RDF_DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) |
264                                  (RDF_DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)),
265
266         /* packet length is set in-line */
267         RF_PKTCTRL1_OFF,        ((0 << PKTCTRL1_PQT_SHIFT)|
268                                  PKTCTRL1_ADR_CHK_NONE),
269         RF_PKTCTRL0_OFF,        (RF_PKTCTRL0_PKT_FORMAT_NORMAL|
270                                  RF_PKTCTRL0_LENGTH_CONFIG_FIXED),
271 };
272
273 static __code uint8_t fixed_pkt_setup[] = {
274 #if !HAS_RADIO_RATE
275         RF_MDMCFG4_OFF,         ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
276                                  (CHANBW_M_384 << RF_MDMCFG4_CHANBW_M_SHIFT) |
277                                  (DRATE_E_384 << RF_MDMCFG4_DRATE_E_SHIFT)),
278 #endif
279         RF_MDMCFG3_OFF,         (DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT),
280         RF_MDMCFG2_OFF,         (RF_MDMCFG2_DEM_DCFILT_ON |
281                                  RF_MDMCFG2_MOD_FORMAT_GFSK |
282                                  RF_MDMCFG2_SYNC_MODE_15_16),
283         RF_MDMCFG1_OFF,         (RF_MDMCFG1_FEC_EN |
284                                  RF_MDMCFG1_NUM_PREAMBLE_4 |
285                                  (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)),
286
287         RF_DEVIATN_OFF,         ((DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) |
288                                  (DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)),
289
290         /* max packet length -- now set inline */
291         RF_PKTCTRL1_OFF,        ((1 << PKTCTRL1_PQT_SHIFT)|
292                                  PKTCTRL1_APPEND_STATUS|
293                                  PKTCTRL1_ADR_CHK_NONE),
294         RF_PKTCTRL0_OFF,        (RF_PKTCTRL0_WHITE_DATA|
295                                  RF_PKTCTRL0_PKT_FORMAT_NORMAL|
296                                  RF_PKTCTRL0_CRC_EN|
297                                  RF_PKTCTRL0_LENGTH_CONFIG_FIXED),
298 };
299
300 #if HAS_RADIO_RATE
301 static __code uint8_t packet_rate_setup[] = {
302         /* 38400 */
303         ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
304          (CHANBW_M_384 << RF_MDMCFG4_CHANBW_M_SHIFT) |
305          (DRATE_E_384 << RF_MDMCFG4_DRATE_E_SHIFT)),
306         /* 9600 */
307         ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
308          (CHANBW_M_96 << RF_MDMCFG4_CHANBW_M_SHIFT) |
309          (DRATE_E_96 << RF_MDMCFG4_DRATE_E_SHIFT)),
310         /* 2400 */
311         ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
312          (CHANBW_M_24 << RF_MDMCFG4_CHANBW_M_SHIFT) |
313          (DRATE_E_24 << RF_MDMCFG4_DRATE_E_SHIFT)),
314 };
315 #endif
316
317 __xdata uint8_t ao_radio_dma;
318 __xdata uint8_t ao_radio_dma_done;
319 __xdata uint8_t ao_radio_done;
320 __xdata uint8_t ao_radio_abort;
321 __xdata uint8_t ao_radio_mutex;
322
323 #if PACKET_HAS_MASTER || HAS_AES
324 #define NEED_RADIO_RSSI 1
325 #endif
326
327 #ifndef NEED_RADIO_RSSI
328 #define NEED_RADIO_RSSI 0
329 #endif
330
331 #if NEED_RADIO_RSSI
332 __xdata int8_t ao_radio_rssi;
333 #endif
334
335 void
336 ao_radio_general_isr(void) __interrupt 16
337 {
338         S1CON &= ~0x03;
339         if (RFIF & RFIF_IM_TIMEOUT) {
340                 ao_radio_recv_abort();
341                 RFIF &= ~ RFIF_IM_TIMEOUT;
342         } else if (RFIF & RFIF_IM_DONE) {
343                 ao_radio_done = 1;
344                 ao_wakeup(&ao_radio_done);
345                 RFIF &= ~RFIF_IM_DONE;
346         }
347 }
348
349 static void
350 ao_radio_set_packet(void)
351 {
352         uint8_t i;
353         for (i = 0; i < sizeof (fixed_pkt_setup); i += 2)
354                 RF[fixed_pkt_setup[i]] = fixed_pkt_setup[i+1];
355 }
356
357 static void
358 ao_radio_idle(void)
359 {
360         if (RF_MARCSTATE != RF_MARCSTATE_IDLE)
361         {
362                 do {
363                         RFST = RFST_SIDLE;
364                         ao_yield();
365                 } while (RF_MARCSTATE != RF_MARCSTATE_IDLE);
366         }
367 }
368
369 #define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
370
371 static void
372 ao_radio_get(uint8_t len)
373 {
374         ao_config_get();
375         ao_mutex_get(&ao_radio_mutex);
376         ao_radio_idle();
377         RF_CHANNR = 0;
378         RF_FREQ2 = (uint8_t) (ao_config.radio_setting >> 16);
379         RF_FREQ1 = (uint8_t) (ao_config.radio_setting >> 8);
380         RF_FREQ0 = (uint8_t) (ao_config.radio_setting);
381         RF_PKTLEN = len;
382 #if HAS_RADIO_RATE
383         RF_MDMCFG4 = packet_rate_setup[ao_config.radio_rate];
384 #endif
385 }
386
387
388 void
389 ao_radio_send(__xdata void *packet, uint8_t size) __reentrant
390 {
391         ao_radio_get(size);
392         ao_radio_done = 0;
393         ao_dma_set_transfer(ao_radio_dma,
394                             packet,
395                             &RFDXADDR,
396                             size,
397                             DMA_CFG0_WORDSIZE_8 |
398                             DMA_CFG0_TMODE_SINGLE |
399                             DMA_CFG0_TRIGGER_RADIO,
400                             DMA_CFG1_SRCINC_1 |
401                             DMA_CFG1_DESTINC_0 |
402                             DMA_CFG1_PRIORITY_HIGH);
403         ao_dma_start(ao_radio_dma);
404         RFST = RFST_STX;
405         __critical while (!ao_radio_done)
406                 ao_sleep(&ao_radio_done);
407         ao_radio_put();
408 }
409
410 uint8_t
411 ao_radio_recv(__xdata void *packet, uint8_t size, uint8_t timeout) __reentrant
412 {
413         ao_radio_abort = 0;
414         ao_radio_get(size - 2);
415         ao_dma_set_transfer(ao_radio_dma,
416                             &RFDXADDR,
417                             packet,
418                             size,
419                             DMA_CFG0_WORDSIZE_8 |
420                             DMA_CFG0_TMODE_SINGLE |
421                             DMA_CFG0_TRIGGER_RADIO,
422                             DMA_CFG1_SRCINC_0 |
423                             DMA_CFG1_DESTINC_1 |
424                             DMA_CFG1_PRIORITY_HIGH);
425         ao_dma_start(ao_radio_dma);
426         RFST = RFST_SRX;
427
428         /* Wait for DMA to be done, for the radio receive process to
429          * get aborted or for a receive timeout to fire
430          */
431         if (timeout)
432                 ao_alarm(timeout);
433         __critical while (!ao_radio_dma_done && !ao_radio_abort)
434                            if (ao_sleep(&ao_radio_dma_done))
435                                    break;
436         if (timeout)
437                 ao_clear_alarm();
438
439         /* If recv was aborted, clean up by stopping the DMA engine
440          * and idling the radio
441          */
442         if (!ao_radio_dma_done) {
443                 ao_dma_abort(ao_radio_dma);
444                 ao_radio_idle();
445 #if NEED_RADIO_RSSI
446                 ao_radio_rssi = 0;
447 #endif
448         }
449 #if NEED_RADIO_RSSI
450         else
451                 ao_radio_rssi = AO_RSSI_FROM_RADIO(((uint8_t *)packet)[size - 2]);
452 #endif
453         ao_radio_put();
454         return ao_radio_dma_done;
455 }
456
457 /*
458  * Wake up a task waiting to receive a radio packet
459  * and tell them to abort the transfer
460  */
461
462 void
463 ao_radio_recv_abort(void)
464 {
465         ao_radio_abort = 1;
466         ao_wakeup(&ao_radio_dma_done);
467 }
468
469 __code ao_radio_rdf_value = 0x55;
470
471 static void
472 ao_radio_rdf_start(void)
473 {
474         uint8_t i;
475         ao_radio_abort = 0;
476         ao_radio_get(AO_RADIO_RDF_LEN);
477         ao_radio_done = 0;
478         for (i = 0; i < sizeof (rdf_setup); i += 2)
479                 RF[rdf_setup[i]] = rdf_setup[i+1];
480 }
481
482 static void
483 ao_radio_rdf_run(void)
484 {
485         ao_dma_start(ao_radio_dma);
486         RFST = RFST_STX;
487         __critical while (!ao_radio_done && !ao_radio_abort)
488                            ao_sleep(&ao_radio_done);
489         if (!ao_radio_done) {
490                 ao_dma_abort(ao_radio_dma);
491                 ao_radio_idle();
492         }
493         ao_radio_set_packet();
494         ao_radio_put();
495 }
496
497 void
498 ao_radio_rdf(void)
499 {
500         ao_radio_rdf_start();
501
502         ao_dma_set_transfer(ao_radio_dma,
503                             CODE_TO_XDATA(&ao_radio_rdf_value),
504                             &RFDXADDR,
505                             AO_RADIO_RDF_LEN,
506                             DMA_CFG0_WORDSIZE_8 |
507                             DMA_CFG0_TMODE_SINGLE |
508                             DMA_CFG0_TRIGGER_RADIO,
509                             DMA_CFG1_SRCINC_0 |
510                             DMA_CFG1_DESTINC_0 |
511                             DMA_CFG1_PRIORITY_HIGH);
512         ao_radio_rdf_run();
513 }
514
515 #define PA      0x00
516 #define BE      0x55
517
518 #define CONT_PAUSE_8    PA, PA, PA, PA, PA, PA, PA, PA
519 #define CONT_PAUSE_16   CONT_PAUSE_8, CONT_PAUSE_8
520 #define CONT_PAUSE_24   CONT_PAUSE_16, CONT_PAUSE_8
521
522 #define CONT_BEEP_8     BE, BE, BE, BE, BE, BE, BE, BE
523
524 #if AO_RADIO_CONT_PAUSE_LEN == 24
525 #define CONT_PAUSE      CONT_PAUSE_24
526 #endif
527
528 #if AO_RADIO_CONT_TONE_LEN == 8
529 #define CONT_BEEP               CONT_BEEP_8
530 #define CONT_PAUSE_SHORT        CONT_PAUSE_8
531 #endif
532
533 #define CONT_ADDR(c)    CODE_TO_XDATA(&ao_radio_cont[(3-(c)) * (AO_RADIO_CONT_PAUSE_LEN + AO_RADIO_CONT_TONE_LEN)])
534
535 __code uint8_t ao_radio_cont[] = {
536         CONT_PAUSE, CONT_BEEP,
537         CONT_PAUSE, CONT_BEEP,
538         CONT_PAUSE, CONT_BEEP,
539         CONT_PAUSE, CONT_PAUSE_SHORT,
540         CONT_PAUSE, CONT_PAUSE_SHORT,
541         CONT_PAUSE,
542 };
543
544 void
545 ao_radio_continuity(uint8_t c)
546 {
547         ao_radio_rdf_start();
548         ao_dma_set_transfer(ao_radio_dma,
549                             CONT_ADDR(c),
550                             &RFDXADDR,
551                             AO_RADIO_CONT_TOTAL_LEN,
552                             DMA_CFG0_WORDSIZE_8 |
553                             DMA_CFG0_TMODE_SINGLE |
554                             DMA_CFG0_TRIGGER_RADIO,
555                             DMA_CFG1_SRCINC_1 |
556                             DMA_CFG1_DESTINC_0 |
557                             DMA_CFG1_PRIORITY_HIGH);
558         ao_radio_rdf_run();
559 }
560
561 void
562 ao_radio_rdf_abort(void)
563 {
564         ao_radio_abort = 1;
565         ao_wakeup(&ao_radio_done);
566 }
567
568
569 /* Output carrier */
570
571 static __xdata  ao_radio_test_on;
572
573 void
574 ao_radio_test(uint8_t on)
575 {
576         if (on) {
577                 if (!ao_radio_test_on) {
578 #if HAS_MONITOR
579                         ao_monitor_disable();
580 #endif
581 #if PACKET_HAS_SLAVE
582                         ao_packet_slave_stop();
583 #endif
584 #if HAS_PAD
585                         ao_pad_disable();
586 #endif
587                         ao_radio_get(0xff);
588                         RFST = RFST_STX;
589                         ao_radio_test_on = 1;
590                 }
591         } else  {
592                 if (ao_radio_test_on) {
593                         ao_radio_idle();
594                         ao_radio_put();
595                         ao_radio_test_on = 0;
596 #if HAS_MONITOR
597                         ao_monitor_enable();
598 #endif
599 #if HAS_PAD
600                         ao_pad_enable();
601 #endif
602                 }
603         }
604 }
605
606 static void
607 ao_radio_test_cmd(void)
608 {
609         uint8_t mode = 2;
610         static __xdata radio_on;
611         ao_cmd_white();
612         if (ao_cmd_lex_c != '\n') {
613                 ao_cmd_decimal();
614                 mode = (uint8_t) ao_cmd_lex_u32;
615         }
616         mode++;
617         if ((mode & 2))
618                 ao_radio_test(1);
619         if (mode == 3) {
620                 printf ("Hit a character to stop..."); flush();
621                 getchar();
622                 putchar('\n');
623         }
624         if ((mode & 1))
625                 ao_radio_test(0);
626 }
627
628 #if AO_RADIO_REG_TEST
629 static void
630 ao_radio_set_reg(void)
631 {
632         uint8_t offset;
633         ao_cmd_hex();
634         offset = ao_cmd_lex_i;
635         if (ao_cmd_status != ao_cmd_success)
636                 return;
637         ao_cmd_hex();
638         printf("RF[%x] %x", offset, RF[offset]);
639         if (ao_cmd_status == ao_cmd_success) {
640                 RF[offset] = ao_cmd_lex_i;
641                 printf (" -> %x", RF[offset]);
642         }
643         ao_cmd_status = ao_cmd_success;
644         printf("\n");
645 }
646 #endif
647
648 __code struct ao_cmds ao_radio_cmds[] = {
649         { ao_radio_test_cmd,    "C <1 start, 0 stop, none both>\0Radio carrier test" },
650 #if AO_RADIO_REG_TEST
651         { ao_radio_set_reg,     "V <offset> <value>\0Set radio register" },
652 #endif
653         { 0,    NULL },
654 };
655
656 void
657 ao_radio_init(void)
658 {
659         uint8_t i;
660         for (i = 0; i < sizeof (radio_setup); i += 2)
661                 RF[radio_setup[i]] = radio_setup[i+1];
662         ao_radio_set_packet();
663         ao_radio_dma_done = 1;
664         ao_radio_dma = ao_dma_alloc(&ao_radio_dma_done);
665         RFIF = 0;
666         RFIM = RFIM_IM_TIMEOUT|RFIM_IM_DONE;
667         IEN2 |= IEN2_RFIE;
668         ao_cmd_register(&ao_radio_cmds[0]);
669 }