Subversion Repositories HomeAutomation

Rev

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