RemoteIR.

Dependents:   RemoteIR_TestProgram SerialGPS_TestProgram StarBoardOrangeExpansion1 Door_Slamming_Device ... more

Committer:
shintamainjp
Date:
Sat Aug 21 04:46:14 2010 +0000
Revision:
3:dfed23b157e6
Parent:
1:4adf16017a0f
Child:
4:2304646f6ff5

        

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