Subversion Repositories HomeAutomation

Rev

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