Subversion Repositories HomeAutomation

Rev

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