| 1 | /* $Id: ircontrol.c,v 1.3 2010/06/27 22:49:58 simimeie Exp $ |
| 2 | * Functions for the infrared receiver |
| 3 | * |
| 4 | * The infrared receiver is connected to PB0 / PCINT0. |
| 5 | */ |
| 6 | |
| 7 | #include <avr/io.h> |
| 8 | #include <avr/interrupt.h> |
| 9 | #include "ircontrol.h" |
| 10 | #include "timers.h" |
| 11 | #include "console.h" |
| 12 | |
| 13 | /* NOTE1: Note that the signal we get from the sensor is inverted. If we |
| 14 | * read a zero, it means there was infrared on, if we read a one, infrared |
| 15 | * is off. |
| 16 | * NOTE2: Only NEC is implemented here right now, because MY remote uses |
| 17 | * that protocol. However, there may be references to RC5 because I had |
| 18 | * already thought about that and just left them for possible future use. */ |
| 19 | |
| 20 | /* For RC5, one bit length is 1778 us, when it toggles we see half |
| 21 | * of it, i.e. 889 us. |
| 22 | * that equals around 7100 cpu cycles at 8 MHz. */ |
| 23 | #define RC5HALFLENINCYCLES ((CPUFREQ * 889UL) / 1000000UL) |
| 24 | |
| 25 | /* For NEC, we start with a 9000 us pulse, then 4500 us silence. |
| 26 | * Then the bits follow: |
| 27 | * a 1 is a 560 us pulse followed by 1690 us of silence. |
| 28 | * a 0 is a 560 us pulse followed by 560 us of silence. |
| 29 | * These values equal the following cpu cycle counts: |
| 30 | * 9000 us = 72000 cc, 4500 us = 36000 cc, 560 us = 4480, 1690 us = 13520 cc |
| 31 | */ |
| 32 | #define NECSTARTLEN1 ((CPUFREQ * 9UL) / 1000UL) |
| 33 | #define NECSTARTLEN2 ((CPUFREQ * 45UL) / 10000UL) |
| 34 | #define NECPULSELEN ((CPUFREQ * 56UL) / 100000UL) |
| 35 | #define NECZEROLEN ((CPUFREQ * 112UL) / 100000UL) |
| 36 | #define NECONELEN ((CPUFREQ * 225UL) / 100000UL) |
| 37 | |
| 38 | /* the NEC code contains 4 bytes, sent with LSB first: |
| 39 | * 0+1 are either the "extended address" or "address and inverted address". |
| 40 | * 2 is the command code |
| 41 | * 3 is the inverted command code |
| 42 | */ |
| 43 | |
| 44 | static struct timestamp last0irqts; |
| 45 | static struct timestamp last1irqts; |
| 46 | static uint8_t lastpin = 0; |
| 47 | static uint8_t codebytes[4]; |
| 48 | static uint8_t curcodebit = 0xff; |
| 49 | |
| 50 | /* some example codes |
| 51 | root@moodlight# !NSB! 11111111 00001000 11011111 00100000 (r) |
| 52 | root@moodlight# !NSB! 11111111 00001000 01011111 10100000 (g) |
| 53 | root@moodlight# !NSB! 11111111 00001000 10011111 01100000 (b) |
| 54 | root@moodlight# !NSB! 11111111 00001000 00011111 11100000 (w) |
| 55 | */ |
| 56 | |
| 57 | ISR(PCINT0_vect) { |
| 58 | uint8_t v; |
| 59 | struct timestamp curirqts; |
| 60 | uint32_t ts1diff; /* distance from last 1 */ |
| 61 | uint32_t ts0diff; /* distance from last 0 */ |
| 62 | |
| 63 | v = PINB & _BV(PB0); |
| 64 | if (v == lastpin) { /* No change visible - spurious interrupt */ |
| 65 | return; |
| 66 | } |
| 67 | curirqts = gettimestamp_noirq(); |
| 68 | ts1diff = ((uint32_t)curirqts.ticks << 16) + curirqts.partticks; |
| 69 | ts0diff = ts1diff; |
| 70 | ts1diff -= ((uint32_t)last1irqts.ticks << 16) + last1irqts.partticks; |
| 71 | ts0diff -= ((uint32_t)last0irqts.ticks << 16) + last0irqts.partticks; |
| 72 | if (v) { /* Infrared just went away! */ |
| 73 | if ((ts1diff >= (( 8 * NECSTARTLEN1) / 10)) |
| 74 | && (ts1diff <= ((12 * NECSTARTLEN1) / 10))) { |
| 75 | /* NEC start bit */ |
| 76 | /* console_printpgm_P(PSTR("!NSB!")); */ |
| 77 | curcodebit = 0xfe; /* Wait for second part of start sequence */ |
| 78 | } else { |
| 79 | if (curcodebit <= 32) { /* We're in a decoding attempt, so */ |
| 80 | /* Check pulse length */ |
| 81 | if ((ts1diff < (( 8 * NECPULSELEN) / 10)) |
| 82 | || (ts1diff > ((12 * NECPULSELEN) / 10))) { |
| 83 | /* WRONG */ |
| 84 | curcodebit = 0xff; |
| 85 | } |
| 86 | } |
| 87 | if (curcodebit == 32) { |
| 88 | if (codebytes[2] != (codebytes[3] ^ 0xff)) { |
| 89 | console_printpgm_P(PSTR("!CRC!")); |
| 90 | } else { |
| 91 | /* Successful decode! */ |
| 92 | console_printpgm_P(PSTR(" DEC>")); |
| 93 | console_printhex8(codebytes[0]); |
| 94 | console_printhex8(codebytes[1]); |
| 95 | console_printhex8(codebytes[2]); |
| 96 | console_printhex8(codebytes[3]); |
| 97 | } |
| 98 | } |
| 99 | } |
| 100 | last0irqts = curirqts; |
| 101 | } else { /* Infrared went on */ |
| 102 | if ((ts1diff >= (( 8 * NECZEROLEN) / 10)) |
| 103 | && (ts1diff <= ((12 * NECZEROLEN) / 10))) { |
| 104 | /* console_printpgm_P(PSTR("0")); */ |
| 105 | if (curcodebit < 32) { |
| 106 | curcodebit++; |
| 107 | } |
| 108 | } else if ((ts1diff >= (( 8 * NECONELEN) / 10)) |
| 109 | && (ts1diff <= ((12 * NECONELEN) / 10))) { |
| 110 | /* console_printpgm_P(PSTR("1")); */ |
| 111 | if (curcodebit < 32) { |
| 112 | codebytes[curcodebit >> 3] |= (1 << (curcodebit & 0x07)); |
| 113 | curcodebit++; |
| 114 | } else { |
| 115 | curcodebit = 0xff; |
| 116 | } |
| 117 | } else if ((ts0diff >= (( 8 * NECSTARTLEN2) / 10)) |
| 118 | && (ts0diff <= ((12 * NECSTARTLEN2) / 10))) { |
| 119 | if (curcodebit == 0xfe) { /* voila, correct start sequence */ |
| 120 | curcodebit = 0; |
| 121 | codebytes[0] = codebytes[1] = codebytes[2] = codebytes[3] = 0; |
| 122 | } |
| 123 | } |
| 124 | last1irqts = curirqts; |
| 125 | } |
| 126 | #if 0 |
| 127 | console_printpgm_P(PSTR("!")); |
| 128 | console_printhex8(tsdiff >> 24); |
| 129 | console_printhex8(tsdiff >> 16); |
| 130 | console_printhex8(tsdiff >> 8); |
| 131 | console_printhex8(tsdiff >> 0); |
| 132 | console_printpgm_P(PSTR("!")); |
| 133 | #endif |
| 134 | #if 0 |
| 135 | if (tsdiff > ((24 * HALFRC5LENINCYCLES) / 10)) { |
| 136 | /* Start of new transmission */ |
| 137 | console_printpgm_P(PSTR("!1[")); |
| 138 | console_printhex8(v); |
| 139 | lastbit = 1; |
| 140 | } else if (tsdiff > ((15 * HALFRC5LENINCYCLES) / 10)) { |
| 141 | /* Different bit than last time */ |
| 142 | lastbit = !lastbit; |
| 143 | if (lastbit) { |
| 144 | console_printpgm_P(PSTR("1")); |
| 145 | } else { |
| 146 | console_printpgm_P(PSTR("0")); |
| 147 | } |
| 148 | } else if ((tsdiff < ((15 * HALFRC5LENINCYCLES) / 10)) |
| 149 | && (tsdiff > (( 5 * HALFRC5LENINCYCLES) / 10))) { |
| 150 | /* Same bit as last time */ |
| 151 | if (lastbit) { |
| 152 | console_printpgm_P(PSTR("1")); |
| 153 | } else { |
| 154 | console_printpgm_P(PSTR("0")); |
| 155 | } |
| 156 | } |
| 157 | #endif |
| 158 | lastpin = v; |
| 159 | } |
| 160 | |
| 161 | void ircontrol_init(void) |
| 162 | { |
| 163 | /* Activate pullup */ |
| 164 | PORTB |= _BV(PB0); |
| 165 | /* enable PCINT0 */ |
| 166 | PCICR |= _BV(PCIE0); |
| 167 | /* Enable pin change interrupt 0 (=PB0) in pcint0 */ |
| 168 | PCMSK0 |= _BV(PCINT0); |
| 169 | } |