RemoteIR.

Dependents:   RemoteIR_TestProgram SerialGPS_TestProgram StarBoardOrangeExpansion1 Door_Slamming_Device ... more

Committer:
shintamainjp
Date:
Sat Aug 21 11:05:57 2010 +0000
Revision:
7:9452ba065449
Parent:
6:e57504fc802e
Child:
9:dcfdac59ef74

        

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