Subversion Repositories HomeAutomation

Rev

Rev 568 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /**
  2.  * IR receiver driver.
  3.  *
  4.  * @date    2006-12-10
  5.  *
  6.  * @author  Anders Runeson
  7.  *  
  8.  */
  9.  
  10. /*-----------------------------------------------------------------------------
  11.  * Includes
  12.  *---------------------------------------------------------------------------*/
  13. #include <config.h>
  14. #include <drivers/ir/transceiver/irtransceiver.h>
  15. #include <avr/io.h>
  16. #include <avr/interrupt.h>
  17.  
  18. /*-----------------------------------------------------------------------------
  19.  * Globals
  20.  *---------------------------------------------------------------------------*/
  21. //static uint16_t times[MAX_NR_TIMES];          //stores
  22. uint16_t *rxbuf, *txbuf;       
  23. uint8_t rxlen, txlen;
  24. //static uint8_t timesCounter=0;                    //counts the items in Times, always less then MAX_NR_TIMES
  25. //static uint8_t timesIndex;                        //selects the pulse width in Times to send
  26. volatile uint8_t data_received;
  27. volatile uint8_t data_transmitted;
  28. uint8_t detect_edge;
  29. uint8_t store;
  30.  
  31. /*-----------------------------------------------------------------------------
  32.  * Prerequisites
  33.  *---------------------------------------------------------------------------*/
  34. #if defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__)
  35. #define TIMSK1  TIMSK
  36. #define TIFR1   TIFR
  37. #define ICIE1   TICIE1
  38. #endif
  39.  
  40. #define IR_COMPARE_VECTOR       TIMER1_COMPB_vect
  41. #define IR_TIMEOUT_VECTOR       TIMER1_COMPA_vect
  42. #define IR_CAPTURE_VECTOR       TIMER1_CAPT_vect
  43. #define IR_TIMEOUT_REG          OCR1A
  44. #define IR_COMPARE_REG          OCR1B
  45. #define IR_CAPTURE_REG          ICR1
  46. #define IR_COUNT_REG            TCNT1
  47. #define IR_TIMER_INIT()         TCCR1A = 0; \
  48.                                 TCCR1B = (1<<ICNC1)|(2<<CS10);
  49. #define IR_MASK_COMPARE()       TIMSK1 &= ~(1<<OCIE1B);
  50. #define IR_UNMASK_COMPARE()     TIFR1 = (1<<OCF1B); TIMSK1 |= (1<<OCIE1B);
  51. #define IR_MASK_TIMEOUT()       TIMSK1 &= ~(1<<OCIE1A);
  52. #define IR_UNMASK_TIMEOUT()     TIFR1 = (1<<OCF1A); TIMSK1 |= (1<<OCIE1A);
  53. #define IR_MASK_CAPTURE()       TIMSK1 &= ~(1<<ICIE1);
  54. #define IR_UNMASK_CAPTURE()     TIFR1 = (1<<ICF1); TIMSK1 |= (1<<ICIE1);
  55. #define IR_CAPTURE_FALLING()    TCCR1B &= ~(1<<ICES1); \
  56.                                 TIFR1 = (1<<ICF1);
  57. #define IR_CAPTURE_RISING()     TCCR1B |= (1<<ICES1); \
  58.                                 TIFR1 = (1<<ICF1);
  59.  
  60. #define IR_RX_ACTIVE_LOW    1
  61. #define IR_TX_ACTIVE_LOW    1
  62.  
  63. /*-----------------------------------------------------------------------------
  64.  * Interrupt Handlers
  65.  *---------------------------------------------------------------------------*/
  66.  
  67. ISR(IR_COMPARE_VECTOR)
  68. {
  69.     PORTC ^= (1<<PC5);
  70.     if (timesIndex < timesCounter)
  71.     {
  72.         IR_COMPARE_REG += times[timesIndex++];     
  73.     }
  74.     else
  75.     {
  76.         IR_MASK_COMPARE();
  77.         data_transmitted = 1;
  78.     }
  79. }
  80.  
  81. ISR(IR_TIMEOUT_VECTOR)
  82. {
  83.     if (timesCounter)
  84.     {
  85.         /* Disable interrupts until the application has taken action on the
  86.          * current data and reenabled reception. */
  87.         IR_MASK_CAPTURE();
  88.         IR_MASK_TIMEOUT();
  89.         /* Notify the application that a pulse train has been received. */
  90.         data_received = 1;
  91.     }
  92.     store = 0;
  93. }
  94.  
  95. ISR(IR_CAPTURE_VECTOR)
  96. {
  97.     static uint16_t prev_time;
  98.     uint16_t pulsewidth;
  99.  
  100.     /* Read the measured transition time from the capture register. */
  101.     uint16_t time = IR_CAPTURE_REG;
  102.    
  103.     /* Toggle the edge detection. */
  104.     if (detect_edge == 0)
  105.     {
  106.         IR_CAPTURE_RISING();
  107.         detect_edge = 1;
  108.     }
  109.     else
  110.     {
  111.         IR_CAPTURE_FALLING();
  112.         detect_edge = 0;
  113.     }
  114.    
  115.     /* Subtract the current measurement from the previous to get the pulse
  116.      * width. */
  117.     pulsewidth = time - prev_time;
  118.     prev_time = time;
  119.    
  120.     /* Set the timeout. */
  121.     IR_TIMEOUT_REG = time + IR_MAX_PULSE_WIDTH;
  122.    
  123.     if (store)
  124.     {
  125.         /* Store the measurement. */
  126.         times[timesCounter++] = pulsewidth;
  127.         /* Disable future measurements if we've filled the buffer. */
  128.         //TODO: Report overflow to application
  129.         if (timesCounter == MAX_NR_TIMES)
  130.         {
  131.             IR_MASK_CAPTURE();
  132.         }
  133.     }
  134.     else
  135.     {
  136.         /* The first edge of the pulse train has been detected. Enable the
  137.          * storage of the following pulsewidths. */
  138.         store = 1;
  139.         /* Enable timeout interrupt for detection of the end of the pulse
  140.          * train. */
  141.         IR_UNMASK_TIMEOUT();
  142.     }
  143. }
  144.  
  145.  
  146. /*-----------------------------------------------------------------------------
  147.  * Public Functions
  148.  *---------------------------------------------------------------------------*/
  149.  
  150. void IrTransceiver_Init(void)
  151. {
  152.     IR_TIMER_INIT();
  153.     IR_TIMEOUT_REG = IR_MAX_PULSE_WIDTH;
  154.     IRDDR &= ~(1<<IRBIT);
  155.     DDRC |= (1<<PC5);
  156. }
  157.  
  158. void IrTransceiver_Start(uint16_t *buffer)
  159. {
  160.     /* Setup buffer and arm the edge detection. */
  161.     rxbuf = buffer;
  162.     rxlen = 0;
  163.     data_received = 0;
  164.     store = 0;
  165. #if (IR_RX_ACTIVE_LOW == 1)
  166.     IR_CAPTURE_FALLING();
  167.     detect_edge = 0;
  168. #else
  169.     IR_CAPTURE_RISING();
  170.     detect_edge = 1;
  171. #endif
  172.     IR_UNMASK_CAPTURE();
  173. }
  174.  
  175. uint8_t IrTransceiver_Poll(void)
  176. {
  177.     if (data_received)
  178.     {
  179.         return rxlen;
  180.     }
  181.     else
  182.     {
  183.         return 0;
  184.     }
  185. }
  186.  
  187. uint8_t IrTransceiver_Transmit(uint16_t *buffer, uint8_t length)
  188. {
  189.     data_transmitted = 0;
  190.     if (timesCounter == 0) return IR_NO_DATA;
  191.     timesIndex = 1;
  192.     IR_COMPARE_REG = IR_COUNT_REG + times[0];
  193. #if (IR_RX_ACTIVE_LOW == 1)
  194.     PORTC &= ~(1<<PC5);
  195. #else
  196.     PORTC |= (1<<PC5);
  197. #endif
  198.     IR_UNMASK_COMPARE();
  199.    
  200.     while (!data_transmitted);
  201.    
  202.     return IR_OK;
  203. }
  204.  
  205. /* Behöver denna verkligen användas numer? Isf, kan samma sak implementeras
  206.  * i applikationens tillståndsmaskin/main-loop med hjälp av standard timer.h
  207.  * för timeout-funktioner? */
  208. #if 0
  209. //varför är denna funktion så komplex? jo den filtrerar bort korta ir-pulser
  210. //TODO: skriv doxygen-header som för de andra funktionerna
  211. uint8_t IrReceive_CheckIdle(void) {
  212.     if (IRPIN & (1<<IRBIT)) return IR_NO_DATA;      //om irmodulen ger en etta så återgå
  213.    
  214.     //nu lägger irmodulen ut en nolla, "startbiten" alltså
  215.    
  216.     uint16_t timerVal;
  217.    
  218.     //Läs in längden på startbiten
  219.     initTimer();
  220.     while (!(IRPIN & (1<<IRBIT))) {     //vänta på att irmodulen lägger ut en etta
  221.         //om timeout (om timer-ovflow-flaggan sätt)
  222.         if (isTimerOvfl() == 1) return IR_TIME_OVFL;
  223.     }
  224.     timerVal = getTimerVal();
  225.    
  226.     if ((timerVal < IR_MAX_PULSE_WIDTH) && (timerVal > IR_MIN_PULSE_WIDTH)) {
  227.         return IR_OK;
  228.     } //else if ...
  229.    
  230.    
  231.     return IR_NO_PROTOCOL;
  232. }
  233. #endif
  234.