RemoteIR.

Dependents:   RemoteIR_TestProgram SerialGPS_TestProgram StarBoardOrangeExpansion1 Door_Slamming_Device ... more

Committer:
shintamainjp
Date:
Tue Aug 17 08:50:54 2010 +0000
Revision:
0:ec264f4ce158
Child:
1:4adf16017a0f

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
shintamainjp 0:ec264f4ce158 1 /**
shintamainjp 0:ec264f4ce158 2 * IR receiver (Version 0.0.3)
shintamainjp 0:ec264f4ce158 3 *
shintamainjp 0:ec264f4ce158 4 * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
shintamainjp 0:ec264f4ce158 5 * http://shinta.main.jp/
shintamainjp 0:ec264f4ce158 6 */
shintamainjp 0:ec264f4ce158 7
shintamainjp 0:ec264f4ce158 8 #include "ReceiverIR.h"
shintamainjp 0:ec264f4ce158 9
shintamainjp 0:ec264f4ce158 10 #define IRQ_ENABLE() sem.release(); __enable_irq()
shintamainjp 0:ec264f4ce158 11 #define IRQ_DISABLE() sem.take(); __disable_irq()
shintamainjp 0:ec264f4ce158 12
shintamainjp 0:ec264f4ce158 13 #define InRange(x,y) ((((y) * 0.7) < (x)) && ((x) < ((y) * 1.3)))
shintamainjp 0:ec264f4ce158 14
shintamainjp 0:ec264f4ce158 15 ReceiverIR::ReceiverIR(PinName rxpin) : evt(rxpin) {
shintamainjp 0:ec264f4ce158 16 }
shintamainjp 0:ec264f4ce158 17
shintamainjp 0:ec264f4ce158 18 ReceiverIR::~ReceiverIR() {}
shintamainjp 0:ec264f4ce158 19
shintamainjp 0:ec264f4ce158 20 void ReceiverIR::init(void) {
shintamainjp 0:ec264f4ce158 21 IRQ_DISABLE();
shintamainjp 0:ec264f4ce158 22 evt.fall(this, &ReceiverIR::isr_fall);
shintamainjp 0:ec264f4ce158 23 evt.rise(this, &ReceiverIR::isr_rise);
shintamainjp 0:ec264f4ce158 24 evt.mode(PullUp);
shintamainjp 0:ec264f4ce158 25 ticker.attach_us(this, &ReceiverIR::isr_wdt, 10 * 1000);
shintamainjp 0:ec264f4ce158 26 init_state();
shintamainjp 0:ec264f4ce158 27 IRQ_ENABLE();
shintamainjp 0:ec264f4ce158 28 }
shintamainjp 0:ec264f4ce158 29
shintamainjp 0:ec264f4ce158 30 ReceiverIR::State ReceiverIR::getState() {
shintamainjp 0:ec264f4ce158 31 IRQ_DISABLE();
shintamainjp 0:ec264f4ce158 32 State s = data.state;
shintamainjp 0:ec264f4ce158 33 IRQ_ENABLE();
shintamainjp 0:ec264f4ce158 34 wait_ms(100);
shintamainjp 0:ec264f4ce158 35 return s;
shintamainjp 0:ec264f4ce158 36 }
shintamainjp 0:ec264f4ce158 37
shintamainjp 0:ec264f4ce158 38 int ReceiverIR::getData(RemoteIR::Format *format, uint8_t *buf, int bufsiz) {
shintamainjp 0:ec264f4ce158 39 IRQ_DISABLE();
shintamainjp 0:ec264f4ce158 40
shintamainjp 0:ec264f4ce158 41 const int bitcount = data.bitcount;
shintamainjp 0:ec264f4ce158 42 const int n = bitcount / 8 + (((bitcount % 8) != 0) ? 1 : 0);
shintamainjp 0:ec264f4ce158 43 if (bufsiz < n) {
shintamainjp 0:ec264f4ce158 44 IRQ_ENABLE();
shintamainjp 0:ec264f4ce158 45 return -1;
shintamainjp 0:ec264f4ce158 46 }
shintamainjp 0:ec264f4ce158 47
shintamainjp 0:ec264f4ce158 48 *format = data.format;
shintamainjp 0:ec264f4ce158 49 for (int i = 0; i < n; i++) {
shintamainjp 0:ec264f4ce158 50 buf[i] = data.buffer[i];
shintamainjp 0:ec264f4ce158 51 }
shintamainjp 0:ec264f4ce158 52
shintamainjp 0:ec264f4ce158 53 init_state();
shintamainjp 0:ec264f4ce158 54
shintamainjp 0:ec264f4ce158 55 IRQ_ENABLE();
shintamainjp 0:ec264f4ce158 56 return bitcount;
shintamainjp 0:ec264f4ce158 57 }
shintamainjp 0:ec264f4ce158 58
shintamainjp 0:ec264f4ce158 59 void ReceiverIR::init_state(void) {
shintamainjp 0:ec264f4ce158 60 work.c1 = -1;
shintamainjp 0:ec264f4ce158 61 work.c2 = -1;
shintamainjp 0:ec264f4ce158 62 work.c3 = -1;
shintamainjp 0:ec264f4ce158 63 work.d1 = -1;
shintamainjp 0:ec264f4ce158 64 work.d2 = -1;
shintamainjp 0:ec264f4ce158 65 data.state = Idle;
shintamainjp 0:ec264f4ce158 66 data.format = RemoteIR::UNKNOWN;
shintamainjp 0:ec264f4ce158 67 data.bitcount = 0;
shintamainjp 0:ec264f4ce158 68 timer.stop();
shintamainjp 0:ec264f4ce158 69 timer.reset();
shintamainjp 0:ec264f4ce158 70 for (int i = 0; i < sizeof(data.buffer); i++) {
shintamainjp 0:ec264f4ce158 71 data.buffer[i] = 0;
shintamainjp 0:ec264f4ce158 72 }
shintamainjp 0:ec264f4ce158 73 }
shintamainjp 0:ec264f4ce158 74
shintamainjp 0:ec264f4ce158 75 void ReceiverIR::isr_wdt(void) {
shintamainjp 0:ec264f4ce158 76 IRQ_DISABLE();
shintamainjp 0:ec264f4ce158 77 static int cnt = 0;
shintamainjp 0:ec264f4ce158 78 if ((Idle != data.state) || ((0 <= work.c1) || (0 <= work.c2) || (0 <= work.c3) || (0 <= work.d1) || (0 <= work.d2))) {
shintamainjp 0:ec264f4ce158 79 cnt++;
shintamainjp 0:ec264f4ce158 80 if (cnt > 50) {
shintamainjp 0:ec264f4ce158 81 #if 0
shintamainjp 0:ec264f4ce158 82 printf("# WDT [c1=%d, c2=%d, c3=%d, d1=%d, d2=%d, state=%d, format=%d, bitcount=%d]\n",
shintamainjp 0:ec264f4ce158 83 work.c1,
shintamainjp 0:ec264f4ce158 84 work.c2,
shintamainjp 0:ec264f4ce158 85 work.c3,
shintamainjp 0:ec264f4ce158 86 work.d1,
shintamainjp 0:ec264f4ce158 87 work.d2,
shintamainjp 0:ec264f4ce158 88 data.state,
shintamainjp 0:ec264f4ce158 89 data.format,
shintamainjp 0:ec264f4ce158 90 data.bitcount);
shintamainjp 0:ec264f4ce158 91 #endif
shintamainjp 0:ec264f4ce158 92 init_state();
shintamainjp 0:ec264f4ce158 93 cnt = 0;
shintamainjp 0:ec264f4ce158 94 }
shintamainjp 0:ec264f4ce158 95 } else {
shintamainjp 0:ec264f4ce158 96 cnt = 0;
shintamainjp 0:ec264f4ce158 97 }
shintamainjp 0:ec264f4ce158 98 IRQ_ENABLE();
shintamainjp 0:ec264f4ce158 99 }
shintamainjp 0:ec264f4ce158 100
shintamainjp 0:ec264f4ce158 101 void ReceiverIR::isr_fall(void) {
shintamainjp 0:ec264f4ce158 102 IRQ_DISABLE();
shintamainjp 0:ec264f4ce158 103 switch (data.state) {
shintamainjp 0:ec264f4ce158 104 case Idle:
shintamainjp 0:ec264f4ce158 105 if (work.c1 < 0) {
shintamainjp 0:ec264f4ce158 106 timer.start();
shintamainjp 0:ec264f4ce158 107 work.c1 = timer.read_us();
shintamainjp 0:ec264f4ce158 108 } else {
shintamainjp 0:ec264f4ce158 109 work.c3 = timer.read_us();
shintamainjp 0:ec264f4ce158 110 int a = work.c2 - work.c1;
shintamainjp 0:ec264f4ce158 111 int b = work.c3 - work.c2;
shintamainjp 0:ec264f4ce158 112 if (InRange(a, TUS_NEC * 16) && InRange(b, TUS_NEC * 8)) {
shintamainjp 0:ec264f4ce158 113 /*
shintamainjp 0:ec264f4ce158 114 * NEC.
shintamainjp 0:ec264f4ce158 115 */
shintamainjp 0:ec264f4ce158 116 data.format = RemoteIR::NEC;
shintamainjp 0:ec264f4ce158 117 data.state = Receiving;
shintamainjp 0:ec264f4ce158 118 data.bitcount = 0;
shintamainjp 0:ec264f4ce158 119 } else if (InRange(a, TUS_NEC * 16) && InRange(b, TUS_NEC * 4)) {
shintamainjp 0:ec264f4ce158 120 /*
shintamainjp 0:ec264f4ce158 121 * NEC Repeat.
shintamainjp 0:ec264f4ce158 122 */
shintamainjp 0:ec264f4ce158 123 data.format = RemoteIR::NEC;
shintamainjp 0:ec264f4ce158 124 data.state = Received;
shintamainjp 0:ec264f4ce158 125 data.bitcount = 0;
shintamainjp 0:ec264f4ce158 126 } else if (InRange(a, TUS_AEHA * 8) && InRange(b, TUS_AEHA * 4)) {
shintamainjp 0:ec264f4ce158 127 /*
shintamainjp 0:ec264f4ce158 128 * AEHA.
shintamainjp 0:ec264f4ce158 129 */
shintamainjp 0:ec264f4ce158 130 data.format = RemoteIR::AEHA;
shintamainjp 0:ec264f4ce158 131 data.state = Receiving;
shintamainjp 0:ec264f4ce158 132 data.bitcount = 0;
shintamainjp 0:ec264f4ce158 133 } else if (InRange(a, TUS_AEHA * 8) && InRange(b, TUS_AEHA * 8)) {
shintamainjp 0:ec264f4ce158 134 /*
shintamainjp 0:ec264f4ce158 135 * AEHA Repeat.
shintamainjp 0:ec264f4ce158 136 */
shintamainjp 0:ec264f4ce158 137 data.format = RemoteIR::AEHA;
shintamainjp 0:ec264f4ce158 138 data.state = Received;
shintamainjp 0:ec264f4ce158 139 data.bitcount = 0;
shintamainjp 0:ec264f4ce158 140 } else {
shintamainjp 0:ec264f4ce158 141 init_state();
shintamainjp 0:ec264f4ce158 142 }
shintamainjp 0:ec264f4ce158 143 }
shintamainjp 0:ec264f4ce158 144 break;
shintamainjp 0:ec264f4ce158 145 case Receiving:
shintamainjp 0:ec264f4ce158 146 if (RemoteIR::NEC == data.format) {
shintamainjp 0:ec264f4ce158 147 work.d2 = timer.read_us();
shintamainjp 0:ec264f4ce158 148 int a = work.d2 - work.d1;
shintamainjp 0:ec264f4ce158 149 if (InRange(a, TUS_NEC * 3)) {
shintamainjp 0:ec264f4ce158 150 data.buffer[data.bitcount / 8] |= (1 << (data.bitcount % 8));
shintamainjp 0:ec264f4ce158 151 } else if (InRange(a, TUS_NEC * 1)) {
shintamainjp 0:ec264f4ce158 152 data.buffer[data.bitcount / 8] &= ~(1 << (data.bitcount % 8));
shintamainjp 0:ec264f4ce158 153 }
shintamainjp 0:ec264f4ce158 154 data.bitcount++;
shintamainjp 0:ec264f4ce158 155 #if 1
shintamainjp 0:ec264f4ce158 156 /*
shintamainjp 0:ec264f4ce158 157 * Length of NEC is always 32 bits.
shintamainjp 0:ec264f4ce158 158 */
shintamainjp 0:ec264f4ce158 159 if (32 <= data.bitcount) {
shintamainjp 0:ec264f4ce158 160 data.state = Received;
shintamainjp 0:ec264f4ce158 161 work.c1 = -1;
shintamainjp 0:ec264f4ce158 162 work.c2 = -1;
shintamainjp 0:ec264f4ce158 163 work.c3 = -1;
shintamainjp 0:ec264f4ce158 164 work.d1 = -1;
shintamainjp 0:ec264f4ce158 165 work.d2 = -1;
shintamainjp 0:ec264f4ce158 166 }
shintamainjp 0:ec264f4ce158 167 #else
shintamainjp 0:ec264f4ce158 168 /*
shintamainjp 0:ec264f4ce158 169 * Set timeout for tail detection automatically.
shintamainjp 0:ec264f4ce158 170 */
shintamainjp 0:ec264f4ce158 171 timeout.detach();
shintamainjp 0:ec264f4ce158 172 timeout.attach_us(this, &ReceiverIR::isr_timeout, TUS_NEC * 12);
shintamainjp 0:ec264f4ce158 173 #endif
shintamainjp 0:ec264f4ce158 174 } else if (RemoteIR::AEHA == data.format) {
shintamainjp 0:ec264f4ce158 175 work.d2 = timer.read_us();
shintamainjp 0:ec264f4ce158 176 int a = work.d2 - work.d1;
shintamainjp 0:ec264f4ce158 177 if (InRange(a, TUS_AEHA * 3)) {
shintamainjp 0:ec264f4ce158 178 data.buffer[data.bitcount / 8] |= (1 << (data.bitcount % 8));
shintamainjp 0:ec264f4ce158 179 } else if (InRange(a, TUS_AEHA * 1)) {
shintamainjp 0:ec264f4ce158 180 data.buffer[data.bitcount / 8] &= ~(1 << (data.bitcount % 8));
shintamainjp 0:ec264f4ce158 181 }
shintamainjp 0:ec264f4ce158 182 data.bitcount++;
shintamainjp 0:ec264f4ce158 183 #if 1
shintamainjp 0:ec264f4ce158 184 /*
shintamainjp 0:ec264f4ce158 185 * Typical length of AEHA is 48 bits.
shintamainjp 0:ec264f4ce158 186 * Please check a specification of your remote controller if you find a problem.
shintamainjp 0:ec264f4ce158 187 */
shintamainjp 0:ec264f4ce158 188 if (48 <= data.bitcount) {
shintamainjp 0:ec264f4ce158 189 data.state = Received;
shintamainjp 0:ec264f4ce158 190 work.c1 = -1;
shintamainjp 0:ec264f4ce158 191 work.c2 = -1;
shintamainjp 0:ec264f4ce158 192 work.c3 = -1;
shintamainjp 0:ec264f4ce158 193 work.d1 = -1;
shintamainjp 0:ec264f4ce158 194 work.d2 = -1;
shintamainjp 0:ec264f4ce158 195 }
shintamainjp 0:ec264f4ce158 196 #else
shintamainjp 0:ec264f4ce158 197 /*
shintamainjp 0:ec264f4ce158 198 * Set timeout for tail detection automatically.
shintamainjp 0:ec264f4ce158 199 */
shintamainjp 0:ec264f4ce158 200 timeout.detach();
shintamainjp 0:ec264f4ce158 201 timeout.attach_us(this, &ReceiverIR::isr_timeout, TUS_AEHA * 12);
shintamainjp 0:ec264f4ce158 202 #endif
shintamainjp 0:ec264f4ce158 203 } else if (RemoteIR::SONY == data.format) {
shintamainjp 0:ec264f4ce158 204 work.d1 = timer.read_us();
shintamainjp 0:ec264f4ce158 205 }
shintamainjp 0:ec264f4ce158 206 break;
shintamainjp 0:ec264f4ce158 207 case Received:
shintamainjp 0:ec264f4ce158 208 break;
shintamainjp 0:ec264f4ce158 209 default:
shintamainjp 0:ec264f4ce158 210 break;
shintamainjp 0:ec264f4ce158 211 }
shintamainjp 0:ec264f4ce158 212 IRQ_ENABLE();
shintamainjp 0:ec264f4ce158 213 }
shintamainjp 0:ec264f4ce158 214
shintamainjp 0:ec264f4ce158 215 void ReceiverIR::isr_rise(void) {
shintamainjp 0:ec264f4ce158 216 IRQ_DISABLE();
shintamainjp 0:ec264f4ce158 217 switch (data.state) {
shintamainjp 0:ec264f4ce158 218 case Idle:
shintamainjp 0:ec264f4ce158 219 if (0 <= work.c1) {
shintamainjp 0:ec264f4ce158 220 work.c2 = timer.read_us();
shintamainjp 0:ec264f4ce158 221 int a = work.c2 - work.c1;
shintamainjp 0:ec264f4ce158 222 if (InRange(a, TUS_SONY * 4)) {
shintamainjp 0:ec264f4ce158 223 data.format = RemoteIR::SONY;
shintamainjp 0:ec264f4ce158 224 data.state = Receiving;
shintamainjp 0:ec264f4ce158 225 data.bitcount = 0;
shintamainjp 0:ec264f4ce158 226 } else {
shintamainjp 0:ec264f4ce158 227 static const int MINIMUM_LEADER_WIDTH = 150;
shintamainjp 0:ec264f4ce158 228 if (a < MINIMUM_LEADER_WIDTH) {
shintamainjp 0:ec264f4ce158 229 init_state();
shintamainjp 0:ec264f4ce158 230 }
shintamainjp 0:ec264f4ce158 231 }
shintamainjp 0:ec264f4ce158 232 } else {
shintamainjp 0:ec264f4ce158 233 init_state();
shintamainjp 0:ec264f4ce158 234 }
shintamainjp 0:ec264f4ce158 235 break;
shintamainjp 0:ec264f4ce158 236 case Receiving:
shintamainjp 0:ec264f4ce158 237 if (RemoteIR::NEC == data.format) {
shintamainjp 0:ec264f4ce158 238 work.d1 = timer.read_us();
shintamainjp 0:ec264f4ce158 239 } else if (RemoteIR::AEHA == data.format) {
shintamainjp 0:ec264f4ce158 240 work.d1 = timer.read_us();
shintamainjp 0:ec264f4ce158 241 } else if (RemoteIR::SONY == data.format) {
shintamainjp 0:ec264f4ce158 242 work.d2 = timer.read_us();
shintamainjp 0:ec264f4ce158 243 int a = work.d2 - work.d1;
shintamainjp 0:ec264f4ce158 244 if (InRange(a, TUS_SONY * 2)) {
shintamainjp 0:ec264f4ce158 245 data.buffer[data.bitcount / 8] |= (1 << (data.bitcount % 8));
shintamainjp 0:ec264f4ce158 246 } else if (InRange(a, TUS_SONY * 1)) {
shintamainjp 0:ec264f4ce158 247 data.buffer[data.bitcount / 8] &= ~(1 << (data.bitcount % 8));
shintamainjp 0:ec264f4ce158 248 }
shintamainjp 0:ec264f4ce158 249 data.bitcount++;
shintamainjp 0:ec264f4ce158 250 #if 1
shintamainjp 0:ec264f4ce158 251 /*
shintamainjp 0:ec264f4ce158 252 * How do we get the correct length? (6bits, 12bits, 15bits, 20bits...)
shintamainjp 0:ec264f4ce158 253 * By a model only?
shintamainjp 0:ec264f4ce158 254 * Please check a specification of your remote controller if you find a problem.
shintamainjp 0:ec264f4ce158 255 */
shintamainjp 0:ec264f4ce158 256 if (12 <= data.bitcount) {
shintamainjp 0:ec264f4ce158 257 data.state = Received;
shintamainjp 0:ec264f4ce158 258 work.c1 = -1;
shintamainjp 0:ec264f4ce158 259 work.c2 = -1;
shintamainjp 0:ec264f4ce158 260 work.c3 = -1;
shintamainjp 0:ec264f4ce158 261 work.d1 = -1;
shintamainjp 0:ec264f4ce158 262 work.d2 = -1;
shintamainjp 0:ec264f4ce158 263 }
shintamainjp 0:ec264f4ce158 264 #else
shintamainjp 0:ec264f4ce158 265 /*
shintamainjp 0:ec264f4ce158 266 * Set timeout for tail detection automatically.
shintamainjp 0:ec264f4ce158 267 */
shintamainjp 0:ec264f4ce158 268 timeout.detach();
shintamainjp 0:ec264f4ce158 269 timeout.attach_us(this, &ReceiverIR::isr_timeout, TUS_SONY * 10);
shintamainjp 0:ec264f4ce158 270 #endif
shintamainjp 0:ec264f4ce158 271 }
shintamainjp 0:ec264f4ce158 272 break;
shintamainjp 0:ec264f4ce158 273 case Received:
shintamainjp 0:ec264f4ce158 274 break;
shintamainjp 0:ec264f4ce158 275 default:
shintamainjp 0:ec264f4ce158 276 break;
shintamainjp 0:ec264f4ce158 277 }
shintamainjp 0:ec264f4ce158 278 IRQ_ENABLE();
shintamainjp 0:ec264f4ce158 279 }
shintamainjp 0:ec264f4ce158 280
shintamainjp 0:ec264f4ce158 281 void ReceiverIR::isr_timeout(void) {
shintamainjp 0:ec264f4ce158 282 IRQ_DISABLE();
shintamainjp 0:ec264f4ce158 283 if (data.state == Receiving) {
shintamainjp 0:ec264f4ce158 284 data.state = Received;
shintamainjp 0:ec264f4ce158 285 work.c1 = -1;
shintamainjp 0:ec264f4ce158 286 work.c2 = -1;
shintamainjp 0:ec264f4ce158 287 work.c3 = -1;
shintamainjp 0:ec264f4ce158 288 work.d1 = -1;
shintamainjp 0:ec264f4ce158 289 work.d2 = -1;
shintamainjp 0:ec264f4ce158 290 }
shintamainjp 0:ec264f4ce158 291 IRQ_ENABLE();
shintamainjp 0:ec264f4ce158 292 }