Subversion Repositories HomeAutomation

Rev

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