altos: Provide timeout value to ao_radio_recv
[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,        0x43,
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 void
253 ao_radio_general_isr(void) __interrupt 16
254 {
255         S1CON &= ~0x03;
256         if (RFIF & RFIF_IM_TIMEOUT) {
257                 ao_radio_recv_abort();
258                 RFIF &= ~ RFIF_IM_TIMEOUT;
259         } else if (RFIF & RFIF_IM_DONE) {
260                 ao_radio_done = 1;
261                 ao_wakeup(&ao_radio_done);
262                 RFIF &= ~RFIF_IM_DONE;
263         }
264 }
265
266 static void
267 ao_radio_set_packet(void)
268 {
269         uint8_t i;
270         for (i = 0; i < sizeof (fixed_pkt_setup); i += 2)
271                 RF[fixed_pkt_setup[i]] = fixed_pkt_setup[i+1];
272 }
273
274 static void
275 ao_radio_idle(void)
276 {
277         if (RF_MARCSTATE != RF_MARCSTATE_IDLE)
278         {
279                 do {
280                         RFST = RFST_SIDLE;
281                         ao_yield();
282                 } while (RF_MARCSTATE != RF_MARCSTATE_IDLE);
283         }
284 }
285
286 #define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
287
288 static void
289 ao_radio_get(uint8_t len)
290 {
291         ao_config_get();
292         ao_mutex_get(&ao_radio_mutex);
293         ao_radio_idle();
294         RF_CHANNR = 0;
295         RF_FREQ2 = (uint8_t) (ao_config.radio_setting >> 16);
296         RF_FREQ1 = (uint8_t) (ao_config.radio_setting >> 8);
297         RF_FREQ0 = (uint8_t) (ao_config.radio_setting);
298         RF_PKTLEN = len;
299 }
300
301
302 void
303 ao_radio_send(__xdata void *packet, uint8_t size) __reentrant
304 {
305         ao_radio_get(size);
306         ao_radio_done = 0;
307         ao_dma_set_transfer(ao_radio_dma,
308                             packet,
309                             &RFDXADDR,
310                             size,
311                             DMA_CFG0_WORDSIZE_8 |
312                             DMA_CFG0_TMODE_SINGLE |
313                             DMA_CFG0_TRIGGER_RADIO,
314                             DMA_CFG1_SRCINC_1 |
315                             DMA_CFG1_DESTINC_0 |
316                             DMA_CFG1_PRIORITY_HIGH);
317         ao_dma_start(ao_radio_dma);
318         RFST = RFST_STX;
319         __critical while (!ao_radio_done)
320                 ao_sleep(&ao_radio_done);
321         ao_radio_put();
322 }
323
324 uint8_t
325 ao_radio_recv(__xdata void *packet, uint8_t size, uint8_t timeout) __reentrant
326 {
327         ao_radio_abort = 0;
328         ao_radio_get(size - 2);
329         ao_dma_set_transfer(ao_radio_dma,
330                             &RFDXADDR,
331                             packet,
332                             size,
333                             DMA_CFG0_WORDSIZE_8 |
334                             DMA_CFG0_TMODE_SINGLE |
335                             DMA_CFG0_TRIGGER_RADIO,
336                             DMA_CFG1_SRCINC_0 |
337                             DMA_CFG1_DESTINC_1 |
338                             DMA_CFG1_PRIORITY_HIGH);
339         ao_dma_start(ao_radio_dma);
340         RFST = RFST_SRX;
341
342         /* Wait for DMA to be done, for the radio receive process to
343          * get aborted or for a receive timeout to fire
344          */
345         if (timeout)
346                 ao_alarm(timeout);
347         __critical while (!ao_radio_dma_done && !ao_radio_abort)
348                            if (ao_sleep(&ao_radio_dma_done))
349                                    break;
350         if (timeout)
351                 ao_clear_alarm();
352
353         /* If recv was aborted, clean up by stopping the DMA engine
354          * and idling the radio
355          */
356         if (!ao_radio_dma_done) {
357                 ao_dma_abort(ao_radio_dma);
358                 ao_radio_idle();
359         }
360         ao_radio_put();
361         return ao_radio_dma_done;
362 }
363
364 /*
365  * Wake up a task waiting to receive a radio packet
366  * and tell them to abort the transfer
367  */
368
369 void
370 ao_radio_recv_abort(void)
371 {
372         ao_radio_abort = 1;
373         ao_wakeup(&ao_radio_dma_done);
374 }
375
376 __code ao_radio_rdf_value = 0x55;
377
378 static void
379 ao_radio_rdf_start(void)
380 {
381         uint8_t i;
382         ao_radio_abort = 0;
383         ao_radio_get(AO_RADIO_RDF_LEN);
384         ao_radio_done = 0;
385         for (i = 0; i < sizeof (rdf_setup); i += 2)
386                 RF[rdf_setup[i]] = rdf_setup[i+1];
387 }
388
389 static void
390 ao_radio_rdf_run(void)
391 {
392         ao_dma_start(ao_radio_dma);
393         RFST = RFST_STX;
394         __critical while (!ao_radio_done && !ao_radio_abort)
395                            ao_sleep(&ao_radio_done);
396         if (!ao_radio_done) {
397                 ao_dma_abort(ao_radio_dma);
398                 ao_radio_idle();
399         }
400         ao_radio_set_packet();
401         ao_radio_put();
402 }
403
404 void
405 ao_radio_rdf(void)
406 {
407         ao_radio_rdf_start();
408
409         ao_dma_set_transfer(ao_radio_dma,
410                             CODE_TO_XDATA(&ao_radio_rdf_value),
411                             &RFDXADDR,
412                             AO_RADIO_RDF_LEN,
413                             DMA_CFG0_WORDSIZE_8 |
414                             DMA_CFG0_TMODE_SINGLE |
415                             DMA_CFG0_TRIGGER_RADIO,
416                             DMA_CFG1_SRCINC_0 |
417                             DMA_CFG1_DESTINC_0 |
418                             DMA_CFG1_PRIORITY_HIGH);
419         ao_radio_rdf_run();
420 }
421
422 #define PA      0x00
423 #define BE      0x55
424
425 #define CONT_PAUSE_8    PA, PA, PA, PA, PA, PA, PA, PA
426 #define CONT_PAUSE_16   CONT_PAUSE_8, CONT_PAUSE_8
427 #define CONT_PAUSE_24   CONT_PAUSE_16, CONT_PAUSE_8
428
429 #define CONT_BEEP_8     BE, BE, BE, BE, BE, BE, BE, BE
430
431 #if AO_RADIO_CONT_PAUSE_LEN == 24
432 #define CONT_PAUSE      CONT_PAUSE_24
433 #endif
434
435 #if AO_RADIO_CONT_TONE_LEN == 8
436 #define CONT_BEEP               CONT_BEEP_8
437 #define CONT_PAUSE_SHORT        CONT_PAUSE_8
438 #endif
439
440 #define CONT_ADDR(c)    CODE_TO_XDATA(&ao_radio_cont[(3-(c)) * (AO_RADIO_CONT_PAUSE_LEN + AO_RADIO_CONT_TONE_LEN)])
441
442 __code uint8_t ao_radio_cont[] = {
443         CONT_PAUSE, CONT_BEEP,
444         CONT_PAUSE, CONT_BEEP,
445         CONT_PAUSE, CONT_BEEP,
446         CONT_PAUSE, CONT_PAUSE_SHORT,
447         CONT_PAUSE, CONT_PAUSE_SHORT,
448         CONT_PAUSE,
449 };
450
451 void
452 ao_radio_continuity(uint8_t c)
453 {
454         ao_radio_rdf_start();
455         ao_dma_set_transfer(ao_radio_dma,
456                             CONT_ADDR(c),
457                             &RFDXADDR,
458                             AO_RADIO_CONT_TOTAL_LEN,
459                             DMA_CFG0_WORDSIZE_8 |
460                             DMA_CFG0_TMODE_SINGLE |
461                             DMA_CFG0_TRIGGER_RADIO,
462                             DMA_CFG1_SRCINC_1 |
463                             DMA_CFG1_DESTINC_0 |
464                             DMA_CFG1_PRIORITY_HIGH);
465         ao_radio_rdf_run();
466 }
467
468 void
469 ao_radio_rdf_abort(void)
470 {
471         ao_radio_abort = 1;
472         ao_wakeup(&ao_radio_done);
473 }
474
475
476 /* Output carrier */
477
478 static __xdata  ao_radio_test_on;
479
480 void
481 ao_radio_test(uint8_t on)
482 {
483         if (on) {
484                 if (!ao_radio_test_on) {
485 #if HAS_MONITOR
486                         ao_monitor_disable();
487 #endif
488 #if PACKET_HAS_SLAVE
489                         ao_packet_slave_stop();
490 #endif
491 #if HAS_PAD
492                         ao_pad_disable();
493 #endif
494                         ao_radio_get(0xff);
495                         RFST = RFST_STX;
496                         ao_radio_test_on = 1;
497                 }
498         } else  {
499                 if (ao_radio_test_on) {
500                         ao_radio_idle();
501                         ao_radio_put();
502                         ao_radio_test_on = 0;
503 #if HAS_MONITOR
504                         ao_monitor_enable();
505 #endif
506 #if HAS_PAD
507                         ao_pad_enable();
508 #endif
509                 }
510         }
511 }
512
513 static void
514 ao_radio_test_cmd(void)
515 {
516         uint8_t mode = 2;
517         static __xdata radio_on;
518         ao_cmd_white();
519         if (ao_cmd_lex_c != '\n') {
520                 ao_cmd_decimal();
521                 mode = (uint8_t) ao_cmd_lex_u32;
522         }
523         mode++;
524         if ((mode & 2))
525                 ao_radio_test(1);
526         if (mode == 3) {
527                 printf ("Hit a character to stop..."); flush();
528                 getchar();
529                 putchar('\n');
530         }
531         if ((mode & 1))
532                 ao_radio_test(0);
533 }
534
535 __code struct ao_cmds ao_radio_cmds[] = {
536         { ao_radio_test_cmd,    "C <1 start, 0 stop, none both>\0Radio carrier test" },
537         { 0,    NULL },
538 };
539
540 void
541 ao_radio_init(void)
542 {
543         uint8_t i;
544         for (i = 0; i < sizeof (radio_setup); i += 2)
545                 RF[radio_setup[i]] = radio_setup[i+1];
546         ao_radio_set_packet();
547         ao_radio_dma_done = 1;
548         ao_radio_dma = ao_dma_alloc(&ao_radio_dma_done);
549         RFIF = 0;
550         RFIM = RFIM_IM_TIMEOUT|RFIM_IM_DONE;
551         IEN2 |= IEN2_RFIE;
552         ao_cmd_register(&ao_radio_cmds[0]);
553 }