Subversion Repositories HomeAutomation

Rev

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