altos: Need to use 16-bit counts for ao_xmem functions
[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) __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         __critical while (!ao_radio_dma_done && !ao_radio_abort)
346                            if (ao_sleep(&ao_radio_dma_done))
347                                    break;
348
349         /* If recv was aborted, clean up by stopping the DMA engine
350          * and idling the radio
351          */
352         if (!ao_radio_dma_done) {
353                 ao_dma_abort(ao_radio_dma);
354                 ao_radio_idle();
355         }
356         ao_radio_put();
357         return ao_radio_dma_done;
358 }
359
360 /*
361  * Wake up a task waiting to receive a radio packet
362  * and tell them to abort the transfer
363  */
364
365 void
366 ao_radio_recv_abort(void)
367 {
368         ao_radio_abort = 1;
369         ao_wakeup(&ao_radio_dma_done);
370 }
371
372 __code ao_radio_rdf_value = 0x55;
373
374 static void
375 ao_radio_rdf_start(void)
376 {
377         uint8_t i;
378         ao_radio_abort = 0;
379         ao_radio_get(AO_RADIO_RDF_LEN);
380         ao_radio_done = 0;
381         for (i = 0; i < sizeof (rdf_setup); i += 2)
382                 RF[rdf_setup[i]] = rdf_setup[i+1];
383 }
384
385 static void
386 ao_radio_rdf_run(void)
387 {
388         ao_dma_start(ao_radio_dma);
389         RFST = RFST_STX;
390         __critical while (!ao_radio_done && !ao_radio_abort)
391                            ao_sleep(&ao_radio_done);
392         if (!ao_radio_done) {
393                 ao_dma_abort(ao_radio_dma);
394                 ao_radio_idle();
395         }
396         ao_radio_set_packet();
397         ao_radio_put();
398 }
399
400 void
401 ao_radio_rdf(void)
402 {
403         ao_radio_rdf_start();
404
405         ao_dma_set_transfer(ao_radio_dma,
406                             CODE_TO_XDATA(&ao_radio_rdf_value),
407                             &RFDXADDR,
408                             AO_RADIO_RDF_LEN,
409                             DMA_CFG0_WORDSIZE_8 |
410                             DMA_CFG0_TMODE_SINGLE |
411                             DMA_CFG0_TRIGGER_RADIO,
412                             DMA_CFG1_SRCINC_0 |
413                             DMA_CFG1_DESTINC_0 |
414                             DMA_CFG1_PRIORITY_HIGH);
415         ao_radio_rdf_run();
416 }
417
418 #define PA      0x00
419 #define BE      0x55
420
421 #define CONT_PAUSE_8    PA, PA, PA, PA, PA, PA, PA, PA
422 #define CONT_PAUSE_16   CONT_PAUSE_8, CONT_PAUSE_8
423 #define CONT_PAUSE_24   CONT_PAUSE_16, CONT_PAUSE_8
424
425 #define CONT_BEEP_8     BE, BE, BE, BE, BE, BE, BE, BE
426
427 #if AO_RADIO_CONT_PAUSE_LEN == 24
428 #define CONT_PAUSE      CONT_PAUSE_24
429 #endif
430
431 #if AO_RADIO_CONT_TONE_LEN == 8
432 #define CONT_BEEP               CONT_BEEP_8
433 #define CONT_PAUSE_SHORT        CONT_PAUSE_8
434 #endif
435
436 #define CONT_ADDR(c)    CODE_TO_XDATA(&ao_radio_cont[(3-(c)) * (AO_RADIO_CONT_PAUSE_LEN + AO_RADIO_CONT_TONE_LEN)])
437
438 __code uint8_t ao_radio_cont[] = {
439         CONT_PAUSE, CONT_BEEP,
440         CONT_PAUSE, CONT_BEEP,
441         CONT_PAUSE, CONT_BEEP,
442         CONT_PAUSE, CONT_PAUSE_SHORT,
443         CONT_PAUSE, CONT_PAUSE_SHORT,
444         CONT_PAUSE,
445 };
446
447 void
448 ao_radio_continuity(uint8_t c)
449 {
450         ao_radio_rdf_start();
451         ao_dma_set_transfer(ao_radio_dma,
452                             CONT_ADDR(c),
453                             &RFDXADDR,
454                             AO_RADIO_CONT_TOTAL_LEN,
455                             DMA_CFG0_WORDSIZE_8 |
456                             DMA_CFG0_TMODE_SINGLE |
457                             DMA_CFG0_TRIGGER_RADIO,
458                             DMA_CFG1_SRCINC_1 |
459                             DMA_CFG1_DESTINC_0 |
460                             DMA_CFG1_PRIORITY_HIGH);
461         ao_radio_rdf_run();
462 }
463
464 void
465 ao_radio_rdf_abort(void)
466 {
467         ao_radio_abort = 1;
468         ao_wakeup(&ao_radio_done);
469 }
470
471
472 /* Output carrier */
473
474 static __xdata  ao_radio_test_on;
475
476 void
477 ao_radio_test(uint8_t on)
478 {
479         if (on) {
480                 if (!ao_radio_test_on) {
481 #if HAS_MONITOR
482                         ao_monitor_disable();
483 #endif
484 #if PACKET_HAS_SLAVE
485                         ao_packet_slave_stop();
486 #endif
487 #if HAS_PAD
488                         ao_pad_disable();
489 #endif
490                         ao_radio_get(0xff);
491                         RFST = RFST_STX;
492                         ao_radio_test_on = 1;
493                 }
494         } else  {
495                 if (ao_radio_test_on) {
496                         ao_radio_idle();
497                         ao_radio_put();
498                         ao_radio_test_on = 0;
499 #if HAS_MONITOR
500                         ao_monitor_enable();
501 #endif
502 #if HAS_PAD
503                         ao_pad_enable();
504 #endif
505                 }
506         }
507 }
508
509 static void
510 ao_radio_test_cmd(void)
511 {
512         uint8_t mode = 2;
513         static __xdata radio_on;
514         ao_cmd_white();
515         if (ao_cmd_lex_c != '\n') {
516                 ao_cmd_decimal();
517                 mode = (uint8_t) ao_cmd_lex_u32;
518         }
519         mode++;
520         if ((mode & 2))
521                 ao_radio_test(1);
522         if (mode == 3) {
523                 printf ("Hit a character to stop..."); flush();
524                 getchar();
525                 putchar('\n');
526         }
527         if ((mode & 1))
528                 ao_radio_test(0);
529 }
530
531 __code struct ao_cmds ao_radio_cmds[] = {
532         { ao_radio_test_cmd,    "C <1 start, 0 stop, none both>\0Radio carrier test" },
533         { 0,    NULL },
534 };
535
536 void
537 ao_radio_init(void)
538 {
539         uint8_t i;
540         for (i = 0; i < sizeof (radio_setup); i += 2)
541                 RF[radio_setup[i]] = radio_setup[i+1];
542         ao_radio_set_packet();
543         ao_radio_dma_done = 1;
544         ao_radio_dma = ao_dma_alloc(&ao_radio_dma_done);
545         RFIF = 0;
546         RFIM = RFIM_IM_TIMEOUT|RFIM_IM_DONE;
547         IEN2 |= IEN2_RFIE;
548         ao_cmd_register(&ao_radio_cmds[0]);
549 }