Subversion Repositories HomeAutomation

Rev

Rev 548 | 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/receiver/irreceiver.h>
  15. #include <avr/io.h>
  16.  
  17. /*-----------------------------------------------------------------------------
  18.  * Globals
  19.  *---------------------------------------------------------------------------*/
  20. static uint16_t times[MAX_NR_TIMES];            //stores
  21. static uint8_t timesCounter=0;                  //counts the items in Times, always less then MAX_NR_TIMES
  22.  
  23. /*-----------------------------------------------------------------------------
  24.  * Prerequisites
  25.  *---------------------------------------------------------------------------*/
  26.  
  27.  
  28. /*-----------------------------------------------------------------------------
  29.  * Public Functions
  30.  *---------------------------------------------------------------------------*/
  31.  
  32.  
  33. /**
  34.  * Get an ir-time from the stored array, this can be used
  35.  * when a proper protocol is not found.
  36.  *
  37.  * @param index
  38.  *      Which time to get
  39.  * @return
  40.  *      The 16bit value at index index
  41.  */
  42. uint16_t getRawData(uint8_t index) {
  43.     return times[index];
  44. }
  45.  
  46. /**
  47.  * Get the number of stored ir-times in the array
  48.  *
  49.  * @return
  50.  *      The number of stored ir-times in the array
  51.  */
  52. uint8_t getRawDataCnt(void) {
  53.     return timesCounter;
  54. }
  55.  
  56. /**
  57.  * Test data on SIRC protocol, 12-bit version
  58.  * http://www.sbprojects.com/knowledge/ir/sirc.htm
  59.  *
  60.  * @param address
  61.  *      Pointer to store the address of the received data
  62.  * @param command
  63.  *      Pointer to store the command of the received data
  64.  * @return
  65.  *      IR_OK if data parsed successfully, one of several errormessages if not
  66.  */
  67. uint8_t testSIRC(uint8_t *address, uint8_t *command) {
  68.     /* parse times[], max is timesCounter */
  69.  
  70.     /* check if we have correct amount of data */
  71.     if (timesCounter != 25) {
  72.         return IR_NOT_CORRECT_DATA;
  73.     }
  74.    
  75.     /* check startbit */
  76.     if (times[0] > IR_SIRC_ST_BIT + IR_SIRC_ST_BIT/IR_SIRC_TOL_DIV || times[0] < IR_SIRC_ST_BIT - IR_SIRC_ST_BIT/IR_SIRC_TOL_DIV) {
  77.         return IR_NOT_CORRECT_DATA;
  78.     }
  79.    
  80.     uint16_t rawbits=0;
  81.    
  82.     for (uint8_t i = 1; i < timesCounter; i++) {
  83.         if ((i&1) == 1) {       /* if odd, ir-pause */
  84.             /* check length of pause between bits */
  85.             if (times[i] > IR_SIRC_LOW + IR_SIRC_LOW/IR_SIRC_TOL_DIV || times[i] < IR_SIRC_LOW - IR_SIRC_LOW/IR_SIRC_TOL_DIV) {
  86.                 return IR_NOT_CORRECT_DATA;
  87.             }
  88.         } else {            /* if even, ir-bit */
  89.             if (times[i] > IR_SIRC_HIGH_ONE - IR_SIRC_HIGH_ONE/IR_SIRC_TOL_DIV && times[i] < IR_SIRC_HIGH_ONE + IR_SIRC_HIGH_ONE/IR_SIRC_TOL_DIV) {
  90.                 /* write a one */
  91.                 rawbits |= 1<<((i-2)>>1);
  92.             } else if (times[i] > IR_SIRC_HIGH_ZERO - IR_SIRC_HIGH_ZERO/IR_SIRC_TOL_DIV && times[i] < IR_SIRC_HIGH_ZERO + IR_SIRC_HIGH_ZERO/IR_SIRC_TOL_DIV) {
  93.                 /* do nothing, a zero is already in rawbits */
  94.             } else {
  95.                 return IR_NOT_CORRECT_DATA;
  96.             }
  97.         }
  98.     }
  99.    
  100.     *command = ((uint8_t)rawbits&0x7f);
  101.     *address = ((uint8_t)(rawbits>>7)&0x1f);
  102.    
  103.     return IR_OK;
  104. }
  105.  
  106. /**
  107.  * Test data on RC5 protocol
  108.  * http://www.sbprojects.com/knowledge/ir/rc5.htm
  109.  *
  110.  * @param address
  111.  *      Pointer to store the address of the received data
  112.  * @param command
  113.  *      Pointer to store the command of the received data
  114.  * @return
  115.  *      IR_OK if data parsed successfully, one of several errormessages if not
  116.  */
  117. uint8_t testRC5(uint8_t *address, uint8_t *command) {
  118.     uint8_t halfbitscnt = 1;
  119.     uint16_t rawbits = 0;
  120.    
  121.     for (uint8_t i = 0; i<timesCounter; i++) {
  122.         //halfbitscnt&1==1 in the middle of bits
  123.         //i&1==0 positive flank
  124.  
  125.         if ((halfbitscnt&1)==1 && (i&1)==0) {       /* in the middle of bit AND a positve flank */
  126.             rawbits |= (1<<(13-(halfbitscnt>>1)));
  127.         }
  128.        
  129.         if (times[i] > IR_RC5_HALF_BIT - IR_RC5_HALF_BIT/IR_RC5_TOL_DIV && times[i] < IR_RC5_HALF_BIT + IR_RC5_HALF_BIT/IR_RC5_TOL_DIV) {
  130.             halfbitscnt += 1;
  131.         } else if (times[i] > IR_RC5_BIT - IR_RC5_BIT/IR_RC5_TOL_DIV && times[i] < IR_RC5_BIT + IR_RC5_BIT/IR_RC5_TOL_DIV) {
  132.             halfbitscnt += 2;
  133.         } else {
  134.             return IR_NOT_CORRECT_DATA;
  135.         }
  136.        
  137.     }
  138.  
  139.     *command = ((uint8_t)rawbits&0x3f);
  140.     *address = ((uint8_t)(rawbits>>6)&0x7f);   
  141.  
  142.     //support RC5-extended by putting the inversion of startbit 2 as the 7th commandbit
  143.     *command |= (~(*address) & 0x40);
  144.     *address &= 0x1f;       //remove togglebit and both startbits from address
  145.    
  146.     return IR_OK;
  147. }
  148.  
  149. /**
  150.  * Test data on SHARP protocol
  151.  * http://www.sbprojects.com/knowledge/ir/sharp.htm
  152.  *
  153.  * @param address
  154.  *      Pointer to store the address of the received data
  155.  * @param command
  156.  *      Pointer to store the command of the received data
  157.  * @return
  158.  *      IR_OK if data parsed successfully, one of several errormessages if not
  159.  */
  160. uint8_t testSharp(uint8_t *address, uint8_t *command) {
  161.     /* parse times[], max is timesCounter */
  162.  
  163.     /* check if we have correct amount of data */
  164.     if (timesCounter != 31) {
  165.         return IR_NOT_CORRECT_DATA;
  166.     }
  167.    
  168.     uint16_t rawbits=0;
  169.    
  170.     for (uint8_t i = 1; i < timesCounter; i++) {
  171.         if ((i&1) == 1) {       /* if odd, ir-pause */
  172.             /* check length of pause between bits */
  173.             if (times[i] > IR_SHARP_LOW_ONE - IR_SHARP_LOW_ONE/IR_SHARP_TOL_DIV && times[i] < IR_SHARP_LOW_ONE + IR_SHARP_LOW_ONE/IR_SHARP_TOL_DIV) {
  174.                 /* write a one */
  175.                 rawbits |= 1<<((i-1)>>1);
  176.             } else if (times[i] > IR_SHARP_LOW_ZERO - IR_SHARP_LOW_ZERO/IR_SHARP_TOL_DIV && times[i] < IR_SHARP_LOW_ZERO + IR_SHARP_LOW_ZERO/IR_SHARP_TOL_DIV) {
  177.                 /* do nothing, a zero is already in rawbits */
  178.             } else {
  179.                 return IR_NOT_CORRECT_DATA;
  180.             }
  181.         } else {            /* if even, ir-bit */
  182.             if (times[i] > IR_SHARP_HIGH + IR_SHARP_HIGH/IR_SHARP_TOL_DIV || times[i] < IR_SHARP_HIGH - IR_SHARP_HIGH/IR_SHARP_TOL_DIV) {
  183.                 return IR_NOT_CORRECT_DATA;
  184.             }
  185.         }
  186.     }
  187.    
  188.     *command = ((uint8_t)(rawbits>>5)&0xff);
  189.     *address = ((uint8_t)rawbits&0x1f);
  190.    
  191.     return IR_OK;
  192. }
  193.  
  194. /**
  195.  * Test data on NEC protocol
  196.  * http://www.sbprojects.com/knowledge/ir/nec.htm
  197.  *
  198.  * @param address
  199.  *      Pointer to store the address of the received data
  200.  * @param command
  201.  *      Pointer to store the command of the received data
  202.  * @return
  203.  *      IR_OK if data parsed successfully, one of several errormessages if not
  204.  */
  205. uint8_t testNEC(uint8_t *address, uint8_t *command) {
  206.     /* parse times[], max is timesCounter */
  207.  
  208.     /* check if we have correct amount of data */
  209.     if (timesCounter != 67) {
  210.         return IR_NOT_CORRECT_DATA;
  211.     }
  212.    
  213.     /* check startbit */
  214.     if (times[0] > IR_NEC_ST_BIT + IR_NEC_ST_BIT/IR_NEC_TOL_DIV || times[0] < IR_NEC_ST_BIT - IR_NEC_ST_BIT/IR_NEC_TOL_DIV) {
  215.         return IR_NOT_CORRECT_DATA;
  216.     }
  217.  
  218.     /* check pause after startbit */
  219.     if (times[1] > IR_NEC_ST_PAUSE + IR_NEC_ST_PAUSE/IR_NEC_TOL_DIV || times[1] < IR_NEC_ST_PAUSE - IR_NEC_ST_PAUSE/IR_NEC_TOL_DIV) {
  220.         return IR_NOT_CORRECT_DATA;
  221.     }
  222.  
  223.     *command = 0;
  224.     *address = 0;
  225.    
  226.     for (uint8_t i = 3; i < timesCounter; i++) {
  227.         if ((i&1) == 1) {       /* if odd, ir-pause */
  228.             /* check length of pause between bits */
  229.             if (times[i] > IR_NEC_LOW_ONE - IR_NEC_LOW_ONE/IR_NEC_TOL_DIV && times[i] < IR_NEC_LOW_ONE + IR_NEC_LOW_ONE/IR_NEC_TOL_DIV) {
  230.                 if (i>2 && i<18) {
  231.                     /* write a one */
  232.                     *address |= 1<<((i-3)>>1);
  233.                 }
  234.                 if (i>34 && i<50) {
  235.                     /* write a one */
  236.                     *command |= 1<<((i-35)>>1);
  237.                 }
  238.             } else if (times[i] > IR_NEC_LOW_ZERO - IR_NEC_LOW_ZERO/IR_NEC_TOL_DIV && times[i] < IR_NEC_LOW_ZERO + IR_NEC_LOW_ZERO/IR_NEC_TOL_DIV) {
  239.                 /* do nothing, a zero is already in rawbits */
  240.             } else {
  241.                 return IR_NOT_CORRECT_DATA;
  242.             }
  243.         } else {            /* if even, ir-bit */
  244.             if (times[i] > IR_NEC_HIGH + IR_NEC_HIGH/IR_NEC_TOL_DIV || times[i] < IR_NEC_HIGH - IR_NEC_HIGH/IR_NEC_TOL_DIV) {
  245.                 return IR_NOT_CORRECT_DATA;
  246.             }
  247.         }
  248.     }
  249.    
  250.     return IR_OK;
  251. }
  252.  
  253.  
  254. /**
  255.  * Test data on Samsung protocol
  256.  * Very much like NEC, different start bit/pause lengths etc.
  257.  * http://www.sbprojects.com/knowledge/ir/nec.htm
  258.  *
  259.  * @param address
  260.  *      Pointer to store the address of the received data
  261.  * @param command
  262.  *      Pointer to store the command of the received data
  263.  * @return
  264.  *      IR_OK if data parsed successfully, one of several errormessages if not
  265.  */
  266. uint8_t testSamsung(uint8_t *address, uint8_t *command) {
  267.     /* parse times[], max is timesCounter */
  268.  
  269.     /* check if we have correct amount of data */
  270.     if (timesCounter != 67) {
  271.         return IR_NOT_CORRECT_DATA;
  272.     }
  273.    
  274.     /* check startbit */
  275.     if (times[0] > IR_SAMS_ST_BIT + IR_SAMS_ST_BIT/IR_SAMS_TOL_DIV || times[0] < IR_SAMS_ST_BIT - IR_SAMS_ST_BIT/IR_SAMS_TOL_DIV) {
  276.         return IR_NOT_CORRECT_DATA;
  277.     }
  278.  
  279.     /* check pause after startbit */
  280.     if (times[1] > IR_SAMS_ST_PAUSE + IR_SAMS_ST_PAUSE/IR_SAMS_TOL_DIV || times[1] < IR_SAMS_ST_PAUSE - IR_SAMS_ST_PAUSE/IR_SAMS_TOL_DIV) {
  281.         return IR_NOT_CORRECT_DATA;
  282.     }
  283.  
  284.     *command = 0;
  285.     *address = 0;
  286.    
  287.     for (uint8_t i = 2; i < timesCounter; i++) {
  288.         if ((i&1) == 1) {       /* if odd, ir-pause */
  289.             /* check length of pause between bits */
  290.             if (times[i] > IR_SAMS_LOW_ONE - IR_SAMS_LOW_ONE/IR_SAMS_TOL_DIV && times[i] < IR_SAMS_LOW_ONE + IR_SAMS_LOW_ONE/IR_SAMS_TOL_DIV) {
  291.                 if (i>2 && i<18) {
  292.                     /* write a one */
  293.                     *address |= 1<<((i-3)>>1);
  294.                 }
  295.                 if (i>34 && i<50) {
  296.                     /* write a one */
  297.                     *command |= 1<<((i-35)>>1);
  298.                 }
  299.             } else if (times[i] > IR_SAMS_LOW_ZERO - IR_SAMS_LOW_ZERO/IR_SAMS_TOL_DIV && times[i] < IR_SAMS_LOW_ZERO + IR_SAMS_LOW_ZERO/IR_SAMS_TOL_DIV) {
  300.                 /* do nothing, a zero is already in rawbits */
  301.             } else {
  302.                 return IR_NOT_CORRECT_DATA;
  303.             }
  304.         } else {            /* if even, ir-bit */
  305.             if (times[i] > IR_SAMS_HIGH + IR_SAMS_HIGH/IR_SAMS_TOL_DIV || times[i] < IR_SAMS_HIGH - IR_SAMS_HIGH/IR_SAMS_TOL_DIV) {
  306.                 return IR_NOT_CORRECT_DATA;
  307.             }
  308.         }
  309.     }
  310.    
  311.     return IR_OK;
  312. }
  313.  
  314. uint8_t IrReceive_CheckIR(uint8_t *proto, uint8_t *address, uint8_t *command, uint16_t *timeout) {
  315.     if (IRPIN & (1<<IRBIT)) return IR_NO_DATA;      //om irmodulen ger en etta så återgå
  316.    
  317.     initTimer();
  318.    
  319.     //this routine should sample the timings for received irdata
  320.     timesCounter = 0;
  321.    
  322.     uint8_t gotTimout = 0;  // a timeout is a very long break in irdata (such as occurs between ir frames)
  323.     while (!gotTimout && timesCounter < MAX_NR_TIMES-1) { //loop as long as no timeout occured and not to many pulses received
  324.         setTimerVal(TIM_OVFL_RELOAD_VAL);
  325.         //wait for positiv slope, while checking timer overflow
  326.         while (!(IRPIN & (1<<IRBIT))) {
  327.             //if timeout (if timer-ovflow-flaggan is set)
  328.             if (isTimerOvfl() == 1) return IR_TIME_OVFL;    //this timeout is not good (irsignal low which means active)
  329.         }
  330.        
  331.         times[timesCounter] = getTimerVal()-TIM_OVFL_RELOAD_VAL;
  332.         //TODO: should we check times[timesCounter] so its a realistic time-value? use IR_MIN_PULSE_WIDTH
  333.         timesCounter++;
  334.        
  335.         setTimerVal(TIM_OVFL_RELOAD_VAL);
  336.         //wait for negative slope, while checking timer overflow
  337.         while ((IRPIN & (1<<IRBIT)) && !gotTimout) {
  338.             //om timeout (om timer-ovflow-flaggan sätt)
  339.             if (isTimerOvfl() == 1) gotTimout=1;    //return IR_TIME_OVFL;
  340.         }
  341.  
  342.         if (!gotTimout) {
  343.             times[timesCounter] = getTimerVal()-TIM_OVFL_RELOAD_VAL;
  344.             //TODO: should we check times[timesCounter] so its a realistic time-value?
  345.             timesCounter++;
  346.         }
  347.     }
  348.     if (timesCounter >= MAX_NR_TIMES-1) {
  349.         //to much irdata, not good, abort
  350.         return IR_TO_MUCH_DATA;
  351.     }
  352.    
  353.     if (testSIRC(&*address, &*command) == IR_OK) {
  354.         *proto = IR_PROTO_SIRC;
  355.         *timeout = IR_SIRC_REPETITION;
  356.         return IR_OK;
  357.     } else if (testRC5(&*address, &*command) == IR_OK) {
  358.         *proto = IR_PROTO_RC5;
  359.         *timeout = IR_RC5_REPETITION;
  360.         return IR_OK;
  361.     } else if (testSharp(&*address, &*command) == IR_OK) {
  362.         *proto = IR_PROTO_SHARP;
  363.         *timeout = IR_SHARP_REPETITION;
  364.         return IR_OK;
  365.     } else if (testNEC(&*address, &*command) == IR_OK) {
  366.         *proto = IR_PROTO_NEC;
  367.         *timeout = IR_NEC_REPETITION;
  368.         return IR_OK;
  369.     } else if (testSamsung(&*address, &*command) == IR_OK) {
  370.         *proto = IR_PROTO_SAMS;
  371.         *timeout = IR_SAMS_REPETITION;
  372.         return IR_OK;
  373.     }
  374.        
  375.     return IR_NO_PROTOCOL;
  376.    
  377. }
  378.  
  379. //TODO: skriv doxygen-header som för de andra funktionerna
  380. /**
  381.  *
  382.  *
  383.  *
  384.  *
  385.  */
  386. void IrReceive_Init(void) {
  387.     IRDDR &= ~(1<<IRBIT);
  388. }
  389.  
  390. //varför är denna funktion så komplex? jo den filtrerar bort för korta ir-pulser
  391. //TODO: skriv doxygen-header som för de andra funktionerna
  392. uint8_t IrReceive_CheckIdle(void) {
  393.     if (IRPIN & (1<<IRBIT)) return IR_NO_DATA;      //om irmodulen ger en etta så återgå
  394.    
  395.     //nu lägger irmodulen ut en nolla, "startbiten" alltså
  396.    
  397.     uint16_t timerVal;
  398.    
  399.     //Läs in längden på startbiten
  400.     initTimer();
  401.     while (!(IRPIN & (1<<IRBIT))) {     //vänta på att irmodulen lägger ut en etta
  402.         //om timeout (om timer-ovflow-flaggan sätt)
  403.         if (isTimerOvfl() == 1) return IR_TIME_OVFL;
  404.     }
  405.     timerVal = getTimerVal();
  406.    
  407.     if ((timerVal < IR_MAX_PULSE_WIDTH) && (timerVal > IR_MIN_PULSE_WIDTH)) {
  408.         return IR_OK;
  409.     } //else if ...
  410.    
  411.    
  412.     return IR_NO_PROTOCOL;
  413. }
  414.