RemoteIR.

Dependents:   RemoteIR_TestProgram SerialGPS_TestProgram StarBoardOrangeExpansion1 Door_Slamming_Device ... more

Committer:
shintamainjp
Date:
Tue Aug 17 09:14:49 2010 +0000
Revision:
1:4adf16017a0f
Parent:
0:ec264f4ce158
Child:
3:dfed23b157e6

        

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 0:ec264f4ce158 32 wait_ms(100);
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 0:ec264f4ce158 79 #if 0
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 0:ec264f4ce158 121 data.format = RemoteIR::NEC;
shintamainjp 0:ec264f4ce158 122 data.state = Received;
shintamainjp 0:ec264f4ce158 123 data.bitcount = 0;
shintamainjp 0:ec264f4ce158 124 } else if (InRange(a, TUS_AEHA * 8) && InRange(b, TUS_AEHA * 4)) {
shintamainjp 0:ec264f4ce158 125 /*
shintamainjp 0:ec264f4ce158 126 * AEHA.
shintamainjp 0:ec264f4ce158 127 */
shintamainjp 0:ec264f4ce158 128 data.format = RemoteIR::AEHA;
shintamainjp 0:ec264f4ce158 129 data.state = Receiving;
shintamainjp 0:ec264f4ce158 130 data.bitcount = 0;
shintamainjp 0:ec264f4ce158 131 } else if (InRange(a, TUS_AEHA * 8) && InRange(b, TUS_AEHA * 8)) {
shintamainjp 0:ec264f4ce158 132 /*
shintamainjp 0:ec264f4ce158 133 * AEHA Repeat.
shintamainjp 0:ec264f4ce158 134 */
shintamainjp 0:ec264f4ce158 135 data.format = RemoteIR::AEHA;
shintamainjp 0:ec264f4ce158 136 data.state = Received;
shintamainjp 0:ec264f4ce158 137 data.bitcount = 0;
shintamainjp 0:ec264f4ce158 138 } else {
shintamainjp 0:ec264f4ce158 139 init_state();
shintamainjp 0:ec264f4ce158 140 }
shintamainjp 0:ec264f4ce158 141 }
shintamainjp 0:ec264f4ce158 142 break;
shintamainjp 0:ec264f4ce158 143 case Receiving:
shintamainjp 0:ec264f4ce158 144 if (RemoteIR::NEC == data.format) {
shintamainjp 0:ec264f4ce158 145 work.d2 = timer.read_us();
shintamainjp 0:ec264f4ce158 146 int a = work.d2 - work.d1;
shintamainjp 0:ec264f4ce158 147 if (InRange(a, TUS_NEC * 3)) {
shintamainjp 0:ec264f4ce158 148 data.buffer[data.bitcount / 8] |= (1 << (data.bitcount % 8));
shintamainjp 0:ec264f4ce158 149 } else if (InRange(a, TUS_NEC * 1)) {
shintamainjp 0:ec264f4ce158 150 data.buffer[data.bitcount / 8] &= ~(1 << (data.bitcount % 8));
shintamainjp 0:ec264f4ce158 151 }
shintamainjp 0:ec264f4ce158 152 data.bitcount++;
shintamainjp 0:ec264f4ce158 153 #if 1
shintamainjp 0:ec264f4ce158 154 /*
shintamainjp 0:ec264f4ce158 155 * Length of NEC is always 32 bits.
shintamainjp 0:ec264f4ce158 156 */
shintamainjp 0:ec264f4ce158 157 if (32 <= data.bitcount) {
shintamainjp 0:ec264f4ce158 158 data.state = Received;
shintamainjp 0:ec264f4ce158 159 work.c1 = -1;
shintamainjp 0:ec264f4ce158 160 work.c2 = -1;
shintamainjp 0:ec264f4ce158 161 work.c3 = -1;
shintamainjp 0:ec264f4ce158 162 work.d1 = -1;
shintamainjp 0:ec264f4ce158 163 work.d2 = -1;
shintamainjp 0:ec264f4ce158 164 }
shintamainjp 0:ec264f4ce158 165 #else
shintamainjp 0:ec264f4ce158 166 /*
shintamainjp 0:ec264f4ce158 167 * Set timeout for tail detection automatically.
shintamainjp 0:ec264f4ce158 168 */
shintamainjp 0:ec264f4ce158 169 timeout.detach();
shintamainjp 0:ec264f4ce158 170 timeout.attach_us(this, &ReceiverIR::isr_timeout, TUS_NEC * 12);
shintamainjp 0:ec264f4ce158 171 #endif
shintamainjp 0:ec264f4ce158 172 } else if (RemoteIR::AEHA == data.format) {
shintamainjp 0:ec264f4ce158 173 work.d2 = timer.read_us();
shintamainjp 0:ec264f4ce158 174 int a = work.d2 - work.d1;
shintamainjp 0:ec264f4ce158 175 if (InRange(a, TUS_AEHA * 3)) {
shintamainjp 0:ec264f4ce158 176 data.buffer[data.bitcount / 8] |= (1 << (data.bitcount % 8));
shintamainjp 0:ec264f4ce158 177 } else if (InRange(a, TUS_AEHA * 1)) {
shintamainjp 0:ec264f4ce158 178 data.buffer[data.bitcount / 8] &= ~(1 << (data.bitcount % 8));
shintamainjp 0:ec264f4ce158 179 }
shintamainjp 0:ec264f4ce158 180 data.bitcount++;
shintamainjp 0:ec264f4ce158 181 #if 1
shintamainjp 0:ec264f4ce158 182 /*
shintamainjp 0:ec264f4ce158 183 * Typical length of AEHA is 48 bits.
shintamainjp 0:ec264f4ce158 184 * Please check a specification of your remote controller if you find a problem.
shintamainjp 0:ec264f4ce158 185 */
shintamainjp 0:ec264f4ce158 186 if (48 <= data.bitcount) {
shintamainjp 0:ec264f4ce158 187 data.state = Received;
shintamainjp 0:ec264f4ce158 188 work.c1 = -1;
shintamainjp 0:ec264f4ce158 189 work.c2 = -1;
shintamainjp 0:ec264f4ce158 190 work.c3 = -1;
shintamainjp 0:ec264f4ce158 191 work.d1 = -1;
shintamainjp 0:ec264f4ce158 192 work.d2 = -1;
shintamainjp 0:ec264f4ce158 193 }
shintamainjp 0:ec264f4ce158 194 #else
shintamainjp 0:ec264f4ce158 195 /*
shintamainjp 0:ec264f4ce158 196 * Set timeout for tail detection automatically.
shintamainjp 0:ec264f4ce158 197 */
shintamainjp 0:ec264f4ce158 198 timeout.detach();
shintamainjp 0:ec264f4ce158 199 timeout.attach_us(this, &ReceiverIR::isr_timeout, TUS_AEHA * 12);
shintamainjp 0:ec264f4ce158 200 #endif
shintamainjp 0:ec264f4ce158 201 } else if (RemoteIR::SONY == data.format) {
shintamainjp 0:ec264f4ce158 202 work.d1 = timer.read_us();
shintamainjp 0:ec264f4ce158 203 }
shintamainjp 0:ec264f4ce158 204 break;
shintamainjp 0:ec264f4ce158 205 case Received:
shintamainjp 0:ec264f4ce158 206 break;
shintamainjp 0:ec264f4ce158 207 default:
shintamainjp 0:ec264f4ce158 208 break;
shintamainjp 0:ec264f4ce158 209 }
shintamainjp 0:ec264f4ce158 210 IRQ_ENABLE();
shintamainjp 0:ec264f4ce158 211 }
shintamainjp 0:ec264f4ce158 212
shintamainjp 0:ec264f4ce158 213 void ReceiverIR::isr_rise(void) {
shintamainjp 0:ec264f4ce158 214 IRQ_DISABLE();
shintamainjp 0:ec264f4ce158 215 switch (data.state) {
shintamainjp 0:ec264f4ce158 216 case Idle:
shintamainjp 0:ec264f4ce158 217 if (0 <= work.c1) {
shintamainjp 0:ec264f4ce158 218 work.c2 = timer.read_us();
shintamainjp 0:ec264f4ce158 219 int a = work.c2 - work.c1;
shintamainjp 0:ec264f4ce158 220 if (InRange(a, TUS_SONY * 4)) {
shintamainjp 0:ec264f4ce158 221 data.format = RemoteIR::SONY;
shintamainjp 0:ec264f4ce158 222 data.state = Receiving;
shintamainjp 0:ec264f4ce158 223 data.bitcount = 0;
shintamainjp 0:ec264f4ce158 224 } else {
shintamainjp 0:ec264f4ce158 225 static const int MINIMUM_LEADER_WIDTH = 150;
shintamainjp 0:ec264f4ce158 226 if (a < MINIMUM_LEADER_WIDTH) {
shintamainjp 0:ec264f4ce158 227 init_state();
shintamainjp 0:ec264f4ce158 228 }
shintamainjp 0:ec264f4ce158 229 }
shintamainjp 0:ec264f4ce158 230 } else {
shintamainjp 0:ec264f4ce158 231 init_state();
shintamainjp 0:ec264f4ce158 232 }
shintamainjp 0:ec264f4ce158 233 break;
shintamainjp 0:ec264f4ce158 234 case Receiving:
shintamainjp 0:ec264f4ce158 235 if (RemoteIR::NEC == data.format) {
shintamainjp 0:ec264f4ce158 236 work.d1 = timer.read_us();
shintamainjp 0:ec264f4ce158 237 } else if (RemoteIR::AEHA == data.format) {
shintamainjp 0:ec264f4ce158 238 work.d1 = timer.read_us();
shintamainjp 0:ec264f4ce158 239 } else if (RemoteIR::SONY == data.format) {
shintamainjp 0:ec264f4ce158 240 work.d2 = timer.read_us();
shintamainjp 0:ec264f4ce158 241 int a = work.d2 - work.d1;
shintamainjp 0:ec264f4ce158 242 if (InRange(a, TUS_SONY * 2)) {
shintamainjp 0:ec264f4ce158 243 data.buffer[data.bitcount / 8] |= (1 << (data.bitcount % 8));
shintamainjp 0:ec264f4ce158 244 } else if (InRange(a, TUS_SONY * 1)) {
shintamainjp 0:ec264f4ce158 245 data.buffer[data.bitcount / 8] &= ~(1 << (data.bitcount % 8));
shintamainjp 0:ec264f4ce158 246 }
shintamainjp 0:ec264f4ce158 247 data.bitcount++;
shintamainjp 0:ec264f4ce158 248 #if 1
shintamainjp 0:ec264f4ce158 249 /*
shintamainjp 0:ec264f4ce158 250 * How do we get the correct length? (6bits, 12bits, 15bits, 20bits...)
shintamainjp 0:ec264f4ce158 251 * By a model only?
shintamainjp 0:ec264f4ce158 252 * Please check a specification of your remote controller if you find a problem.
shintamainjp 0:ec264f4ce158 253 */
shintamainjp 0:ec264f4ce158 254 if (12 <= data.bitcount) {
shintamainjp 0:ec264f4ce158 255 data.state = Received;
shintamainjp 0:ec264f4ce158 256 work.c1 = -1;
shintamainjp 0:ec264f4ce158 257 work.c2 = -1;
shintamainjp 0:ec264f4ce158 258 work.c3 = -1;
shintamainjp 0:ec264f4ce158 259 work.d1 = -1;
shintamainjp 0:ec264f4ce158 260 work.d2 = -1;
shintamainjp 0:ec264f4ce158 261 }
shintamainjp 0:ec264f4ce158 262 #else
shintamainjp 0:ec264f4ce158 263 /*
shintamainjp 0:ec264f4ce158 264 * Set timeout for tail detection automatically.
shintamainjp 0:ec264f4ce158 265 */
shintamainjp 0:ec264f4ce158 266 timeout.detach();
shintamainjp 0:ec264f4ce158 267 timeout.attach_us(this, &ReceiverIR::isr_timeout, TUS_SONY * 10);
shintamainjp 0:ec264f4ce158 268 #endif
shintamainjp 0:ec264f4ce158 269 }
shintamainjp 0:ec264f4ce158 270 break;
shintamainjp 0:ec264f4ce158 271 case Received:
shintamainjp 0:ec264f4ce158 272 break;
shintamainjp 0:ec264f4ce158 273 default:
shintamainjp 0:ec264f4ce158 274 break;
shintamainjp 0:ec264f4ce158 275 }
shintamainjp 0:ec264f4ce158 276 IRQ_ENABLE();
shintamainjp 0:ec264f4ce158 277 }
shintamainjp 0:ec264f4ce158 278
shintamainjp 0:ec264f4ce158 279 void ReceiverIR::isr_timeout(void) {
shintamainjp 0:ec264f4ce158 280 IRQ_DISABLE();
shintamainjp 0:ec264f4ce158 281 if (data.state == Receiving) {
shintamainjp 0:ec264f4ce158 282 data.state = Received;
shintamainjp 0:ec264f4ce158 283 work.c1 = -1;
shintamainjp 0:ec264f4ce158 284 work.c2 = -1;
shintamainjp 0:ec264f4ce158 285 work.c3 = -1;
shintamainjp 0:ec264f4ce158 286 work.d1 = -1;
shintamainjp 0:ec264f4ce158 287 work.d2 = -1;
shintamainjp 0:ec264f4ce158 288 }
shintamainjp 0:ec264f4ce158 289 IRQ_ENABLE();
shintamainjp 0:ec264f4ce158 290 }