Subversion Repositories HomeAutomation

Rev

Rev 1753 | Rev 1841 | 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/ir/transceiver/irtransceiverMulti.h>
  16. #include <drivers/ir/protocols.h>
  17. #include <avr/io.h>
  18. #include <avr/interrupt.h>
  19.  
  20. /*-----------------------------------------------------------------------------
  21.  * Prerequisites
  22.  *---------------------------------------------------------------------------*/
  23. #if defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__)
  24. #define TIMSK1  TIMSK
  25. #define TIFR1   TIFR
  26. #define ICIE1   TICIE1
  27. #endif
  28.  
  29. #define IR_COMPARE_VECTOR       TIMER1_COMPB_vect
  30. #define IR_TIMEOUT_VECTOR       TIMER1_COMPA_vect
  31. #define IR_CAPTURE_VECTOR       TIMER1_CAPT_vect
  32. #define IR_TIMEOUT_REG          OCR1A
  33. #define IR_COMPARE_REG          OCR1B
  34. #define IR_CAPTURE_REG          ICR1
  35. #define IR_COUNT_REG            TCNT1
  36. #define IR_MODULATION_REG       OCR0A
  37. /*#define IR_TIMER_INIT()           TCCR1A = 0; \
  38.                                 TCCR1B = (1<<ICNC1)|(2<<CS10);
  39.                                 */
  40. #define IR_TIMER_INIT()         TCCR1A = 0; \
  41.                                 TCCR1B = (2<<CS10);
  42. #define IR_MASK_COMPARE()       TIMSK1 &= ~(1<<OCIE1B);
  43. #define IR_UNMASK_COMPARE()     TIFR1 = (1<<OCF1B); TIMSK1 |= (1<<OCIE1B);
  44. #define IR_MASK_TIMEOUT()       TIMSK1 &= ~(1<<OCIE1A);
  45. #define IR_UNMASK_TIMEOUT()     TIFR1 = (1<<OCF1A); TIMSK1 |= (1<<OCIE1A);
  46. #define IR_MASK_CAPTURE()       TIMSK1 &= ~(1<<ICIE1);
  47. #define IR_UNMASK_CAPTURE()     TIFR1 = (1<<ICF1); TIMSK1 |= (1<<ICIE1);
  48. #define IR_CAPTURE_FALLING()    TCCR1B &= ~(1<<ICES1); \
  49.                                 TIFR1 = (1<<ICF1);
  50. #define IR_CAPTURE_RISING()     TCCR1B |= (1<<ICES1); \
  51.                                 TIFR1 = (1<<ICF1);
  52.  
  53. //#define IR_OUTP_HIGH()            TCCR0A |= (1<<COM0A0);
  54. //#define IR_OUTP_LOW()         TCCR0A &= ~(1<<COM0A0);
  55. #if IR_TX_ACTIVE_LOW==1
  56. #define IR_OUTP_HIGH()  *drvIrTxChannel[channel].port &= ~drvIrTxChannel[channel].pinmask
  57. #define IR_OUTP_LOW()   *drvIrTxChannel[channel].port |= drvIrTxChannel[channel].pinmask
  58. #else
  59. #define IR_OUTP_HIGH()  *drvIrTxChannel[channel].port |= drvIrTxChannel[channel].pinmask
  60. #define IR_OUTP_LOW()   *drvIrTxChannel[channel].port &= ~drvIrTxChannel[channel].pinmask
  61. #endif
  62.  
  63.  
  64. /*-----------------------------------------------------------------------------
  65.  * Globals
  66.  *---------------------------------------------------------------------------*/
  67. #if IR_RX_ENABLE==1
  68. struct {
  69.     uint8_t     enable;
  70.     uint16_t    timeout;
  71.     uint16_t    *rxbuf;
  72.     uint8_t     rxlen;
  73.     uint8_t     storeEnable;
  74.     irRxCallback_t callback;
  75. } drvIrRxChannel[3];
  76. #endif
  77.  
  78. #if IR_TX_ENABLE==1
  79. struct {
  80.     uint8_t     enable;
  81.     uint16_t    timeout;
  82.     uint8_t     timeoutEnable;
  83.     uint16_t    *txbuf;
  84.     uint8_t     txlen;
  85.     uint8_t     txindex;
  86.     irTxCallback_t callback;
  87.     volatile uint8_t    *port;
  88.     uint8_t     pinmask;
  89. } drvIrTxChannel[3];
  90. #endif
  91.  
  92.  
  93. /*-----------------------------------------------------------------------------
  94.  * Interrupt Handlers
  95.  *---------------------------------------------------------------------------*/
  96. #if IR_TX_ENABLE==1
  97. ISR(IR_COMPARE_VECTOR)
  98. {
  99.     /* find which channel */
  100.     uint16_t time = IR_COMPARE_REG;
  101.     uint16_t diff;
  102.     uint8_t channel;
  103.  
  104.     /* go through all channels and check which of thems have overflowed */
  105.     for (channel=0; channel < IR_SUPPORTED_NUM_CHANNELS; channel++)
  106.     {
  107.         /* if channel is waiting for an overflow */
  108.         if (drvIrTxChannel[channel].timeoutEnable==TRUE)
  109.         {
  110.             /* check if channel have overflowed or is about to overflow */
  111.             diff = (time+50)-drvIrTxChannel[channel].timeout;
  112.             if (diff < IR_MAX_PULSE_WIDTH)
  113.             {
  114.                 /* check what to output next */
  115.                 if ((drvIrTxChannel[channel].txindex&1) == 1) {     /* if odd, ir-pause */
  116.                     IR_OUTP_LOW();
  117.                 } else {
  118.                     IR_OUTP_HIGH();
  119.                 }
  120.                
  121.                 /* is there more to send */
  122.                 if (drvIrTxChannel[channel].txindex < drvIrTxChannel[channel].txlen)
  123.                 {
  124.                     /* load next timeout value */
  125.                     drvIrTxChannel[channel].timeout = IR_COMPARE_REG + drvIrTxChannel[channel].txbuf[drvIrTxChannel[channel].txindex++];
  126.                 }
  127.                 else
  128.                 {
  129.                     /* disable this channel */
  130.                     drvIrTxChannel[channel].timeoutEnable = FALSE;
  131.  
  132.                     /* disable the overflow interrupt */
  133.                     IR_MASK_COMPARE();
  134.        
  135.                     /* notify the application that a pulse train has been sent. */
  136.                     drvIrTxChannel[channel].callback(channel);
  137.                 }
  138.             }
  139.         }
  140.     }
  141.    
  142.     channel = 0;
  143.     diff = 0xffff;
  144.     /* go through all channels and find the one that have the next overflow */
  145.     for (uint8_t i=0; i < IR_SUPPORTED_NUM_CHANNELS; i++)
  146.     {
  147.         /* if channel is waiting for an overflow */
  148.         if (drvIrTxChannel[i].timeoutEnable==TRUE)
  149.         {
  150.             if (drvIrTxChannel[i].timeout - time < diff)
  151.             {
  152.                 diff = drvIrTxChannel[i].timeout - time;
  153.                 channel = i;
  154.             }
  155.             /* enable overflow interrupt */
  156.             IR_UNMASK_COMPARE();
  157.         }      
  158.     }  
  159.  
  160.     /* set compare value to the channel that have the next overflow */
  161.     IR_COMPARE_REG = drvIrTxChannel[channel].timeout;
  162. }
  163. #endif
  164.  
  165.  
  166. #if IR_RX_ENABLE==1
  167. /* When this timeout occurs a pulsetrain is complete */
  168. ISR(IR_TIMEOUT_VECTOR)
  169. {
  170.     for (uint8_t i=0; i < 3; i++)
  171.     {
  172.         /* If more than 3 flanks was recevied */
  173.         if (drvIrRxChannel[i].storeEnable == TRUE && drvIrRxChannel[i].rxlen > 3)
  174.         {
  175.             /* Notify the application that a pulse train has been received. */
  176.             drvIrRxChannel[i].callback(i, drvIrRxChannel[i].rxbuf, drvIrRxChannel[i].rxlen);
  177.         }
  178.  
  179.         drvIrRxChannel[i].storeEnable = FALSE;
  180.     }
  181.  
  182.     /* Disable ISR */
  183.     IR_MASK_TIMEOUT();
  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[3];
  211.     uint16_t pulsewidth;
  212.  
  213.     /* Read the timer counter register to get the current "time". */
  214.     uint16_t time = IR_COUNT_REG;
  215.    
  216.     /* Subtract the current measurement from the previous to get the pulse width. */
  217.     pulsewidth = time - prev_time[channel];
  218.     prev_time[channel] = time;
  219.  
  220.     if (drvIrRxChannel[channel].storeEnable)
  221.     {
  222.         /* Store the measurement. */
  223.         drvIrRxChannel[channel].rxbuf[drvIrRxChannel[channel].rxlen++] = pulsewidth;
  224.  
  225.         /* Disable future measurements if we've filled the buffer. */
  226.         //TODO: Report overflow to application
  227.         if (drvIrRxChannel[channel].rxlen == MAX_NR_TIMES)
  228.         {
  229.             drvIrRxChannel[channel].rxlen = MAX_NR_TIMES-1;
  230.         }
  231.         else
  232.         {
  233.             /* Set the timeout for detection of the end of the pulse train. */
  234.             drvIrRxChannel[channel].timeout = time + IR_MAX_PULSE_WIDTH;
  235.             IR_TIMEOUT_REG = drvIrRxChannel[channel].timeout;
  236.         }
  237.     }
  238.     else if (drvIrRxChannel[channel].enable == TRUE)
  239.     {
  240.         /* The first edge of the pulse train has been detected. Enable the storage of the following pulsewidths. */
  241.         drvIrRxChannel[channel].storeEnable = TRUE;
  242.         drvIrRxChannel[channel].rxlen = 0;
  243.  
  244.         /* Enable timeout interrupt for detection of the end of the pulse train. */
  245.         IR_TIMEOUT_REG = time + IR_MAX_PULSE_WIDTH;
  246.         IR_UNMASK_TIMEOUT();
  247.     }
  248. }
  249. #endif
  250.  
  251.  
  252. /* call this function like this:
  253.     IrTransceiver_InitRxChannel(channelnumber, buffer, callback, pcint-id, GPIO_D6);
  254.     buffer is a memory location
  255.     callback is a function to call when a receive/transmitt is complete
  256.     also call with IO port to use  
  257. */
  258.  
  259. #if IR_RX_ENABLE==1
  260. 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)
  261. {
  262.     if (channel == 0)
  263.     {
  264.         Pcint_SetCallback(pcint_id, pcint, &IrTransceiver_Store_ch0);
  265.     }
  266.     else if (channel == 1)
  267.     {
  268.         Pcint_SetCallback(pcint_id, pcint, &IrTransceiver_Store_ch1);
  269.     }
  270.     else if (channel == 2)
  271.     {
  272.         Pcint_SetCallback(pcint_id, pcint, &IrTransceiver_Store_ch2);
  273.     }
  274.    
  275.     if (channel < 3)
  276.     {
  277.         /* Set port direction to input */
  278.         *ddr &= ~(1 << nr);
  279.        
  280.         drvIrRxChannel[channel].rxbuf = buffer;
  281.         drvIrRxChannel[channel].rxlen = 0;
  282.         drvIrRxChannel[channel].storeEnable = FALSE;
  283.         drvIrRxChannel[channel].callback = callback;
  284.         drvIrRxChannel[channel].enable = TRUE;
  285.     }
  286. }
  287.  
  288. /* call this function like this:
  289.     IrTransceiver_DeInitRxChannel(channelnumber, pcint-id, GPIO_D6);
  290. */
  291.  
  292. 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)
  293. {
  294.     /* Deactivate interrupt */
  295.     Pcint_SetCallback(pcint_id, pcint, 0);
  296.    
  297.     if (channel < 3)
  298.     {
  299.         /* Deactivate channel */
  300.         drvIrRxChannel[channel].enable = FALSE;
  301.         drvIrRxChannel[channel].rxlen = 0;
  302.         drvIrRxChannel[channel].storeEnable = FALSE;
  303.         drvIrRxChannel[channel].callback = 0;
  304.     }
  305. }
  306.  
  307. uint8_t IrTransceiver_GetStoreEnableRx(uint8_t channel)
  308. {
  309.     return drvIrRxChannel[channel].storeEnable;
  310. }
  311.  
  312. void IrTransceiver_DisableRx(uint8_t channel)
  313. {
  314.     if (channel < 3)
  315.     {
  316.         /* Soft disable channel */
  317.         drvIrRxChannel[channel].enable = FALSE;
  318.     }
  319. }
  320.  
  321. void IrTransceiver_EnableRx(uint8_t channel)
  322. {
  323.     if (channel < 3)
  324.     {
  325.         /* Soft enable channel */
  326.         drvIrRxChannel[channel].enable = TRUE;
  327.     }
  328. }
  329.  
  330. void IrTransceiver_ResetRx(uint8_t channel)
  331. {
  332.     if (channel < 3)
  333.     {
  334.         /* Reset channel */
  335.         drvIrRxChannel[channel].rxlen = 0;
  336.         drvIrRxChannel[channel].storeEnable = FALSE;
  337.     }
  338. }
  339. #endif
  340.  
  341.  
  342. void IrTransceiver_Init(void)
  343. {
  344.     IR_TIMER_INIT();
  345.  
  346. #if IR_RX_ENABLE==1
  347.     for (uint8_t i = 0; i < 3; i++)
  348.     {
  349.         drvIrRxChannel[i].storeEnable = FALSE;
  350.         drvIrRxChannel[i].rxlen = 0;
  351.     }
  352. #endif
  353.    
  354. #if IR_TX_ENABLE==1
  355.     /* Set up transmitter */
  356.     #if defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__)
  357.     TCCR0A = (0<<COM0A1)|(0<<COM0A0)|(1<<WGM01)|(0<<WGM00);
  358.     TCCR0B = (0<<WGM02)|(1<<CS00)|(0<<CS01)|(0<<CS02);
  359.    
  360.     /* set up modulation frequency to 38kHz */
  361.     IR_MODULATION_REG = (((F_CPU/2000)/38) -1);
  362.  
  363.     /* start pwm generator */
  364.     TCCR0A |= (1<<COM0A0);
  365.     #endif
  366.  
  367. #endif
  368.  
  369. }
  370.  
  371. #if IR_TX_ENABLE==1
  372. 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)
  373. {
  374.     if (channel < 3)
  375.     {
  376.         drvIrTxChannel[channel].port=port;
  377.         drvIrTxChannel[channel].pinmask=(1<<nr);
  378.    
  379.         /* set up port as output */
  380.         *ddr |= (1<<nr);
  381.  
  382.         IR_OUTP_LOW();
  383.            
  384.         drvIrTxChannel[channel].callback = callback;
  385.         drvIrTxChannel[channel].enable = TRUE;
  386.         drvIrTxChannel[channel].timeoutEnable = FALSE;
  387.     }
  388. }
  389.  
  390. void IrTransceiver_Transmit(uint8_t channel, uint16_t *buffer, uint8_t length)
  391. {
  392.     uint16_t diff;
  393.     uint8_t findchannel;
  394.  
  395.     if (length > 0)
  396.     {
  397.         if (drvIrTxChannel[channel].timeoutEnable == FALSE)
  398.         {
  399.             drvIrTxChannel[channel].timeoutEnable = TRUE;
  400.             drvIrTxChannel[channel].txbuf = buffer;
  401.             drvIrTxChannel[channel].txlen = length;
  402.             /* first value will be loaded directly to timer below, therefore index is set to 1 here */
  403.             drvIrTxChannel[channel].txindex = 1;
  404.             drvIrTxChannel[channel].timeout = IR_COUNT_REG + drvIrTxChannel[channel].txbuf[0];
  405.  
  406.  
  407.             findchannel = 0;
  408.             diff = 0xffff;
  409.             uint16_t time = IR_COMPARE_REG;
  410.             /* go through all channels and find the one that have the next overflow */
  411.             for (uint8_t i=0; i < IR_SUPPORTED_NUM_CHANNELS; i++)
  412.             {
  413.                 /* if channel is waiting for an overflow */
  414.                 if (drvIrTxChannel[i].timeoutEnable==TRUE)
  415.                 {
  416.                     if (drvIrTxChannel[i].timeout - time < diff)    // || (timeout - time > 0xffff-IR_MAX_PULSE_WIDTH)
  417.                     {
  418.                         diff = drvIrTxChannel[i].timeout - time;
  419.                         findchannel = i;
  420.                     }
  421.                 }      
  422.             }  
  423.  
  424.             /* set compare value to the channel that have the next overflow */
  425.             IR_COMPARE_REG = drvIrTxChannel[findchannel].timeout;
  426.  
  427.             /* Start send on pin */
  428.             IR_OUTP_HIGH();
  429.  
  430.             /* enable overflow interrupt */
  431.             IR_UNMASK_COMPARE();
  432.         }
  433.     }
  434. }
  435. #endif
  436.  
  437.