Subversion Repositories HomeAutomation

Rev

Rev 2198 | Details | Compare with Previous | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
1465 arune 1
/**
2
 * IR receiver and transmitter driver.
3
 *
4
 * @date    2006-12-10
5
 *
6
 * @author  Anders Runeson, Andreas Fritiofson
7
 *  
8
 */
9
 
10
/*-----------------------------------------------------------------------------
11
 * Includes
12
 *---------------------------------------------------------------------------*/
13
#include <config.h>
1474 arune 14
#include <drivers/mcu/pcint.h>
1465 arune 15
#include <drivers/ir/transceiver/irtransceiverMulti.h>
16
#include <drivers/ir/protocols.h>
17
#include <avr/io.h>
18
#include <avr/interrupt.h>
19
 
1871 arune 20
 
1875 arune 21
//#include <drivers/mcu/gpio.h>
1871 arune 22
 
1465 arune 23
/*-----------------------------------------------------------------------------
24
 * Prerequisites
25
 *---------------------------------------------------------------------------*/
26
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__)
27
#define TIMSK1  TIMSK
28
#define TIFR1   TIFR
29
#define ICIE1   TICIE1
30
#endif
31
 
32
#define IR_COMPARE_VECTOR       TIMER1_COMPB_vect
33
#define IR_TIMEOUT_VECTOR       TIMER1_COMPA_vect
34
#define IR_CAPTURE_VECTOR       TIMER1_CAPT_vect
35
#define IR_TIMEOUT_REG          OCR1A
36
#define IR_COMPARE_REG          OCR1B
37
#define IR_CAPTURE_REG          ICR1
38
#define IR_COUNT_REG            TCNT1
39
#define IR_MODULATION_REG       OCR0A
40
/*#define IR_TIMER_INIT()           TCCR1A = 0; \
41
                                TCCR1B = (1<<ICNC1)|(2<<CS10);
42
                                */
43
#define IR_TIMER_INIT()         TCCR1A = 0; \
44
                                TCCR1B = (2<<CS10);
45
#define IR_MASK_COMPARE()       TIMSK1 &= ~(1<<OCIE1B);
46
#define IR_UNMASK_COMPARE()     TIFR1 = (1<<OCF1B); TIMSK1 |= (1<<OCIE1B);
47
#define IR_MASK_TIMEOUT()       TIMSK1 &= ~(1<<OCIE1A);
48
#define IR_UNMASK_TIMEOUT()     TIFR1 = (1<<OCF1A); TIMSK1 |= (1<<OCIE1A);
49
#define IR_MASK_CAPTURE()       TIMSK1 &= ~(1<<ICIE1);
50
#define IR_UNMASK_CAPTURE()     TIFR1 = (1<<ICF1); TIMSK1 |= (1<<ICIE1);
51
#define IR_CAPTURE_FALLING()    TCCR1B &= ~(1<<ICES1); \
52
                                TIFR1 = (1<<ICF1);
53
#define IR_CAPTURE_RISING()     TCCR1B |= (1<<ICES1); \
54
                                TIFR1 = (1<<ICF1);
55
 
1483 arune 56
//#define IR_OUTP_HIGH()            TCCR0A |= (1<<COM0A0);
57
//#define IR_OUTP_LOW()         TCCR0A &= ~(1<<COM0A0);
58
#if IR_TX_ACTIVE_LOW==1
59
#define IR_OUTP_HIGH()  *drvIrTxChannel[channel].port &= ~drvIrTxChannel[channel].pinmask
60
#define IR_OUTP_LOW()   *drvIrTxChannel[channel].port |= drvIrTxChannel[channel].pinmask
61
#else
62
#define IR_OUTP_HIGH()  *drvIrTxChannel[channel].port |= drvIrTxChannel[channel].pinmask
63
#define IR_OUTP_LOW()   *drvIrTxChannel[channel].port &= ~drvIrTxChannel[channel].pinmask
64
#endif
1465 arune 65
 
66
 
67
/*-----------------------------------------------------------------------------
1483 arune 68
 * Globals
69
 *---------------------------------------------------------------------------*/
70
#if IR_RX_ENABLE==1
71
struct {
72
    uint8_t     enable;
73
    uint16_t    timeout;
2198 arune 74
    uint16_t    *buf;
75
    uint8_t     len;
76
    uint8_t     index;
1483 arune 77
    uint8_t     storeEnable;
78
    irRxCallback_t callback;
79
} drvIrRxChannel[3];
80
#endif
81
 
82
#if IR_TX_ENABLE==1
83
struct {
84
    uint8_t     enable;
85
    uint16_t    timeout;
86
    uint8_t     timeoutEnable;
2198 arune 87
    uint16_t    *buf;
88
    uint8_t     len;
89
    uint8_t     index;
1483 arune 90
    irTxCallback_t callback;
91
    volatile uint8_t    *port;
92
    uint8_t     pinmask;
93
} drvIrTxChannel[3];
1865 myhrman 94
 
95
uint16_t drvIrTxModFreqkHz = 38; /* Default to 38kHz */
96
 
1483 arune 97
#endif
98
 
99
 
100
/*-----------------------------------------------------------------------------
1465 arune 101
 * Interrupt Handlers
102
 *---------------------------------------------------------------------------*/
1931 arune 103
 
104
 /* TRANSMIT */
1465 arune 105
#if IR_TX_ENABLE==1
106
ISR(IR_COMPARE_VECTOR)
107
{
1494 arune 108
    /* find which channel */
109
    uint16_t time = IR_COMPARE_REG;
110
    uint16_t diff;
111
    uint8_t channel;
1483 arune 112
 
1494 arune 113
    /* go through all channels and check which of thems have overflowed */
114
    for (channel=0; channel < IR_SUPPORTED_NUM_CHANNELS; channel++)
115
    {
116
        /* if channel is waiting for an overflow */
117
        if (drvIrTxChannel[channel].timeoutEnable==TRUE)
118
        {
119
            /* check if channel have overflowed or is about to overflow */
120
            diff = (time+50)-drvIrTxChannel[channel].timeout;
121
            if (diff < IR_MAX_PULSE_WIDTH)
122
            {
123
                /* check what to output next */
2198 arune 124
                if ((drvIrTxChannel[channel].index&1) == 1) {       /* if odd, ir-pause */
1494 arune 125
                    IR_OUTP_LOW();
126
                } else {
127
                    IR_OUTP_HIGH();
128
                }
129
 
130
                /* is there more to send */
2198 arune 131
                if (drvIrTxChannel[channel].index < drvIrTxChannel[channel].len)
1494 arune 132
                {
133
                    /* load next timeout value */
2198 arune 134
                    drvIrTxChannel[channel].timeout = IR_COMPARE_REG + drvIrTxChannel[channel].buf[drvIrTxChannel[channel].index++];
1494 arune 135
                }
136
                else
137
                {
138
                    /* disable this channel */
139
                    drvIrTxChannel[channel].timeoutEnable = FALSE;
140
 
141
                    /* disable the overflow interrupt */
142
                    IR_MASK_COMPARE();
143
 
144
                    /* notify the application that a pulse train has been sent. */
145
                    drvIrTxChannel[channel].callback(channel);
146
                }
147
            }
148
        }
1465 arune 149
    }
150
 
1494 arune 151
    channel = 0;
152
    diff = 0xffff;
153
    /* go through all channels and find the one that have the next overflow */
154
    for (uint8_t i=0; i < IR_SUPPORTED_NUM_CHANNELS; i++)
1483 arune 155
    {
1494 arune 156
        /* if channel is waiting for an overflow */
157
        if (drvIrTxChannel[i].timeoutEnable==TRUE)
158
        {
159
            if (drvIrTxChannel[i].timeout - time < diff)
160
            {
161
                diff = drvIrTxChannel[i].timeout - time;
162
                channel = i;
163
            }
164
            /* enable overflow interrupt */
165
            IR_UNMASK_COMPARE();
166
        }      
167
    }  
1483 arune 168
 
1494 arune 169
    /* set compare value to the channel that have the next overflow */
1483 arune 170
    IR_COMPARE_REG = drvIrTxChannel[channel].timeout;
1465 arune 171
}
172
#endif
173
 
1744 arune 174
 
1465 arune 175
#if IR_RX_ENABLE==1
1931 arune 176
/* RECEIVE */
1470 arune 177
/* When this timeout occurs a pulsetrain is complete */
1465 arune 178
ISR(IR_TIMEOUT_VECTOR)
179
{
1931 arune 180
#if IR_RX_CONTINUOUS_MODE==0
1851 myhrman 181
    for (uint8_t i=0; i < IR_SUPPORTED_NUM_CHANNELS; i++)
1465 arune 182
    {
1851 myhrman 183
        /* If more than 2 edges were recevied */
2198 arune 184
        if (drvIrRxChannel[i].storeEnable == TRUE && drvIrRxChannel[i].len > 2)
1470 arune 185
        {
1744 arune 186
            /* Notify the application that a pulse train has been received. */
2198 arune 187
            drvIrRxChannel[i].callback(i, drvIrRxChannel[i].buf, drvIrRxChannel[i].len, drvIrRxChannel[i].index);
1470 arune 188
        }
1744 arune 189
 
190
        drvIrRxChannel[i].storeEnable = FALSE;
1470 arune 191
    }
1465 arune 192
 
1744 arune 193
    /* Disable ISR */
1479 arune 194
    IR_MASK_TIMEOUT();
1931 arune 195
#endif
1470 arune 196
}
1465 arune 197
#endif
198
 
199
 
200
/*-----------------------------------------------------------------------------
201
 * Private Functions
202
 *---------------------------------------------------------------------------*/
203
 
204
#if IR_RX_ENABLE==1
1470 arune 205
 
206
/* these wrapper functions are called from the pcint driver (callback) */
1467 arune 207
void IrTransceiver_Store_ch0(uint8_t id, uint8_t status)
208
{
209
    IrTransceiver_Store(0);
210
}
211
void IrTransceiver_Store_ch1(uint8_t id, uint8_t status)
212
{
213
    IrTransceiver_Store(1);
214
}
215
void IrTransceiver_Store_ch2(uint8_t id, uint8_t status)
216
{
217
    IrTransceiver_Store(2);
218
}
219
 
1465 arune 220
void IrTransceiver_Store(uint8_t channel)
221
{
1479 arune 222
    static uint16_t prev_time[3];
1465 arune 223
    uint16_t pulsewidth;
224
 
225
    /* Read the timer counter register to get the current "time". */
226
    uint16_t time = IR_COUNT_REG;
227
 
1479 arune 228
    /* Subtract the current measurement from the previous to get the pulse width. */
229
    pulsewidth = time - prev_time[channel];
230
    prev_time[channel] = time;
231
 
1871 arune 232
#if IR_MIN_STARTPULSE_WIDTH>0
2198 arune 233
    if ((pulsewidth <= IR_MIN_STARTPULSE_WIDTH) && (drvIrRxChannel[channel].storeEnable == TRUE) && (drvIrRxChannel[channel].len == 0))
1871 arune 234
    {
235
        IR_MASK_TIMEOUT();
236
        return;
237
    }
238
    else
239
    {
240
        IR_UNMASK_TIMEOUT();
241
    }
242
#endif
243
 
2198 arune 244
#if IR_RX_CONTINUOUS_MODE==1
1931 arune 245
/* in continuous mode when short pulse arrives received len should be set to zero */
2198 arune 246
//TODO?
247
    if ((pulsewidth < (IR_MIN_PULSE_WIDTH*CYCLES_PER_US/TIMER_PRESC)) && (drvIrRxChannel[channel].storeEnable == TRUE))
1931 arune 248
    {
2198 arune 249
        drvIrRxChannel[channel].len = 0;
1931 arune 250
        return;
251
    }
252
    else
253
    {
254
    }
255
#endif
1875 arune 256
 
1479 arune 257
    if (drvIrRxChannel[channel].storeEnable)
1470 arune 258
    {
2199 arune 259
#if IR_RX_CONTINUOUS_MODE==0
1465 arune 260
        /* Store the measurement. */
2198 arune 261
        drvIrRxChannel[channel].buf[drvIrRxChannel[channel].len++] = pulsewidth;
1470 arune 262
 
1465 arune 263
        /* Disable future measurements if we've filled the buffer. */
264
        //TODO: Report overflow to application
2198 arune 265
        if (drvIrRxChannel[channel].len == MAX_NR_TIMES)
1465 arune 266
        {
2198 arune 267
            drvIrRxChannel[channel].len = MAX_NR_TIMES-1;
1465 arune 268
        }
1744 arune 269
        else
270
        {
271
            /* Set the timeout for detection of the end of the pulse train. */
2198 arune 272
            drvIrRxChannel[channel].timeout = time + (IR_MAX_PULSE_WIDTH*CYCLES_PER_US/TIMER_PRESC);
1744 arune 273
            IR_TIMEOUT_REG = drvIrRxChannel[channel].timeout;
2199 arune 274
        }
2198 arune 275
#else
2199 arune 276
        /* Store the measurement. */
277
        drvIrRxChannel[channel].buf[drvIrRxChannel[channel].index++] = pulsewidth;
278
 
279
        if (drvIrRxChannel[channel].index == MAX_NR_TIMES)
280
        {
281
            drvIrRxChannel[channel].index = 0;
282
        }
283
        if (drvIrRxChannel[channel].len++ == MAX_NR_TIMES)
284
        {
285
            drvIrRxChannel[channel].len = MAX_NR_TIMES-1;
286
        }
287
        /* Notify the application that a pulse has been received. */
288
        drvIrRxChannel[channel].callback(channel, drvIrRxChannel[channel].buf, drvIrRxChannel[channel].len, drvIrRxChannel[channel].index);
1931 arune 289
#endif
290
 
1465 arune 291
    }
1479 arune 292
    else if (drvIrRxChannel[channel].enable == TRUE)
1465 arune 293
    {
1479 arune 294
        /* The first edge of the pulse train has been detected. Enable the storage of the following pulsewidths. */
295
        drvIrRxChannel[channel].storeEnable = TRUE;
2198 arune 296
        drvIrRxChannel[channel].len = 0;
1479 arune 297
 
1931 arune 298
#if IR_RX_CONTINUOUS_MODE==0
1470 arune 299
        /* Enable timeout interrupt for detection of the end of the pulse train. */
2198 arune 300
        IR_TIMEOUT_REG = time + (IR_MAX_PULSE_WIDTH*CYCLES_PER_US/TIMER_PRESC);
1465 arune 301
        IR_UNMASK_TIMEOUT();
1931 arune 302
#endif
1465 arune 303
    }
304
}
305
#endif
306
 
307
 
308
/* call this function like this:
1730 arune 309
    IrTransceiver_InitRxChannel(channelnumber, buffer, callback, pcint-id, GPIO_D6);
1465 arune 310
    buffer is a memory location
311
    callback is a function to call when a receive/transmitt is complete
1479 arune 312
    also call with IO port to use  
1465 arune 313
*/
1467 arune 314
 
1470 arune 315
#if IR_RX_ENABLE==1
1483 arune 316
void IrTransceiver_InitRxChannel(uint8_t channel, uint16_t *buffer, irRxCallback_t callback, uint8_t pcint_id, volatile uint8_t* port, volatile uint8_t* pin, volatile uint8_t* ddr,uint8_t nr, uint8_t pcint)
1465 arune 317
{
1467 arune 318
    if (channel == 0)
319
    {
1474 arune 320
        Pcint_SetCallback(pcint_id, pcint, &IrTransceiver_Store_ch0);
1467 arune 321
    }
322
    else if (channel == 1)
323
    {
1474 arune 324
        Pcint_SetCallback(pcint_id, pcint, &IrTransceiver_Store_ch1);
1467 arune 325
    }
326
    else if (channel == 2)
327
    {
1474 arune 328
        Pcint_SetCallback(pcint_id, pcint, &IrTransceiver_Store_ch2);
1467 arune 329
    }
1470 arune 330
 
331
    if (channel < 3)
332
    {
333
        /* Set port direction to input */
334
        *ddr &= ~(1 << nr);
335
 
2198 arune 336
        drvIrRxChannel[channel].buf = buffer;
337
        drvIrRxChannel[channel].len = 0;
1479 arune 338
        drvIrRxChannel[channel].storeEnable = FALSE;
339
        drvIrRxChannel[channel].callback = callback;
340
        drvIrRxChannel[channel].enable = TRUE;
1470 arune 341
    }
1465 arune 342
}
1479 arune 343
 
344
/* call this function like this:
1730 arune 345
    IrTransceiver_DeInitRxChannel(channelnumber, pcint-id, GPIO_D6);
1479 arune 346
*/
347
 
1483 arune 348
void IrTransceiver_DeInitRxChannel(uint8_t channel, uint8_t pcint_id, volatile uint8_t* port, volatile uint8_t* pin, volatile uint8_t* ddr,uint8_t nr, uint8_t pcint)
1479 arune 349
{
350
    /* Deactivate interrupt */
351
    Pcint_SetCallback(pcint_id, pcint, 0);
352
 
353
    if (channel < 3)
354
    {
355
        /* Deactivate channel */
356
        drvIrRxChannel[channel].enable = FALSE;
2198 arune 357
        drvIrRxChannel[channel].len = 0;
1479 arune 358
        drvIrRxChannel[channel].storeEnable = FALSE;
359
        drvIrRxChannel[channel].callback = 0;
360
    }
361
}
362
 
1483 arune 363
uint8_t IrTransceiver_GetStoreEnableRx(uint8_t channel)
1479 arune 364
{
365
    return drvIrRxChannel[channel].storeEnable;
366
}
367
 
1483 arune 368
void IrTransceiver_DisableRx(uint8_t channel)
1479 arune 369
{
370
    if (channel < 3)
371
    {
372
        /* Soft disable channel */
373
        drvIrRxChannel[channel].enable = FALSE;
374
    }
375
}
1487 arune 376
 
1483 arune 377
void IrTransceiver_EnableRx(uint8_t channel)
1479 arune 378
{
379
    if (channel < 3)
380
    {
381
        /* Soft enable channel */
382
        drvIrRxChannel[channel].enable = TRUE;
383
    }
384
}
1487 arune 385
 
1483 arune 386
void IrTransceiver_ResetRx(uint8_t channel)
1479 arune 387
{
388
    if (channel < 3)
389
    {
390
        /* Reset channel */
2198 arune 391
        drvIrRxChannel[channel].len = 0;
1479 arune 392
        drvIrRxChannel[channel].storeEnable = FALSE;
393
    }
394
}
1470 arune 395
#endif
1465 arune 396
 
397
 
398
void IrTransceiver_Init(void)
399
{
1483 arune 400
    IR_TIMER_INIT();
401
 
402
#if IR_RX_ENABLE==1
1479 arune 403
    for (uint8_t i = 0; i < 3; i++)
404
    {
405
        drvIrRxChannel[i].storeEnable = FALSE;
2198 arune 406
        drvIrRxChannel[i].len = 0;
1479 arune 407
    }
1483 arune 408
#endif
409
 
1465 arune 410
#if IR_TX_ENABLE==1
411
    /* Set up transmitter */
1468 arune 412
    #if defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__)
1465 arune 413
    TCCR0A = (0<<COM0A1)|(0<<COM0A0)|(1<<WGM01)|(0<<WGM00);
414
    TCCR0B = (0<<WGM02)|(1<<CS00)|(0<<CS01)|(0<<CS02);
415
 
1865 myhrman 416
    /* Set up modulation frequency */
417
    IR_MODULATION_REG = (((F_CPU / 2000) / drvIrTxModFreqkHz) - 1);
1465 arune 418
 
1483 arune 419
    /* start pwm generator */
420
    TCCR0A |= (1<<COM0A0);
421
    #endif
422
 
1465 arune 423
#endif
424
 
425
}
426
 
427
#if IR_TX_ENABLE==1
1483 arune 428
void IrTransceiver_InitTxChannel(uint8_t channel, irTxCallback_t callback, volatile uint8_t *port, volatile uint8_t *pin, volatile uint8_t *ddr,uint8_t nr, uint8_t pcint)
429
{
430
    if (channel < 3)
431
    {
432
        drvIrTxChannel[channel].port=port;
1488 arune 433
        drvIrTxChannel[channel].pinmask=(1<<nr);
1483 arune 434
 
435
        /* set up port as output */
1488 arune 436
        *ddr |= (1<<nr);
1483 arune 437
 
438
        IR_OUTP_LOW();
439
 
440
        drvIrTxChannel[channel].callback = callback;
441
        drvIrTxChannel[channel].enable = TRUE;
442
        drvIrTxChannel[channel].timeoutEnable = FALSE;
1465 arune 443
    }
444
}
445
 
1865 myhrman 446
int IrTransceiver_Transmit(uint8_t channel, uint16_t *buffer, uint8_t start, uint8_t length, uint16_t modfreqkHz)
1465 arune 447
{
1865 myhrman 448
    if (modfreqkHz == 0) {
449
        /* Invalid frequency. */
450
        return -1;
451
    }
1753 arune 452
 
1865 myhrman 453
    if (length == 0) {
454
        /* No data. */
455
        return -2;
456
    }
1465 arune 457
 
1865 myhrman 458
    if (drvIrTxChannel[channel].timeoutEnable == TRUE) {
459
        /* Channel busy. */
460
        return -3;
461
    }
1753 arune 462
 
1865 myhrman 463
    /* New modulation frequency. */
464
    if (modfreqkHz != drvIrTxModFreqkHz) {
465
        /* Check that no transmissions are ongoing. */
466
        for (uint8_t i = 0; i < IR_SUPPORTED_NUM_CHANNELS; i++) {
467
            /* Channel is waiting for an overflow. */
468
            if (drvIrTxChannel[i].timeoutEnable == TRUE) {
469
                /* Transmission active. */
470
                return -4;
471
            }
472
        }
473
    }
1753 arune 474
 
1865 myhrman 475
    /* Update modulation frequency. */
476
    drvIrTxModFreqkHz = modfreqkHz;
1753 arune 477
 
1865 myhrman 478
    /* Start new transmission. */
479
    drvIrTxChannel[channel].timeoutEnable = TRUE;
2198 arune 480
    drvIrTxChannel[channel].buf = buffer;
481
    drvIrTxChannel[channel].len = start + length;
1483 arune 482
 
1865 myhrman 483
    /* first value will be loaded directly to timer below, therefore index is set to 1 here */
2198 arune 484
    drvIrTxChannel[channel].index = 1 + start;
485
    drvIrTxChannel[channel].timeout = IR_COUNT_REG + drvIrTxChannel[channel].buf[start];
1865 myhrman 486
 
487
    /* go through all channels and find the one that have the next overflow */
488
    uint8_t nextChannel = 0;
489
    uint16_t timeRemaining = 0xffff;
490
    uint16_t timeNow = IR_COMPARE_REG;
491
    for (uint8_t i = 0; i < IR_SUPPORTED_NUM_CHANNELS; i++)
492
    {
493
        /* channel is not waiting for an overflow */
494
        if (drvIrTxChannel[i].timeoutEnable == FALSE) continue;
495
 
496
        if (drvIrTxChannel[i].timeout - timeNow < timeRemaining)    // || (timeout - time > 0xffff-IR_MAX_PULSE_WIDTH)
497
        {
498
            timeRemaining = drvIrTxChannel[i].timeout - timeNow;
499
            nextChannel = i;
1483 arune 500
        }
501
    }
1865 myhrman 502
 
503
    /* set compare value to the channel that have the next overflow */
504
    IR_COMPARE_REG = drvIrTxChannel[nextChannel].timeout;
505
 
506
    /* set up modulation frequency */
507
    IR_MODULATION_REG = (((F_CPU / 2000) / drvIrTxModFreqkHz) - 1);
508
 
509
    /* Start send on pin */
510
    IR_OUTP_HIGH();
511
 
512
    /* enable overflow interrupt */
513
    IR_UNMASK_COMPARE();
1871 arune 514
 
515
    return 1;
1483 arune 516
}
1465 arune 517
#endif
1483 arune 518