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