Subversion Repositories HomeAutomation

Rev

Rev 1730 | Rev 1755 | 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.     uint16_t    *rxbuf;
  73.     uint8_t     rxlen;
  74.     uint8_t     storeEnable;
  75.     irRxCallback_t callback;
  76. } drvIrRxChannel[3];
  77. #endif
  78.  
  79. #if IR_TX_ENABLE==1
  80. struct {
  81.     uint8_t     enable;
  82.     uint16_t    timeout;
  83.     uint8_t     timeoutEnable;
  84.     uint16_t    *txbuf;
  85.     uint8_t     txlen;
  86.     uint8_t     txindex;
  87.     irTxCallback_t callback;
  88.     volatile uint8_t    *port;
  89.     uint8_t     pinmask;
  90. } drvIrTxChannel[3];
  91. #endif
  92.  
  93.  
  94. /*-----------------------------------------------------------------------------
  95.  * Interrupt Handlers
  96.  *---------------------------------------------------------------------------*/
  97. #if IR_TX_ENABLE==1
  98. ISR(IR_COMPARE_VECTOR)
  99. {
  100.     /* find which channel */
  101.     uint16_t time = IR_COMPARE_REG;
  102.     uint16_t diff;
  103.     uint8_t channel;
  104.  
  105.     /* go through all channels and check which of thems have overflowed */
  106.     for (channel=0; channel < IR_SUPPORTED_NUM_CHANNELS; channel++)
  107.     {
  108.         /* if channel is waiting for an overflow */
  109.         if (drvIrTxChannel[channel].timeoutEnable==TRUE)
  110.         {
  111.             /* check if channel have overflowed or is about to overflow */
  112.             diff = (time+50)-drvIrTxChannel[channel].timeout;
  113.             if (diff < IR_MAX_PULSE_WIDTH)
  114.             {
  115.                 /* check what to output next */
  116.                 if ((drvIrTxChannel[channel].txindex&1) == 1) {     /* if odd, ir-pause */
  117.                     IR_OUTP_LOW();
  118.                 } else {
  119.                     IR_OUTP_HIGH();
  120.                 }
  121.                
  122.                 /* is there more to send */
  123.                 if (drvIrTxChannel[channel].txindex < drvIrTxChannel[channel].txlen)
  124.                 {
  125.                     /* load next timeout value */
  126.                     drvIrTxChannel[channel].timeout = IR_COMPARE_REG + drvIrTxChannel[channel].txbuf[drvIrTxChannel[channel].txindex++];
  127.                 }
  128.                 else
  129.                 {
  130.                     /* disable this channel */
  131.                     drvIrTxChannel[channel].timeoutEnable = FALSE;
  132.  
  133.                     /* disable the overflow interrupt */
  134.                     IR_MASK_COMPARE();
  135.        
  136.                     /* notify the application that a pulse train has been sent. */
  137.                     drvIrTxChannel[channel].callback(channel);
  138.                 }
  139.             }
  140.         }
  141.     }
  142.    
  143.     channel = 0;
  144.     diff = 0xffff;
  145.     /* go through all channels and find the one that have the next overflow */
  146.     for (uint8_t i=0; i < IR_SUPPORTED_NUM_CHANNELS; i++)
  147.     {
  148.         /* if channel is waiting for an overflow */
  149.         if (drvIrTxChannel[i].timeoutEnable==TRUE)
  150.         {
  151.             if (drvIrTxChannel[i].timeout - time < diff)
  152.             {
  153.                 diff = drvIrTxChannel[i].timeout - time;
  154.                 channel = i;
  155.             }
  156.             /* enable overflow interrupt */
  157.             IR_UNMASK_COMPARE();
  158.         }      
  159.     }  
  160.  
  161.     /* set compare value to the channel that have the next overflow */
  162.     IR_COMPARE_REG = drvIrTxChannel[channel].timeout;
  163. }
  164. #endif
  165.  
  166.  
  167. #if IR_RX_ENABLE==1
  168. /* When this timeout occurs a pulsetrain is complete */
  169. ISR(IR_TIMEOUT_VECTOR)
  170. {
  171. gpio_toggle_pin(GPIO_B0); /* Toggle debug output PB0 */
  172.     for (uint8_t i=0; i < 3; i++)
  173.     {
  174.         /* If more than 3 flanks was recevied */
  175.         if (drvIrRxChannel[i].storeEnable == TRUE && drvIrRxChannel[i].rxlen > 3)
  176.         {
  177.             /* Notify the application that a pulse train has been received. */
  178.             drvIrRxChannel[i].callback(i, drvIrRxChannel[i].rxbuf, drvIrRxChannel[i].rxlen);
  179.         }
  180.  
  181.         drvIrRxChannel[i].storeEnable = FALSE;
  182.     }
  183.  
  184.     /* Disable ISR */
  185.     IR_MASK_TIMEOUT();
  186. }
  187. #endif
  188.  
  189.  
  190. /*-----------------------------------------------------------------------------
  191.  * Private Functions
  192.  *---------------------------------------------------------------------------*/
  193.  
  194. #if IR_RX_ENABLE==1
  195.  
  196. /* these wrapper functions are called from the pcint driver (callback) */
  197. void IrTransceiver_Store_ch0(uint8_t id, uint8_t status)
  198. {
  199.     IrTransceiver_Store(0);
  200. }
  201. void IrTransceiver_Store_ch1(uint8_t id, uint8_t status)
  202. {
  203.     IrTransceiver_Store(1);
  204. }
  205. void IrTransceiver_Store_ch2(uint8_t id, uint8_t status)
  206. {
  207.     IrTransceiver_Store(2);
  208. }
  209.  
  210. void IrTransceiver_Store(uint8_t channel)
  211. {
  212. gpio_toggle_pin(GPIO_B7); /* Toggle debug output PB7 */
  213. //gpio_toggle_pin(GPIO_D7); /* Toggle debug output PD7 */
  214.  
  215.     static uint16_t prev_time[3];
  216.     uint16_t pulsewidth;
  217.  
  218.     /* Read the timer counter register to get the current "time". */
  219.     uint16_t time = IR_COUNT_REG;
  220.    
  221.     /* Subtract the current measurement from the previous to get the pulse width. */
  222.     pulsewidth = time - prev_time[channel];
  223.     prev_time[channel] = time;
  224.  
  225.     if (drvIrRxChannel[channel].storeEnable)
  226.     {
  227.         /* Store the measurement. */
  228.         drvIrRxChannel[channel].rxbuf[drvIrRxChannel[channel].rxlen++] = pulsewidth;
  229.  
  230.         /* Disable future measurements if we've filled the buffer. */
  231.         //TODO: Report overflow to application
  232.         if (drvIrRxChannel[channel].rxlen == MAX_NR_TIMES)
  233.         {
  234.             drvIrRxChannel[channel].rxlen = MAX_NR_TIMES-1;
  235.         }
  236.         else
  237.         {
  238.             /* Set the timeout for detection of the end of the pulse train. */
  239.             drvIrRxChannel[channel].timeout = time + IR_MAX_PULSE_WIDTH;
  240.             IR_TIMEOUT_REG = drvIrRxChannel[channel].timeout;
  241.         }
  242.     }
  243.     else if (drvIrRxChannel[channel].enable == TRUE)
  244.     {
  245.         /* The first edge of the pulse train has been detected. Enable the storage of the following pulsewidths. */
  246.         drvIrRxChannel[channel].storeEnable = TRUE;
  247.         drvIrRxChannel[channel].rxlen = 0;
  248.  
  249.         /* Enable timeout interrupt for detection of the end of the pulse train. */
  250.         IR_TIMEOUT_REG = time + IR_MAX_PULSE_WIDTH;
  251.         IR_UNMASK_TIMEOUT();
  252.     }
  253. }
  254. #endif
  255.  
  256.  
  257. /* call this function like this:
  258.     IrTransceiver_InitRxChannel(channelnumber, buffer, callback, pcint-id, GPIO_D6);
  259.     buffer is a memory location
  260.     callback is a function to call when a receive/transmitt is complete
  261.     also call with IO port to use  
  262. */
  263.  
  264. #if IR_RX_ENABLE==1
  265. 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)
  266. {
  267.     if (channel == 0)
  268.     {
  269.         Pcint_SetCallback(pcint_id, pcint, &IrTransceiver_Store_ch0);
  270.     }
  271.     else if (channel == 1)
  272.     {
  273.         Pcint_SetCallback(pcint_id, pcint, &IrTransceiver_Store_ch1);
  274.     }
  275.     else if (channel == 2)
  276.     {
  277.         Pcint_SetCallback(pcint_id, pcint, &IrTransceiver_Store_ch2);
  278.     }
  279.    
  280.     if (channel < 3)
  281.     {
  282.         /* Set port direction to input */
  283.         *ddr &= ~(1 << nr);
  284.        
  285.         drvIrRxChannel[channel].rxbuf = buffer;
  286.         drvIrRxChannel[channel].rxlen = 0;
  287.         drvIrRxChannel[channel].storeEnable = FALSE;
  288.         drvIrRxChannel[channel].callback = callback;
  289.         drvIrRxChannel[channel].enable = TRUE;
  290.     }
  291. }
  292.  
  293. /* call this function like this:
  294.     IrTransceiver_DeInitRxChannel(channelnumber, pcint-id, GPIO_D6);
  295. */
  296.  
  297. 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)
  298. {
  299.     /* Deactivate interrupt */
  300.     Pcint_SetCallback(pcint_id, pcint, 0);
  301.    
  302.     if (channel < 3)
  303.     {
  304.         /* Deactivate channel */
  305.         drvIrRxChannel[channel].enable = FALSE;
  306.         drvIrRxChannel[channel].rxlen = 0;
  307.         drvIrRxChannel[channel].storeEnable = FALSE;
  308.         drvIrRxChannel[channel].callback = 0;
  309.     }
  310. }
  311.  
  312. uint8_t IrTransceiver_GetStoreEnableRx(uint8_t channel)
  313. {
  314.     return drvIrRxChannel[channel].storeEnable;
  315. }
  316.  
  317. void IrTransceiver_DisableRx(uint8_t channel)
  318. {
  319.     if (channel < 3)
  320.     {
  321.         /* Soft disable channel */
  322.         drvIrRxChannel[channel].enable = FALSE;
  323.     }
  324. }
  325.  
  326. void IrTransceiver_EnableRx(uint8_t channel)
  327. {
  328.     if (channel < 3)
  329.     {
  330.         /* Soft enable channel */
  331.         drvIrRxChannel[channel].enable = TRUE;
  332.     }
  333. }
  334.  
  335. void IrTransceiver_ResetRx(uint8_t channel)
  336. {
  337.     if (channel < 3)
  338.     {
  339.         /* Reset channel */
  340.         drvIrRxChannel[channel].rxlen = 0;
  341.         drvIrRxChannel[channel].storeEnable = FALSE;
  342.     }
  343. }
  344. #endif
  345.  
  346.  
  347. void IrTransceiver_Init(void)
  348. {
  349.     IR_TIMER_INIT();
  350.  
  351. #if IR_RX_ENABLE==1
  352.     for (uint8_t i = 0; i < 3; i++)
  353.     {
  354.         drvIrRxChannel[i].storeEnable = FALSE;
  355.         drvIrRxChannel[i].rxlen = 0;
  356.     }
  357. #endif
  358.    
  359. #if IR_TX_ENABLE==1
  360.     /* Set up transmitter */
  361.     #if defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__)
  362.     TCCR0A = (0<<COM0A1)|(0<<COM0A0)|(1<<WGM01)|(0<<WGM00);
  363.     TCCR0B = (0<<WGM02)|(1<<CS00)|(0<<CS01)|(0<<CS02);
  364.    
  365.     /* set up modulation frequency to 38kHz */
  366.     IR_MODULATION_REG = (((F_CPU/2000)/38) -1);
  367.  
  368.     /* start pwm generator */
  369.     TCCR0A |= (1<<COM0A0);
  370.     #endif
  371.  
  372. #endif
  373.  
  374. }
  375.  
  376. #if IR_TX_ENABLE==1
  377. 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)
  378. {
  379.     if (channel < 3)
  380.     {
  381.         drvIrTxChannel[channel].port=port;
  382.         drvIrTxChannel[channel].pinmask=(1<<nr);
  383.    
  384.         /* set up port as output */
  385.         *ddr |= (1<<nr);
  386.  
  387.         IR_OUTP_LOW();
  388.            
  389.         drvIrTxChannel[channel].callback = callback;
  390.         drvIrTxChannel[channel].enable = TRUE;
  391.         drvIrTxChannel[channel].timeoutEnable = FALSE;
  392.     }
  393. }
  394.  
  395. void IrTransceiver_Transmit(uint8_t channel, uint16_t *buffer, uint8_t length)
  396. {
  397.     if (length > 0)
  398.     {
  399.         if (drvIrTxChannel[channel].timeoutEnable == FALSE)
  400.         {
  401.             drvIrTxChannel[channel].timeoutEnable = TRUE;
  402.             drvIrTxChannel[channel].txbuf = buffer;
  403.             drvIrTxChannel[channel].txlen = length;
  404.             /* first value will be loaded directly to timer below */
  405.             drvIrTxChannel[channel].txindex = 1;
  406.            
  407.             drvIrTxChannel[channel].timeout = IR_COUNT_REG + drvIrTxChannel[channel].txbuf[0];
  408.             /* TODO: only modify timer reg if this channel has the lowest time left */
  409.             IR_COMPARE_REG = drvIrTxChannel[channel].timeout;
  410.  
  411.             IR_OUTP_HIGH();
  412.  
  413.             IR_UNMASK_COMPARE();
  414.         }
  415.     }
  416. }
  417. #endif
  418.  
  419.