]> git.gag.com Git - fw/altos/blob - src/cc1111/ao_radio.c
Merge remote-tracking branch 'origin/master'
[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_OFF |
130                                  RF_MDMCFG2_MOD_FORMAT_GFSK |
131                                  RF_MDMCFG2_SYNC_MODE_15_16_THRES),
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,           0x88,
159         RF_TEST1_OFF,           0x31,
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,        0x03,
191         RF_AGCCTRL1_OFF,        0x40,
192         RF_AGCCTRL0_OFF,        0x91,
193
194         RF_IOCFG2_OFF,          0x00,
195         RF_IOCFG1_OFF,          0x00,
196         RF_IOCFG0_OFF,          0x00,
197 };
198
199 static __code uint8_t rdf_setup[] = {
200         RF_MDMCFG4_OFF,         ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
201                                  (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) |
202                                  (RDF_DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)),
203         RF_MDMCFG3_OFF,         (RDF_DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT),
204         RF_MDMCFG2_OFF,         (RF_MDMCFG2_DEM_DCFILT_OFF |
205                                  RF_MDMCFG2_MOD_FORMAT_GFSK |
206                                  RF_MDMCFG2_SYNC_MODE_NONE),
207         RF_MDMCFG1_OFF,         (RF_MDMCFG1_FEC_DIS |
208                                  RF_MDMCFG1_NUM_PREAMBLE_2 |
209                                  (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)),
210
211         RF_DEVIATN_OFF,         ((RDF_DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) |
212                                  (RDF_DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)),
213
214         /* packet length is set in-line */
215         RF_PKTCTRL1_OFF,        ((1 << PKTCTRL1_PQT_SHIFT)|
216                                  PKTCTRL1_ADR_CHK_NONE),
217         RF_PKTCTRL0_OFF,        (RF_PKTCTRL0_PKT_FORMAT_NORMAL|
218                                  RF_PKTCTRL0_LENGTH_CONFIG_FIXED),
219 };
220
221 static __code uint8_t fixed_pkt_setup[] = {
222         RF_MDMCFG4_OFF,         ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
223                                  (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) |
224                                  (DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)),
225         RF_MDMCFG3_OFF,         (DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT),
226         RF_MDMCFG2_OFF,         (RF_MDMCFG2_DEM_DCFILT_OFF |
227                                  RF_MDMCFG2_MOD_FORMAT_GFSK |
228                                  RF_MDMCFG2_SYNC_MODE_15_16_THRES),
229         RF_MDMCFG1_OFF,         (RF_MDMCFG1_FEC_EN |
230                                  RF_MDMCFG1_NUM_PREAMBLE_4 |
231                                  (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)),
232
233         RF_DEVIATN_OFF,         ((DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) |
234                                  (DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)),
235
236         /* max packet length -- now set inline */
237         RF_PKTCTRL1_OFF,        ((1 << PKTCTRL1_PQT_SHIFT)|
238                                  PKTCTRL1_APPEND_STATUS|
239                                  PKTCTRL1_ADR_CHK_NONE),
240         RF_PKTCTRL0_OFF,        (RF_PKTCTRL0_WHITE_DATA|
241                                  RF_PKTCTRL0_PKT_FORMAT_NORMAL|
242                                  RF_PKTCTRL0_CRC_EN|
243                                  RF_PKTCTRL0_LENGTH_CONFIG_FIXED),
244 };
245
246 __xdata uint8_t ao_radio_dma;
247 __xdata uint8_t ao_radio_dma_done;
248 __xdata uint8_t ao_radio_done;
249 __xdata uint8_t ao_radio_abort;
250 __xdata uint8_t ao_radio_mutex;
251
252 #if PACKET_HAS_MASTER || HAS_AES
253 #define NEED_RADIO_RSSI 1
254 #endif
255
256 #ifndef NEED_RADIO_RSSI
257 #define NEED_RADIO_RSSI 0
258 #endif
259
260 #if NEED_RADIO_RSSI
261 __xdata int8_t ao_radio_rssi;
262 #endif
263
264 void
265 ao_radio_general_isr(void) __interrupt 16
266 {
267         S1CON &= ~0x03;
268         if (RFIF & RFIF_IM_TIMEOUT) {
269                 ao_radio_recv_abort();
270                 RFIF &= ~ RFIF_IM_TIMEOUT;
271         } else if (RFIF & RFIF_IM_DONE) {
272                 ao_radio_done = 1;
273                 ao_wakeup(&ao_radio_done);
274                 RFIF &= ~RFIF_IM_DONE;
275         }
276 }
277
278 static void
279 ao_radio_set_packet(void)
280 {
281         uint8_t i;
282         for (i = 0; i < sizeof (fixed_pkt_setup); i += 2)
283                 RF[fixed_pkt_setup[i]] = fixed_pkt_setup[i+1];
284 }
285
286 static void
287 ao_radio_idle(void)
288 {
289         if (RF_MARCSTATE != RF_MARCSTATE_IDLE)
290         {
291                 do {
292                         RFST = RFST_SIDLE;
293                         ao_yield();
294                 } while (RF_MARCSTATE != RF_MARCSTATE_IDLE);
295         }
296 }
297
298 #define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
299
300 static void
301 ao_radio_get(uint8_t len)
302 {
303         ao_config_get();
304         ao_mutex_get(&ao_radio_mutex);
305         ao_radio_idle();
306         RF_CHANNR = 0;
307         RF_FREQ2 = (uint8_t) (ao_config.radio_setting >> 16);
308         RF_FREQ1 = (uint8_t) (ao_config.radio_setting >> 8);
309         RF_FREQ0 = (uint8_t) (ao_config.radio_setting);
310         RF_PKTLEN = len;
311 }
312
313
314 void
315 ao_radio_send(__xdata void *packet, uint8_t size) __reentrant
316 {
317         ao_radio_get(size);
318         ao_radio_done = 0;
319         ao_dma_set_transfer(ao_radio_dma,
320                             packet,
321                             &RFDXADDR,
322                             size,
323                             DMA_CFG0_WORDSIZE_8 |
324                             DMA_CFG0_TMODE_SINGLE |
325                             DMA_CFG0_TRIGGER_RADIO,
326                             DMA_CFG1_SRCINC_1 |
327                             DMA_CFG1_DESTINC_0 |
328                             DMA_CFG1_PRIORITY_HIGH);
329         ao_dma_start(ao_radio_dma);
330         RFST = RFST_STX;
331         __critical while (!ao_radio_done)
332                 ao_sleep(&ao_radio_done);
333         ao_radio_put();
334 }
335
336 uint8_t
337 ao_radio_recv(__xdata void *packet, uint8_t size, uint8_t timeout) __reentrant
338 {
339         ao_radio_abort = 0;
340         ao_radio_get(size - 2);
341         ao_dma_set_transfer(ao_radio_dma,
342                             &RFDXADDR,
343                             packet,
344                             size,
345                             DMA_CFG0_WORDSIZE_8 |
346                             DMA_CFG0_TMODE_SINGLE |
347                             DMA_CFG0_TRIGGER_RADIO,
348                             DMA_CFG1_SRCINC_0 |
349                             DMA_CFG1_DESTINC_1 |
350                             DMA_CFG1_PRIORITY_HIGH);
351         ao_dma_start(ao_radio_dma);
352         RFST = RFST_SRX;
353
354         /* Wait for DMA to be done, for the radio receive process to
355          * get aborted or for a receive timeout to fire
356          */
357         if (timeout)
358                 ao_alarm(timeout);
359         __critical while (!ao_radio_dma_done && !ao_radio_abort)
360                            if (ao_sleep(&ao_radio_dma_done))
361                                    break;
362         if (timeout)
363                 ao_clear_alarm();
364
365         /* If recv was aborted, clean up by stopping the DMA engine
366          * and idling the radio
367          */
368         if (!ao_radio_dma_done) {
369                 ao_dma_abort(ao_radio_dma);
370                 ao_radio_idle();
371 #if NEED_RADIO_RSSI
372                 ao_radio_rssi = 0;
373 #endif
374         }
375 #if NEED_RADIO_RSSI
376         else
377                 ao_radio_rssi = AO_RSSI_FROM_RADIO(((uint8_t *)packet)[size - 2]);
378 #endif
379         ao_radio_put();
380         return ao_radio_dma_done;
381 }
382
383 /*
384  * Wake up a task waiting to receive a radio packet
385  * and tell them to abort the transfer
386  */
387
388 void
389 ao_radio_recv_abort(void)
390 {
391         ao_radio_abort = 1;
392         ao_wakeup(&ao_radio_dma_done);
393 }
394
395 __code ao_radio_rdf_value = 0x55;
396
397 static void
398 ao_radio_rdf_start(void)
399 {
400         uint8_t i;
401         ao_radio_abort = 0;
402         ao_radio_get(AO_RADIO_RDF_LEN);
403         ao_radio_done = 0;
404         for (i = 0; i < sizeof (rdf_setup); i += 2)
405                 RF[rdf_setup[i]] = rdf_setup[i+1];
406 }
407
408 static void
409 ao_radio_rdf_run(void)
410 {
411         ao_dma_start(ao_radio_dma);
412         RFST = RFST_STX;
413         __critical while (!ao_radio_done && !ao_radio_abort)
414                            ao_sleep(&ao_radio_done);
415         if (!ao_radio_done) {
416                 ao_dma_abort(ao_radio_dma);
417                 ao_radio_idle();
418         }
419         ao_radio_set_packet();
420         ao_radio_put();
421 }
422
423 void
424 ao_radio_rdf(void)
425 {
426         ao_radio_rdf_start();
427
428         ao_dma_set_transfer(ao_radio_dma,
429                             CODE_TO_XDATA(&ao_radio_rdf_value),
430                             &RFDXADDR,
431                             AO_RADIO_RDF_LEN,
432                             DMA_CFG0_WORDSIZE_8 |
433                             DMA_CFG0_TMODE_SINGLE |
434                             DMA_CFG0_TRIGGER_RADIO,
435                             DMA_CFG1_SRCINC_0 |
436                             DMA_CFG1_DESTINC_0 |
437                             DMA_CFG1_PRIORITY_HIGH);
438         ao_radio_rdf_run();
439 }
440
441 #define PA      0x00
442 #define BE      0x55
443
444 #define CONT_PAUSE_8    PA, PA, PA, PA, PA, PA, PA, PA
445 #define CONT_PAUSE_16   CONT_PAUSE_8, CONT_PAUSE_8
446 #define CONT_PAUSE_24   CONT_PAUSE_16, CONT_PAUSE_8
447
448 #define CONT_BEEP_8     BE, BE, BE, BE, BE, BE, BE, BE
449
450 #if AO_RADIO_CONT_PAUSE_LEN == 24
451 #define CONT_PAUSE      CONT_PAUSE_24
452 #endif
453
454 #if AO_RADIO_CONT_TONE_LEN == 8
455 #define CONT_BEEP               CONT_BEEP_8
456 #define CONT_PAUSE_SHORT        CONT_PAUSE_8
457 #endif
458
459 #define CONT_ADDR(c)    CODE_TO_XDATA(&ao_radio_cont[(3-(c)) * (AO_RADIO_CONT_PAUSE_LEN + AO_RADIO_CONT_TONE_LEN)])
460
461 __code uint8_t ao_radio_cont[] = {
462         CONT_PAUSE, CONT_BEEP,
463         CONT_PAUSE, CONT_BEEP,
464         CONT_PAUSE, CONT_BEEP,
465         CONT_PAUSE, CONT_PAUSE_SHORT,
466         CONT_PAUSE, CONT_PAUSE_SHORT,
467         CONT_PAUSE,
468 };
469
470 void
471 ao_radio_continuity(uint8_t c)
472 {
473         ao_radio_rdf_start();
474         ao_dma_set_transfer(ao_radio_dma,
475                             CONT_ADDR(c),
476                             &RFDXADDR,
477                             AO_RADIO_CONT_TOTAL_LEN,
478                             DMA_CFG0_WORDSIZE_8 |
479                             DMA_CFG0_TMODE_SINGLE |
480                             DMA_CFG0_TRIGGER_RADIO,
481                             DMA_CFG1_SRCINC_1 |
482                             DMA_CFG1_DESTINC_0 |
483                             DMA_CFG1_PRIORITY_HIGH);
484         ao_radio_rdf_run();
485 }
486
487 void
488 ao_radio_rdf_abort(void)
489 {
490         ao_radio_abort = 1;
491         ao_wakeup(&ao_radio_done);
492 }
493
494
495 /* Output carrier */
496
497 static __xdata  ao_radio_test_on;
498
499 void
500 ao_radio_test(uint8_t on)
501 {
502         if (on) {
503                 if (!ao_radio_test_on) {
504 #if HAS_MONITOR
505                         ao_monitor_disable();
506 #endif
507 #if PACKET_HAS_SLAVE
508                         ao_packet_slave_stop();
509 #endif
510 #if HAS_PAD
511                         ao_pad_disable();
512 #endif
513                         ao_radio_get(0xff);
514                         RFST = RFST_STX;
515                         ao_radio_test_on = 1;
516                 }
517         } else  {
518                 if (ao_radio_test_on) {
519                         ao_radio_idle();
520                         ao_radio_put();
521                         ao_radio_test_on = 0;
522 #if HAS_MONITOR
523                         ao_monitor_enable();
524 #endif
525 #if HAS_PAD
526                         ao_pad_enable();
527 #endif
528                 }
529         }
530 }
531
532 static void
533 ao_radio_test_cmd(void)
534 {
535         uint8_t mode = 2;
536         static __xdata radio_on;
537         ao_cmd_white();
538         if (ao_cmd_lex_c != '\n') {
539                 ao_cmd_decimal();
540                 mode = (uint8_t) ao_cmd_lex_u32;
541         }
542         mode++;
543         if ((mode & 2))
544                 ao_radio_test(1);
545         if (mode == 3) {
546                 printf ("Hit a character to stop..."); flush();
547                 getchar();
548                 putchar('\n');
549         }
550         if ((mode & 1))
551                 ao_radio_test(0);
552 }
553
554 __code struct ao_cmds ao_radio_cmds[] = {
555         { ao_radio_test_cmd,    "C <1 start, 0 stop, none both>\0Radio carrier test" },
556         { 0,    NULL },
557 };
558
559 void
560 ao_radio_init(void)
561 {
562         uint8_t i;
563         for (i = 0; i < sizeof (radio_setup); i += 2)
564                 RF[radio_setup[i]] = radio_setup[i+1];
565         ao_radio_set_packet();
566         ao_radio_dma_done = 1;
567         ao_radio_dma = ao_dma_alloc(&ao_radio_dma_done);
568         RFIF = 0;
569         RFIM = RFIM_IM_TIMEOUT|RFIM_IM_DONE;
570         IEN2 |= IEN2_RFIE;
571         ao_cmd_register(&ao_radio_cmds[0]);
572 }