Subversion Repositories HomeAutomation

Rev

Rev 1468 | Rev 1474 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  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>
  14. #include <drivers/ir/transceiver/irtransceiverMulti.h>
  15. #include <drivers/ir/protocols.h>
  16. #include <avr/io.h>
  17. #include <avr/interrupt.h>
  18. #include <drivers/mcu/pcint.h>
  19.  
  20. /*-----------------------------------------------------------------------------
  21.  * Globals
  22.  *---------------------------------------------------------------------------*/
  23. #if IR_RX_ENABLE==1
  24. struct {
  25.     uint16_t    timeout;
  26.     uint8_t     timeoutEnable;
  27.     uint16_t    *rxbuf;
  28.     uint8_t     rxlen;
  29.     uint8_t     storeEnable;
  30.     irCallback_t callback;
  31. } irRxChannel[3];
  32.  
  33.  
  34. #endif
  35. #if IR_TX_ENABLE==1
  36. uint16_t *txbuf;
  37. uint8_t txlen;
  38. static uint8_t bufIndex;                            //selects the pulse width in buffer to send
  39. #endif
  40.  
  41. volatile uint8_t data_transmitted;
  42.  
  43.  
  44. /*-----------------------------------------------------------------------------
  45.  * Prerequisites
  46.  *---------------------------------------------------------------------------*/
  47. #ifndef IR_RX_ACTIVE_LOW
  48. #define IR_RX_ACTIVE_LOW    1
  49. #endif
  50.  
  51. #ifndef IR_TX_ACTIVE_LOW
  52. #define IR_TX_ACTIVE_LOW    0
  53. #endif
  54.  
  55. #ifndef IR_TX_ENABLE
  56. #define IR_TX_ENABLE    0
  57. #endif
  58.  
  59. #ifndef IR_RX_ENABLE
  60. #define IR_RX_ENABLE    0
  61. #endif
  62.  
  63.  
  64. #if defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__)
  65. #define TIMSK1  TIMSK
  66. #define TIFR1   TIFR
  67. #define ICIE1   TICIE1
  68. #endif
  69.  
  70. #define IR_COMPARE_VECTOR       TIMER1_COMPB_vect
  71. #define IR_TIMEOUT_VECTOR       TIMER1_COMPA_vect
  72. #define IR_CAPTURE_VECTOR       TIMER1_CAPT_vect
  73. #define IR_TIMEOUT_REG          OCR1A
  74. #define IR_COMPARE_REG          OCR1B
  75. #define IR_CAPTURE_REG          ICR1
  76. #define IR_COUNT_REG            TCNT1
  77. #define IR_MODULATION_REG       OCR0A
  78. /*#define IR_TIMER_INIT()           TCCR1A = 0; \
  79.                                 TCCR1B = (1<<ICNC1)|(2<<CS10);
  80.                                 */
  81. #define IR_TIMER_INIT()         TCCR1A = 0; \
  82.                                 TCCR1B = (2<<CS10);
  83. #define IR_MASK_COMPARE()       TIMSK1 &= ~(1<<OCIE1B);
  84. #define IR_UNMASK_COMPARE()     TIFR1 = (1<<OCF1B); TIMSK1 |= (1<<OCIE1B);
  85. #define IR_MASK_TIMEOUT()       TIMSK1 &= ~(1<<OCIE1A);
  86. #define IR_UNMASK_TIMEOUT()     TIFR1 = (1<<OCF1A); TIMSK1 |= (1<<OCIE1A);
  87. #define IR_MASK_CAPTURE()       TIMSK1 &= ~(1<<ICIE1);
  88. #define IR_UNMASK_CAPTURE()     TIFR1 = (1<<ICF1); TIMSK1 |= (1<<ICIE1);
  89. #define IR_CAPTURE_FALLING()    TCCR1B &= ~(1<<ICES1); \
  90.                                 TIFR1 = (1<<ICF1);
  91. #define IR_CAPTURE_RISING()     TCCR1B |= (1<<ICES1); \
  92.                                 TIFR1 = (1<<ICF1);
  93.  
  94. #define IR_OUTP_HIGH()          TCCR0A |= (1<<COM0A0);
  95. #define IR_OUTP_LOW()           TCCR0A &= ~(1<<COM0A0);
  96.  
  97.  
  98. /*-----------------------------------------------------------------------------
  99.  * Interrupt Handlers
  100.  *---------------------------------------------------------------------------*/
  101.  
  102.  
  103. /*
  104. timer 1 has two comprare registers and compare ISRs, one is used below for "timeout" on receive and the other is used here for transmitter
  105. //TODO: how to handle more than one transmitter on one compare interrupt, spara en array med tider och nån enableflagga för varje kanal
  106. */
  107.  
  108. #if IR_TX_ENABLE==1
  109. ISR(IR_COMPARE_VECTOR)
  110. {
  111.     if ((bufIndex&1) == 1) {        /* if odd, ir-pause */
  112.         IR_OUTP_LOW();
  113.     } else {
  114.         IR_OUTP_HIGH();
  115.     }
  116.    
  117.     //The following three lines is just to allow a start signal to be zero.
  118. /*  bufIndex++;
  119.     while (txbuf[bufIndex] == 0){
  120.         bufIndex++;
  121.     }*/
  122.    
  123.     if (bufIndex < txlen)
  124.     {      
  125.         IR_COMPARE_REG += txbuf[bufIndex++];       
  126.         //IR_COMPARE_REG += *(txbuf + bufIndex++);     
  127.     }
  128.     else
  129.     {
  130.         IR_MASK_COMPARE();
  131.         data_transmitted = 1;
  132.     }
  133. }
  134. #endif
  135.  
  136. #if IR_RX_ENABLE==1
  137. //TODO: hur hantera detta i multi receiver
  138. //TODO: ha en array med tider och nån enableflagga för varje kanal
  139. //TODO: mot slutet av ISRen laddas nästa tid in...
  140.  
  141. /* When this timeout occurs a pulsetrain is complete */
  142. ISR(IR_TIMEOUT_VECTOR)
  143. {
  144.  
  145.     /* Find which channel timed out */
  146.     uint16_t timeDiff = 0xffff;
  147.     uint8_t channel = 0;
  148.     for (uint8_t i=0; i < 3; i++)
  149.     {
  150.         if ((irRxChannel[channel].timeoutEnable) && (IR_TIMEOUT_REG-irRxChannel[i].timeout < timeDiff))
  151.         {
  152.             timeDiff = IR_TIMEOUT_REG-irRxChannel[i].timeout;
  153.             channel = i;
  154.         }
  155.     }
  156.  
  157.     /* If more than 3 flanks was recevied */
  158.     if (irRxChannel[channel].rxlen > 3)
  159.     {
  160.         /* Notify the application that a pulse train has been received. */
  161.         irRxChannel[channel].callback(channel, irRxChannel[channel].rxbuf, irRxChannel[channel].rxlen);
  162.     }
  163.  
  164.     irRxChannel[channel].storeEnable = FALSE;
  165.     irRxChannel[channel].timeoutEnable = FALSE;
  166.  
  167.     IR_UNMASK_TIMEOUT();
  168.    
  169. //TODO: reset the timeout for next enabled channel
  170. /*
  171.     uint16_t nextTimeout = irRxChannel[channel].timeout;
  172.     for (uint8_t i=0; i < 3; i++)
  173.     {
  174. //TODO: hitta den med timeout härnäst (svårt med tanke på att den tiden kan ha passerat eftersom vi är under interrupt)
  175. //kanske inte är så noga, i värsta fall tar det 65ms extra
  176.         if ((irRxChannel[channel].timeoutEnable) && (irRxChannel[i].timeout < nextTimeout))
  177.         {
  178.             nextTimeout = irRxChannel[i].timeout;
  179.         }
  180.     }
  181.     IR_MASK_TIMEOUT();
  182.     IR_TIMEOUT_REG = nextTimeout;
  183. */
  184. }
  185. #endif
  186.  
  187.  
  188. /*-----------------------------------------------------------------------------
  189.  * Private Functions
  190.  *---------------------------------------------------------------------------*/
  191.  
  192. #if IR_RX_ENABLE==1
  193.  
  194. /* these wrapper functions are called from the pcint driver (callback) */
  195. void IrTransceiver_Store_ch0(uint8_t id, uint8_t status)
  196. {
  197.     IrTransceiver_Store(0);
  198. }
  199. void IrTransceiver_Store_ch1(uint8_t id, uint8_t status)
  200. {
  201.     IrTransceiver_Store(1);
  202. }
  203. void IrTransceiver_Store_ch2(uint8_t id, uint8_t status)
  204. {
  205.     IrTransceiver_Store(2);
  206. }
  207.  
  208. void IrTransceiver_Store(uint8_t channel)
  209. {
  210.     static uint16_t prev_time;
  211.     uint16_t pulsewidth;
  212.  
  213.     /* Read the measured transition time from the capture register. */
  214.     //uint16_t time = IR_CAPTURE_REG;
  215.     /* Read the timer counter register to get the current "time". */
  216.     uint16_t time = IR_COUNT_REG;
  217.        
  218.     /* Subtract the current measurement from the previous to get the pulse
  219.      * width. */
  220.     pulsewidth = time - prev_time;
  221.     prev_time = time;
  222.    
  223.     /* Set the timeout. */
  224.     irRxChannel[channel].timeout = time + IR_MAX_PULSE_WIDTH;
  225.     irRxChannel[channel].timeoutEnable = TRUE;
  226.     uint16_t nextTimeout = irRxChannel[channel].timeout;
  227.     for (uint8_t i=0; i < 3; i++)
  228.     {
  229. //TODO: hitta den med timeout härnäst (svårt med tanke på att den tiden kan ha passerat eftersom vi är under interrupt)
  230. //kanske inte är så noga, i värsta fall tar det 65ms extra
  231.         if ((irRxChannel[channel].timeoutEnable) && (irRxChannel[i].timeout < nextTimeout))
  232.         {
  233.             nextTimeout = irRxChannel[i].timeout;
  234.         }
  235.     }
  236.     IR_TIMEOUT_REG = nextTimeout;
  237.    
  238.     if (irRxChannel[channel].storeEnable)
  239.     {
  240.         /* Store the measurement. */
  241.         irRxChannel[channel].rxbuf[irRxChannel[channel].rxlen++] = pulsewidth;
  242.  
  243.         /* Disable future measurements if we've filled the buffer. */
  244.         //TODO: What to do in multi recevier?
  245.         //TODO: Report overflow to application
  246.         if (irRxChannel[channel].rxlen == MAX_NR_TIMES)
  247.         {
  248.             irRxChannel[channel].rxlen = MAX_NR_TIMES-1;
  249.             //IR_MASK_CAPTURE();
  250.         }
  251.     }
  252.     else
  253.     {
  254.         /* The first edge of the pulse train has been detected. Enable the
  255.          * storage of the following pulsewidths. */
  256.         irRxChannel[channel].storeEnable = TRUE;
  257.         irRxChannel[channel].rxlen = 0;
  258.         /* Enable timeout interrupt for detection of the end of the pulse train. */
  259.         IR_UNMASK_TIMEOUT();
  260.  
  261.         //TODO: if buffer resource coordinator is implemented this is where a buffer should be assinged to this channel
  262.     }
  263. }
  264. #endif
  265.  
  266.  
  267. /*-----------------------------------------------------------------------------
  268.  * Public Functions
  269.  *---------------------------------------------------------------------------*/
  270.  
  271. /* call this function like this:
  272.     IrTransceiver_Init_TX_Channel(0, buffer, callback, pcint-id, GPIO_D6);
  273.     buffer is a memory location
  274.     callback is a function to call when a receive/transmitt is complete
  275.     also call with IO port to use
  276.    
  277.     function to deactivate channel may later be needed
  278. */
  279.  
  280. #if IR_RX_ENABLE==1
  281. void IrTransceiver_Init_TX_Channel(uint8_t channel, uint16_t *buffer, irCallback_t callback, uint8_t pcint_id, volatile uint8_t* port, volatile uint8_t* pin, volatile uint8_t* ddr,uint8_t nr, uint8_t pcint)
  282. {
  283.     if (channel == 0)
  284.     {
  285.         Pcint_SetCallback(uint8_t pcint_id, uint8_t pcint, &IrTransceiver_Store_ch0);
  286.     }
  287.     else if (channel == 1)
  288.     {
  289.         Pcint_SetCallback(uint8_t pcint_id, uint8_t pcint, &IrTransceiver_Store_ch1);
  290.     }
  291.     else if (channel == 2)
  292.     {
  293.         Pcint_SetCallback(uint8_t pcint_id, uint8_t pcint, &IrTransceiver_Store_ch2);
  294.     }
  295.    
  296.     if (channel < 3)
  297.     {
  298.         /* Set port direction to input */
  299.         *ddr &= ~(1 << nr);
  300.        
  301.         irRxChannel[channel].rxbuf = buffer;
  302.         irRxChannel[channel].rxlen = 0;
  303.         irRxChannel[channel].storeEnable = FALSE;
  304.         irRxChannel[channel].timeoutEnable = FALSE;
  305.         irRxChannel[channel].callback = callback;
  306.        
  307.     }
  308. }
  309. #endif
  310.  
  311. /*
  312. void IrTransceiver_Init_RX_Channel(uint8_t channel, uint16_t *buffer, irCallback_t callback, volatile uint8_t* port, volatile uint8_t* pin, volatile uint8_t* ddr,uint8_t nr, uint8_t pcint)
  313. {
  314.    
  315. }
  316. */
  317.  
  318. void IrTransceiver_Init(void)
  319. {
  320.     IR_TIMER_INIT();
  321.        
  322. #if IR_TX_ENABLE==1
  323.     /* Set up transmitter */
  324.     IR_T_DDR |= (1<<IR_T_BIT);
  325.     #if defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__)
  326.     TCCR0A = (0<<COM0A1)|(0<<COM0A0)|(1<<WGM01)|(0<<WGM00);
  327.     TCCR0B = (0<<WGM02)|(1<<CS00)|(0<<CS01)|(0<<CS02);
  328.     #endif
  329.    
  330. #if IR_TX_ACTIVE_LOW==1
  331.     /* when pwm is disconnected from port (during low) the port should output 5V */
  332.     IR_T_PORT |= (1<<IR_T_BIT);
  333. #else
  334.     /* when pwm is disconnected from port (during low) the port should output 0V */
  335.     IR_T_PORT &= ~(1<<IR_T_BIT);
  336. #endif
  337.  
  338. #endif
  339.  
  340. }
  341.  
  342. uint8_t IrTransceiver_Transmit_Poll(void) {
  343. #if IR_TX_ENABLE==1
  344.     if (data_transmitted == 0) {
  345.         return IR_NOT_FINISHED;
  346.     } else {
  347.         return IR_OK;
  348.     }
  349. #else
  350.     return 0;
  351. #endif
  352. }
  353.  
  354. uint8_t IrTransceiver_Transmit(uint16_t *buffer, uint8_t length, uint8_t modfreq)
  355. {
  356. #if IR_TX_ENABLE==1
  357.     data_transmitted = 0;
  358.    
  359.     if (length == 0) return IR_NO_DATA;
  360.  
  361.     txbuf = buffer;
  362.     txlen = length;
  363.     bufIndex = 1;
  364.    
  365.     IR_MODULATION_REG = modfreq;
  366.    
  367.     IR_COMPARE_REG = IR_COUNT_REG + txbuf[0];
  368.    
  369.     IR_OUTP_HIGH();
  370.    
  371.     IR_UNMASK_COMPARE();
  372.    
  373.     //while (!data_transmitted);
  374.    
  375.     return IR_OK;
  376. #else
  377.     return 0;
  378. #endif
  379. }
  380.