Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
RemoteIR/ReceiverIR.cpp
- Committer:
- shintamainjp
- Date:
- 2010-08-15
- Revision:
- 1:9370008ac96b
- Parent:
- 0:5d79cd4ac81d
- Child:
- 2:d4625043c895
File content as of revision 1:9370008ac96b:
/**
* IR receiver (Version 0.0.2)
*
* Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
* http://shinta.main.jp/
*/
#include "ReceiverIR.h"
#define InRange(x,y) ((((y) * 0.7) < (x)) && ((x) < ((y) * 1.3)))
#define IRQ_ENABLE() sem.release(); __enable_irq()
#define IRQ_DISABLE() __disable_irq(); sem.take()
ReceiverIR::ReceiverIR(PinName rx) : evt(rx) {
IRQ_DISABLE();
evt.fall(this, &ReceiverIR::isr_fall);
evt.rise(this, &ReceiverIR::isr_rise);
ticker.attach_us(this, &ReceiverIR::isr_wdt, 1 * 1000);
init_state();
IRQ_ENABLE();
}
ReceiverIR::~ReceiverIR() {}
ReceiverIR::State ReceiverIR::getState() {
IRQ_DISABLE();
State s = data.state;
IRQ_ENABLE();
return s;
}
int ReceiverIR::getData(ReceiverIR::Format *format, uint8_t *buf, int bufsiz) {
IRQ_DISABLE();
const int bc = data.bitcount;
if (bufsiz < (bc / 8)) {
IRQ_ENABLE();
return -1;
}
*format = data.format;
for (int i = 0; i < (bc / 8); i++) {
buf[i] = data.buffer[i];
}
init_state();
IRQ_ENABLE();
return bc;
}
void ReceiverIR::init_state(void) {
work.c1 = -1;
work.c2 = -1;
work.c3 = -1;
work.d1 = -1;
work.d2 = -1;
data.state = Idle;
data.format = UNKNOWN;
data.bitcount = 0;
timer.stop();
timer.reset();
for (int i = 0; i < sizeof(data.buffer); i++) {
data.buffer[i] = 0;
}
}
void ReceiverIR::isr_wdt(void) {
IRQ_DISABLE();
static int cnt = 0;
if ((Receiving == data.state) || ((0 <= work.c1) || (0 <= work.c2) || (0 <= work.c3))) {
cnt++;
if (cnt > 500) {
printf("# WDT [c1=%d, c2=%d, c3=%d, d1=%d, d2=%d, state=%d, format=%d, bitcount=%d]\n",
work.c1,
work.c2,
work.c3,
work.d1,
work.d2,
data.state,
data.format,
data.bitcount);
init_state();
cnt = 0;
}
} else {
cnt = 0;
}
IRQ_ENABLE();
}
void ReceiverIR::isr_fall(void) {
IRQ_DISABLE();
switch (data.state) {
case Idle:
if (work.c1 < 0) {
timer.start();
work.c1 = timer.read_us();
} else {
work.c3 = timer.read_us();
int a = work.c2 - work.c1;
int b = work.c3 - work.c2;
if (InRange(a, TUS_NEC * 16) && InRange(b, TUS_NEC * 8)) {
/*
* NEC.
*/
data.format = NEC;
data.state = Receiving;
data.bitcount = 0;
} else if (InRange(a, TUS_NEC * 16) && InRange(b, TUS_NEC * 4)) {
/*
* NEC Repeat.
*/
data.format = NEC;
data.state = Received;
data.bitcount = 0;
} else if (InRange(a, TUS_AEHA * 8) && InRange(b, TUS_AEHA * 4)) {
/*
* AEHA.
*/
data.format = AEHA;
data.state = Receiving;
data.bitcount = 0;
} else if (InRange(a, TUS_AEHA * 8) && InRange(b, TUS_AEHA * 8)) {
/*
* AEHA Repeat.
*/
data.format = AEHA;
data.state = Received;
data.bitcount = 0;
} else {
init_state();
}
}
break;
case Receiving:
if (NEC == data.format) {
work.d2 = timer.read_us();
int a = work.d2 - work.d1;
if (InRange(a, TUS_NEC * 3)) {
data.buffer[data.bitcount / 8] |= (1 << (data.bitcount % 8));
} else if (InRange(a, TUS_NEC * 1)) {
data.buffer[data.bitcount / 8] &= ~(1 << (data.bitcount % 8));
}
data.bitcount++;
if (32 <= data.bitcount) {
data.state = Received;
}
} else if (AEHA == data.format) {
work.d2 = timer.read_us();
int a = work.d2 - work.d1;
if (InRange(a, TUS_AEHA * 3)) {
data.buffer[data.bitcount / 8] |= (1 << (data.bitcount % 8));
} else if (InRange(a, TUS_AEHA * 1)) {
data.buffer[data.bitcount / 8] &= ~(1 << (data.bitcount % 8));
}
data.bitcount++;
/*
* Typical length of AEHA is 48 bits.
* Please check a specification of your remote controller if you find a problem.
*/
if (48 <= data.bitcount) {
data.state = Received;
work.c1 = -1;
work.c2 = -1;
work.c3 = -1;
work.d1 = -1;
work.d2 = -1;
}
} else if (SONY == data.format) {
work.d1 = timer.read_us();
}
break;
case Received:
break;
default:
break;
}
IRQ_ENABLE();
}
void ReceiverIR::isr_rise(void) {
IRQ_DISABLE();
switch (data.state) {
case Idle:
if (0 <= work.c1) {
work.c2 = timer.read_us();
int a = work.c2 - work.c1;
if (InRange(a, TUS_SONY * 4)) {
data.format = SONY;
data.state = Receiving;
data.bitcount = 0;
} else {
static const int MINIMUM_LEADER_WIDTH = 150;
if (a < MINIMUM_LEADER_WIDTH) {
init_state();
}
}
} else {
init_state();
}
break;
case Receiving:
if (NEC == data.format) {
work.d1 = timer.read_us();
} else if (AEHA == data.format) {
work.d1 = timer.read_us();
} else if (SONY == data.format) {
work.d2 = timer.read_us();
int a = work.d2 - work.d1;
if (InRange(a, TUS_SONY * 2)) {
data.buffer[data.bitcount / 8] |= (1 << (data.bitcount % 8));
} else if (InRange(a, TUS_SONY * 1)) {
data.buffer[data.bitcount / 8] &= ~(1 << (data.bitcount % 8));
}
data.bitcount++;
/*
* How do we get the correct length? (12bits, 15bits, 20bits...)
* By a model only?
* Please check a specification of your remote controller if you find a problem.
*/
if (12 <= data.bitcount) {
data.state = Received;
work.c1 = -1;
work.c2 = -1;
work.c3 = -1;
work.d1 = -1;
work.d2 = -1;
}
}
break;
case Received:
break;
default:
break;
}
IRQ_ENABLE();
}