forked from thaussma/OpenGarden
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRemoteReceiver.cpp
157 lines (134 loc) · 4.46 KB
/
RemoteReceiver.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
* RemoteSwitch library v2.0.0 made by Randy Simons http://randysimons.nl
* See RemoteSwitchSender.h for details.
*
* License: "Free BSD license". See license.txt
*/
#include "RemoteReceiver.h"
/************
* RemoteReceiver
************/
unsigned short RemoteReceiver::_interrupt;
volatile unsigned short RemoteReceiver::_state;
unsigned short RemoteReceiver::_minRepeats;
RemoteReceiverCallBack RemoteReceiver::_callback;
boolean RemoteReceiver::_inCallback = false;
void RemoteReceiver::init(unsigned short interrupt, unsigned short minRepeats, RemoteReceiverCallBack callback) {
_interrupt = interrupt;
_minRepeats = minRepeats;
_callback = callback;
enable();
}
void RemoteReceiver::enable() {
_state = -1;
attachInterrupt(_interrupt, interruptHandler, CHANGE);
}
void RemoteReceiver::disable() {
detachInterrupt(_interrupt);
}
void RemoteReceiver::interruptHandler() {
static unsigned int period; //Calculated duration of 1 period
static unsigned short receivedBit; //Contains "bit" currently receiving
static unsigned long receivedCode; //Contains received code
static unsigned long previousCode; //Contains previous received code
static unsigned short repeats = 0; //The number of times the an identical code is received in a row.
static unsigned long lastChange=0; //Timestamp of previous edge
static unsigned int min1Period, max1Period, min3Period, max3Period;
unsigned long currentTime=micros();
unsigned int duration=currentTime-lastChange; //Duration = Time between edges
lastChange=currentTime;
if (_state==-1) { //Waiting for sync-signal
if (duration>3720) { //==31*120 minimal time between two edges before decoding starts.
//Sync signal received.. Preparing for decoding
period=duration/31;
receivedCode=previousCode=repeats=0;
//Allow for large error-margin. ElCheapo-hardware :(
min1Period=period*4/10; //Avoid floating point math; saves memory.
max1Period=period*16/10;
min3Period=period*23/10;
max3Period=period*37/10;
}
else {
return;
}
} else if (_state<48) { //Decoding message
//bit part durations can ONLY be 1 or 3 periods.
if (duration>=min1Period && duration<=max1Period) {
bitClear(receivedBit,_state%4); //Note: this sets the bits in reversed order! Correct order would be: 3-(_state%4), but that's overhead we don't want.
}
else if (duration>=min3Period && duration<=max3Period) {
bitSet(receivedBit,_state%4); //Note: this sets the bits in reversed order!
}
else { //Otherwise the entire sequence is invalid
_state=-1;
return;
}
if ((_state%4)==3) { //Last bit part?
//Shift
receivedCode*=3;
//Decode bit.
if (receivedBit==B1010) { //short long short long == B0101, but bits are set in reversed order, so compare to B1010
//bit "0" received
receivedCode+=0; //I hope the optimizer handles this ;)
}
else if (receivedBit==B0101) { //long short long short == B101, but bits are set in reversed order, so compare to B0101
//bit "1" received
receivedCode+=1;
}
else if (receivedBit==B0110) { //short long long short. Reversed too, but makes no difference.
//bit "f" received
receivedCode+=2;
}
else {
//Bit was rubbish. Abort.
_state=-1;
return;
}
}
} else if (_state==48) { //Waiting for sync bit part 1
//Must be 1 period.
if (duration<min1Period || duration>max1Period) {
_state=-1;
return;
}
} else { //Waiting for sync bit part 2
//Must be 31 periods.
if (duration<period*25 || duration>period*36) {
_state=-1;
return;
}
//receivedCode is a valid code!
if (receivedCode!=previousCode) {
repeats=0;
previousCode=receivedCode;
}
repeats++;
if (repeats>=_minRepeats) {
if (!_inCallback) {
_inCallback = true;
(_callback)(receivedCode, period);
_inCallback = false;
}
//Reset after callback.
_state=-1;
return;
}
//Reset for next round
receivedCode = 0;
_state=0; //no need to wait for another sync-bit!
return;
}
_state++;
return;
}
boolean RemoteReceiver::isReceiving(int waitMillis) {
unsigned long startTime=millis();
int waited; //signed int!
do {
if (_state!=-1) {
return true;
}
waited = (millis()-startTime);
} while(waited>=0 && waited <= waitMillis); //Yes, clock wraps every 50 days. And then you'd have to wait for a looooong time.
return false;
}