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 |