Subversion Repositories HomeAutomation

Rev

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