new_remote 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rubocop.yml +19 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +43 -0
- data/LICENSE +674 -0
- data/README.md +80 -0
- data/Rakefile +11 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/ext/new_remote/NewRemoteReceiver.cpp +311 -0
- data/ext/new_remote/NewRemoteReceiver.h +108 -0
- data/ext/new_remote/NewRemoteTransmitter.cpp +162 -0
- data/ext/new_remote/NewRemoteTransmitter.h +116 -0
- data/ext/new_remote/extconf.rb +10 -0
- data/ext/new_remote/license.txt +674 -0
- data/ext/new_remote/new_remote.cpp +173 -0
- data/lib/new_remote.rb +53 -0
- data/lib/new_remote/version.rb +5 -0
- data/new_remote.gemspec +30 -0
- metadata +106 -0
data/README.md
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# NewRemoteSwitch for Raspberry Pi
|
2
|
+
|
3
|
+
This is a port of the [NewRemoteSwitch for Arduino](https://bitbucket.org/fuzzillogic/433mhzforarduino/wiki/Home) (by Randy Simons) to the Raspberry Pi as a Ruby gem.
|
4
|
+
|
5
|
+
It can be used to send and receive signals from and to the new A-series [KlikAanKlikUit](https://www.klikaanklikuit.nl/) remote switches. Using a 433MHz transmitter and/or receiver connected to the GPIO ports on a Raspberry Pi. And from Ruby. Isn't that awesome?
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
If you haven't installed Ruby yet, then do that first:
|
10
|
+
|
11
|
+
$ sudo apt-get install ruby ruby-dev
|
12
|
+
|
13
|
+
This gem uses the [wiringPi](http://wiringpi.com/) library, which should be installed as well:
|
14
|
+
|
15
|
+
$ sudo apt-get install wiringpi
|
16
|
+
|
17
|
+
Install the gem:
|
18
|
+
|
19
|
+
$ sudo gem install new_remote
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
If you want to use this library as a non-root user, then you need to add that user to the `gpio` group:
|
24
|
+
|
25
|
+
$ sudo usermod -a -G gpio username
|
26
|
+
|
27
|
+
### Transmitter
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'new_remote'
|
31
|
+
|
32
|
+
transmitter = NewRemote::Transmitter.new(address, pin, periodusec = 260, repeats = 4)
|
33
|
+
```
|
34
|
+
|
35
|
+
The `address` parameter can be either a random number, or copied from your existing remote. You can use the `Receiver` to determine your remotes address.
|
36
|
+
|
37
|
+
The `pin` parameter is the GPIO pin where the transmitter is connected to. Please note that it uses the [wiringPi pin numbering scheme](http://wiringpi.com/pins/).
|
38
|
+
|
39
|
+
For more details about the parameters, please read the comments in `NewRemoteTransmitter.h`.
|
40
|
+
|
41
|
+
The usage of the transmitter is pretty simple and almost needs no further explanation:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
switch = transmitter.unit(0) # select first unit (range 0-15)
|
45
|
+
switch = transmitter.group # or select group
|
46
|
+
|
47
|
+
switch.on # switch on devices(s)
|
48
|
+
switch.off # switch off device(s)
|
49
|
+
switch.dim(8) # set dim level (range 0-15); also switches on device(s)
|
50
|
+
```
|
51
|
+
|
52
|
+
### Receiver
|
53
|
+
|
54
|
+
The `receive` method loops forever and shows the received codes on the standard output.
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
require 'new_remote'
|
58
|
+
|
59
|
+
NewRemote::Receiver.receive(pin, repeats)
|
60
|
+
```
|
61
|
+
|
62
|
+
The `pin` parameter is the GPIO pin where the receiver is connected to. Please note that it uses the [wiringPi pin numbering scheme](http://wiringpi.com/pins/).
|
63
|
+
|
64
|
+
The `repeats` parameter indicates the number of times the same message must be received to be valid.
|
65
|
+
|
66
|
+
For more information about the inner working, please read the comments in `NewRemoteReceiver.h`.
|
67
|
+
|
68
|
+
## Development
|
69
|
+
|
70
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
71
|
+
|
72
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
73
|
+
|
74
|
+
## Contributing
|
75
|
+
|
76
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ppostma/NewRemoteSwitch.
|
77
|
+
|
78
|
+
## License
|
79
|
+
|
80
|
+
The gem is available as open source under the terms of the [GNU General Public License version 3](https://opensource.org/licenses/GPL-3.0).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "new_remote"
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require "irb"
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,311 @@
|
|
1
|
+
/*
|
2
|
+
* NewRemoteSwitch library v1.2.0 (20140128) made by Randy Simons http://randysimons.nl/
|
3
|
+
* See NewRemoteReceiver.h for details.
|
4
|
+
*
|
5
|
+
* License: GPLv3. See license.txt
|
6
|
+
*/
|
7
|
+
|
8
|
+
#include "NewRemoteReceiver.h"
|
9
|
+
|
10
|
+
#define RESET_STATE _state = -1 // Resets state to initial position.
|
11
|
+
|
12
|
+
/************
|
13
|
+
* NewRemoteReceiver
|
14
|
+
|
15
|
+
Protocol. (Copied from Wieltje, http://www.circuitsonline.net/forum/view/message/1181410#1181410,
|
16
|
+
but with slightly different timings, as measured on my device.)
|
17
|
+
_ _
|
18
|
+
'0': | |_| |_____ (T,T,T,5T)
|
19
|
+
_ _
|
20
|
+
'1': | |_____| |_ (T,5T,T,T)
|
21
|
+
_ _
|
22
|
+
dim: | |_| |_ (T,T,T,T)
|
23
|
+
|
24
|
+
T = short period of ~260µs. However, this code tries
|
25
|
+
to figure out the correct period
|
26
|
+
|
27
|
+
A full frame looks like this:
|
28
|
+
|
29
|
+
- start pulse: 1T high, 10.44T low
|
30
|
+
- 26 bit: Address
|
31
|
+
- 1 bit: group bit
|
32
|
+
- 1 bit: on/off/[dim]
|
33
|
+
- 4 bit: unit
|
34
|
+
- [4 bit: dim level. Present of [dim] is chosen, but might be present anyway...]
|
35
|
+
- stop pulse: 1T high, 40T low
|
36
|
+
|
37
|
+
************/
|
38
|
+
|
39
|
+
int8_t NewRemoteReceiver::_interrupt;
|
40
|
+
volatile short NewRemoteReceiver::_state;
|
41
|
+
uint8_t NewRemoteReceiver::_minRepeats;
|
42
|
+
NewRemoteReceiverCallBack NewRemoteReceiver::_callback;
|
43
|
+
bool NewRemoteReceiver::_inCallback = false;
|
44
|
+
bool NewRemoteReceiver::_enabled = false;
|
45
|
+
|
46
|
+
void NewRemoteReceiver::init(int8_t interrupt, uint8_t minRepeats, NewRemoteReceiverCallBack callback) {
|
47
|
+
_interrupt = interrupt;
|
48
|
+
_minRepeats = minRepeats;
|
49
|
+
_callback = callback;
|
50
|
+
|
51
|
+
enable();
|
52
|
+
if (_interrupt >= 0) {
|
53
|
+
wiringPiISR(_interrupt, INT_EDGE_BOTH, &interruptHandler);
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
void NewRemoteReceiver::enable() {
|
58
|
+
RESET_STATE;
|
59
|
+
_enabled = true;
|
60
|
+
}
|
61
|
+
|
62
|
+
void NewRemoteReceiver::disable() {
|
63
|
+
_enabled = false;
|
64
|
+
}
|
65
|
+
|
66
|
+
void NewRemoteReceiver::deinit() {
|
67
|
+
_enabled = false;
|
68
|
+
if (_interrupt >= 0) {
|
69
|
+
//detachInterrupt(_interrupt);
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
void NewRemoteReceiver::interruptHandler() {
|
74
|
+
// This method is written as compact code to keep it fast. While breaking up this method into more
|
75
|
+
// methods would certainly increase the readability, it would also be much slower to execute.
|
76
|
+
// Making calls to other methods is quite expensive on AVR. As These interrupt handlers are called
|
77
|
+
// many times a second, calling other methods should be kept to a minimum.
|
78
|
+
|
79
|
+
if (!_enabled) {
|
80
|
+
return;
|
81
|
+
}
|
82
|
+
|
83
|
+
static uint8_t receivedBit; // Contains "bit" currently receiving
|
84
|
+
static NewRemoteCode receivedCode; // Contains received code
|
85
|
+
static NewRemoteCode previousCode; // Contains previous received code
|
86
|
+
static uint8_t repeats = 0; // The number of times the an identical code is received in a row.
|
87
|
+
static unsigned long edgeTimeStamp[3] = {0, }; // Timestamp of edges
|
88
|
+
static unsigned int min1Period, max1Period, min5Period, max5Period;
|
89
|
+
static bool skip;
|
90
|
+
|
91
|
+
// Filter out too short pulses. This method works as a low pass filter.
|
92
|
+
edgeTimeStamp[1] = edgeTimeStamp[2];
|
93
|
+
edgeTimeStamp[2] = micros();
|
94
|
+
|
95
|
+
if (skip) {
|
96
|
+
skip = false;
|
97
|
+
return;
|
98
|
+
}
|
99
|
+
|
100
|
+
if (_state >= 0 && edgeTimeStamp[2]-edgeTimeStamp[1] < min1Period) {
|
101
|
+
// Last edge was too short.
|
102
|
+
// Skip this edge, and the next too.
|
103
|
+
skip = true;
|
104
|
+
return;
|
105
|
+
}
|
106
|
+
|
107
|
+
unsigned int duration = edgeTimeStamp[1] - edgeTimeStamp[0];
|
108
|
+
edgeTimeStamp[0] = edgeTimeStamp[1];
|
109
|
+
|
110
|
+
// Note that if state>=0, duration is always >= 1 period.
|
111
|
+
|
112
|
+
if (_state == -1) {
|
113
|
+
// wait for the long low part of a stop bit.
|
114
|
+
// Stopbit: 1T high, 40T low
|
115
|
+
// By default 1T is 260µs, but for maximum compatibility go as low as 120µs
|
116
|
+
if (duration > 4800) { // =40*120µs, minimal time between two edges before decoding starts.
|
117
|
+
// Sync signal received.. Preparing for decoding
|
118
|
+
repeats = 0;
|
119
|
+
|
120
|
+
receivedCode.period = duration / 40; // Measured signal is 40T, so 1T (period) is measured signal / 40.
|
121
|
+
|
122
|
+
// Allow for large error-margin. ElCheapo-hardware :(
|
123
|
+
min1Period = receivedCode.period * 3 / 10; // Lower limit for 1 period is 0.3 times measured period; high signals can "linger" a bit sometimes, making low signals quite short.
|
124
|
+
max1Period = receivedCode.period * 3; // Upper limit for 1 period is 3 times measured period
|
125
|
+
min5Period = receivedCode.period * 3; // Lower limit for 5 periods is 3 times measured period
|
126
|
+
max5Period = receivedCode.period * 8; // Upper limit for 5 periods is 8 times measured period
|
127
|
+
}
|
128
|
+
else {
|
129
|
+
return;
|
130
|
+
}
|
131
|
+
} else if (_state == 0) { // Verify start bit part 1 of 2
|
132
|
+
// Duration must be ~1T
|
133
|
+
if (duration > max1Period) {
|
134
|
+
RESET_STATE;
|
135
|
+
return;
|
136
|
+
}
|
137
|
+
// Start-bit passed. Do some clean-up.
|
138
|
+
receivedCode.address = receivedCode.unit = receivedCode.dimLevel = 0;
|
139
|
+
} else if (_state == 1) { // Verify start bit part 2 of 2
|
140
|
+
// Duration must be ~10.44T
|
141
|
+
if (duration < 7 * receivedCode.period || duration > 15 * receivedCode.period) {
|
142
|
+
RESET_STATE;
|
143
|
+
return;
|
144
|
+
}
|
145
|
+
} else if (_state < 148) { // state 146 is first edge of stop-sequence. All bits before that adhere to default protocol, with exception of dim-bit
|
146
|
+
receivedBit <<= 1;
|
147
|
+
|
148
|
+
// One bit consists out of 4 bit parts.
|
149
|
+
// bit part durations can ONLY be 1 or 5 periods.
|
150
|
+
if (duration <= max1Period) {
|
151
|
+
receivedBit &= 0b1110; // Clear LSB of receivedBit
|
152
|
+
} else if (duration >= min5Period && duration <= max5Period) {
|
153
|
+
receivedBit |= 0b1; // Set LSB of receivedBit
|
154
|
+
} else if (
|
155
|
+
// Check if duration matches the second part of stopbit (duration must be ~40T), and ...
|
156
|
+
(duration >= 20 * receivedCode.period && duration <= 80 * receivedCode.period) &&
|
157
|
+
// if first part op stopbit was a short signal (short signal yielded a 0 as second bit in receivedBit), and ...
|
158
|
+
((receivedBit & 0b10) == 0b00) &&
|
159
|
+
// we are in a state in which a stopbit is actually valid, only then ...
|
160
|
+
(_state == 147 || _state == 131) ) {
|
161
|
+
// If a dim-level was present...
|
162
|
+
if (_state == 147) {
|
163
|
+
// mark received switch signal as signal-with-dim
|
164
|
+
receivedCode.dimLevelPresent = true;
|
165
|
+
}
|
166
|
+
|
167
|
+
// a valid signal was found!
|
168
|
+
if (
|
169
|
+
receivedCode.address != previousCode.address ||
|
170
|
+
receivedCode.unit != previousCode.unit ||
|
171
|
+
receivedCode.dimLevelPresent != previousCode.dimLevelPresent ||
|
172
|
+
receivedCode.dimLevel != previousCode.dimLevel ||
|
173
|
+
receivedCode.groupBit != previousCode.groupBit ||
|
174
|
+
receivedCode.switchType != previousCode.switchType
|
175
|
+
) { // memcmp isn't deemed safe
|
176
|
+
repeats=0;
|
177
|
+
previousCode = receivedCode;
|
178
|
+
}
|
179
|
+
|
180
|
+
repeats++;
|
181
|
+
|
182
|
+
if (repeats>=_minRepeats) {
|
183
|
+
if (!_inCallback) {
|
184
|
+
_inCallback = true;
|
185
|
+
(_callback)(receivedCode);
|
186
|
+
_inCallback = false;
|
187
|
+
}
|
188
|
+
// Reset after callback.
|
189
|
+
RESET_STATE;
|
190
|
+
return;
|
191
|
+
}
|
192
|
+
|
193
|
+
// Reset for next round
|
194
|
+
_state=0; // no need to wait for another sync-bit!
|
195
|
+
return;
|
196
|
+
}
|
197
|
+
else { // Otherwise the entire sequence is invalid
|
198
|
+
RESET_STATE;
|
199
|
+
return;
|
200
|
+
}
|
201
|
+
|
202
|
+
if (_state % 4 == 1) { // Last bit part? Note: this is the short version of "if ( (_state-2) % 4 == 3 )"
|
203
|
+
// There are 3 valid options for receivedBit:
|
204
|
+
// 0, indicated by short short short long == B0001.
|
205
|
+
// 1, short long shot short == B0100.
|
206
|
+
// dim, short shot short shot == B0000.
|
207
|
+
// Everything else: inconsistent data, trash the whole sequence.
|
208
|
+
|
209
|
+
|
210
|
+
if (_state < 106) {
|
211
|
+
// States 2 - 105 are address bit states
|
212
|
+
|
213
|
+
receivedCode.address <<= 1;
|
214
|
+
|
215
|
+
// Decode bit. Only 4 LSB's of receivedBit are used; trim the rest.
|
216
|
+
switch (receivedBit & 0b1111) {
|
217
|
+
case 0b0001: // Bit "0" received.
|
218
|
+
// receivedCode.address |= 0; But let's not do that, as it is wasteful.
|
219
|
+
break;
|
220
|
+
case 0b0100: // Bit "1" received.
|
221
|
+
receivedCode.address |= 1;
|
222
|
+
break;
|
223
|
+
default: // Bit was invalid. Abort.
|
224
|
+
RESET_STATE;
|
225
|
+
return;
|
226
|
+
}
|
227
|
+
} else if (_state < 110) {
|
228
|
+
// States 106 - 109 are group bit states.
|
229
|
+
switch (receivedBit & 0b1111) {
|
230
|
+
case 0b0001: // Bit "0" received.
|
231
|
+
receivedCode.groupBit = false;
|
232
|
+
break;
|
233
|
+
case 0b0100: // Bit "1" received.
|
234
|
+
receivedCode.groupBit = true;
|
235
|
+
break;
|
236
|
+
default: // Bit was invalid. Abort.
|
237
|
+
RESET_STATE;
|
238
|
+
return;
|
239
|
+
}
|
240
|
+
} else if (_state < 114) {
|
241
|
+
// States 110 - 113 are switch bit states.
|
242
|
+
switch (receivedBit & 0b1111) {
|
243
|
+
case 0b0001: // Bit "0" received.
|
244
|
+
receivedCode.switchType = NewRemoteCode::off;
|
245
|
+
break;
|
246
|
+
case 0b0100: // Bit "1" received. Note: this might turn out to be a on_with_dim signal.
|
247
|
+
receivedCode.switchType = NewRemoteCode::on;
|
248
|
+
break;
|
249
|
+
case 0b0000: // Bit "dim" received.
|
250
|
+
receivedCode.switchType = NewRemoteCode::dim;
|
251
|
+
break;
|
252
|
+
default: // Bit was invalid. Abort.
|
253
|
+
RESET_STATE;
|
254
|
+
return;
|
255
|
+
}
|
256
|
+
} else if (_state < 130){
|
257
|
+
// States 114 - 129 are unit bit states.
|
258
|
+
receivedCode.unit <<= 1;
|
259
|
+
|
260
|
+
// Decode bit.
|
261
|
+
switch (receivedBit & 0b1111) {
|
262
|
+
case 0b0001: // Bit "0" received.
|
263
|
+
// receivedCode.unit |= 0; But let's not do that, as it is wasteful.
|
264
|
+
break;
|
265
|
+
case 0b0100: // Bit "1" received.
|
266
|
+
receivedCode.unit |= 1;
|
267
|
+
break;
|
268
|
+
default: // Bit was invalid. Abort.
|
269
|
+
RESET_STATE;
|
270
|
+
return;
|
271
|
+
}
|
272
|
+
|
273
|
+
} else if (_state < 146) {
|
274
|
+
// States 130 - 145 are dim bit states.
|
275
|
+
// Depending on hardware, these bits can be present, even if switchType is NewRemoteCode::on or NewRemoteCode::off
|
276
|
+
|
277
|
+
receivedCode.dimLevel <<= 1;
|
278
|
+
|
279
|
+
// Decode bit.
|
280
|
+
switch (receivedBit & 0b1111) {
|
281
|
+
case 0b0001: // Bit "0" received.
|
282
|
+
// receivedCode.dimLevel |= 0; But let's not do that, as it is wasteful.
|
283
|
+
break;
|
284
|
+
case 0b0100: // Bit "1" received.
|
285
|
+
receivedCode.dimLevel |= 1;
|
286
|
+
break;
|
287
|
+
default: // Bit was invalid. Abort.
|
288
|
+
RESET_STATE;
|
289
|
+
return;
|
290
|
+
}
|
291
|
+
}
|
292
|
+
}
|
293
|
+
}
|
294
|
+
|
295
|
+
_state++;
|
296
|
+
return;
|
297
|
+
}
|
298
|
+
|
299
|
+
bool NewRemoteReceiver::isReceiving(int waitMillis) {
|
300
|
+
unsigned long startTime=millis();
|
301
|
+
|
302
|
+
int waited; // Signed int!
|
303
|
+
do {
|
304
|
+
if (_state >= 34) { // Abort if a significant part of a code (start pulse + 8 bits) has been received
|
305
|
+
return true;
|
306
|
+
}
|
307
|
+
waited = (millis()-startTime);
|
308
|
+
} while(waited>=0 && waited <= waitMillis); // Yes, clock wraps every 50 days. And then you'd have to wait for a looooong time.
|
309
|
+
|
310
|
+
return false;
|
311
|
+
}
|
@@ -0,0 +1,108 @@
|
|
1
|
+
/*
|
2
|
+
* NewRemoteSwitch library v1.2.0 (20140128) made by Randy Simons http://randysimons.nl/
|
3
|
+
*
|
4
|
+
* License: GPLv3. See license.txt
|
5
|
+
*/
|
6
|
+
|
7
|
+
#ifndef NewRemoteReceiver_h
|
8
|
+
#define NewRemoteReceiver_h
|
9
|
+
|
10
|
+
#include <cstdint>
|
11
|
+
#include <wiringPi.h>
|
12
|
+
|
13
|
+
struct NewRemoteCode {
|
14
|
+
enum SwitchType {
|
15
|
+
off = 0,
|
16
|
+
on = 1,
|
17
|
+
dim = 2
|
18
|
+
};
|
19
|
+
|
20
|
+
unsigned int period; // Detected duration in microseconds of 1T in the received signal
|
21
|
+
unsigned long address; // Address of received code. [0..2^26-1]
|
22
|
+
bool groupBit; // Group bit set or not
|
23
|
+
SwitchType switchType; // off, on, dim, on_with_dim.
|
24
|
+
uint8_t unit; // Unit code of received code [0..15]
|
25
|
+
bool dimLevelPresent; // Dim level present or not. Will be available for switchType dim, but might be available for on or off too, depending on remote.
|
26
|
+
uint8_t dimLevel; // Dim level [0..15]. Will be available if switchType is dim, on_with_dim or off_with_dim.
|
27
|
+
};
|
28
|
+
|
29
|
+
typedef void (*NewRemoteReceiverCallBack)(NewRemoteCode);
|
30
|
+
|
31
|
+
/**
|
32
|
+
* See RemoteSwitch for introduction.
|
33
|
+
*
|
34
|
+
* NewRemoteReceiver decodes the signal received from a 433MHz-receiver, like the "KlikAanKlikUit"-system
|
35
|
+
* as well as the signal sent by the RemoteSwtich class. When a correct signal is received,
|
36
|
+
* a user-defined callback function is called.
|
37
|
+
*
|
38
|
+
* Note that in the callback function, the interrupts are still disabled. You can enabled them, if needed.
|
39
|
+
* A call to the callback must be finished before NewRemoteReceiver will call the callback function again, thus
|
40
|
+
* there is no re-entrant problem.
|
41
|
+
*
|
42
|
+
* When sending your own code using NewRemoteSwich, disable() the receiver first.
|
43
|
+
*
|
44
|
+
* This is a pure static class, for simplicity and to limit memory-use.
|
45
|
+
*/
|
46
|
+
|
47
|
+
class NewRemoteReceiver {
|
48
|
+
public:
|
49
|
+
/**
|
50
|
+
* Initializes the decoder.
|
51
|
+
*
|
52
|
+
* If interrupt >= 0, init will register pin <interrupt> to this library.
|
53
|
+
* If interrupt < 0, no interrupt is registered. In that case, you have to call interruptHandler()
|
54
|
+
* yourself whenever the output of the receiver changes, or you can use InterruptChain.
|
55
|
+
*
|
56
|
+
* @param interrupt The interrupt as is used by Arduino's attachInterrupt function. See attachInterrupt for details.
|
57
|
+
If < 0, you must call interruptHandler() yourself.
|
58
|
+
* @param minRepeats The number of times the same code must be received in a row before the callback is calles
|
59
|
+
* @param callback Pointer to a callback function, with signature void (*func)(NewRemoteCode)
|
60
|
+
*/
|
61
|
+
static void init(int8_t interrupt, uint8_t minRepeats, NewRemoteReceiverCallBack callback);
|
62
|
+
|
63
|
+
/**
|
64
|
+
* Enable decoding. No need to call enable() after init().
|
65
|
+
*/
|
66
|
+
static void enable();
|
67
|
+
|
68
|
+
/**
|
69
|
+
* Disable decoding. You can re-enable decoding by calling enable();
|
70
|
+
*/
|
71
|
+
static void disable();
|
72
|
+
|
73
|
+
/**
|
74
|
+
* Deinitializes the decoder. Disables decoding and detaches the interrupt handler. If you want to
|
75
|
+
* re-enable decoding, call init() again.
|
76
|
+
*/
|
77
|
+
static void deinit();
|
78
|
+
|
79
|
+
/**
|
80
|
+
* Tells wether a signal is being received. If a compatible signal is detected within the time out, isReceiving returns true.
|
81
|
+
* Since it makes no sense to transmit while another transmitter is active, it's best to wait for isReceiving() to false.
|
82
|
+
* By default it waits for 150ms, in which a (relative slow) KaKu signal can be broadcasted three times.
|
83
|
+
*
|
84
|
+
* Note: isReceiving() depends on interrupts enabled. Thus, when disabled()'ed, or when interrupts are disabled (as is
|
85
|
+
* the case in the callback), isReceiving() will not work properly.
|
86
|
+
*
|
87
|
+
* @param waitMillis number of milliseconds to monitor for signal.
|
88
|
+
* @return bool If after waitMillis no signal was being processed, returns false. If before expiration a signal was being processed, returns true.
|
89
|
+
*/
|
90
|
+
static bool isReceiving(int waitMillis = 150);
|
91
|
+
|
92
|
+
/**
|
93
|
+
* Called every time the signal level changes (high to low or vice versa). Usually called by interrupt.
|
94
|
+
*/
|
95
|
+
static void interruptHandler();
|
96
|
+
|
97
|
+
private:
|
98
|
+
|
99
|
+
static int8_t _interrupt; // Radio input interrupt
|
100
|
+
volatile static short _state; // State of decoding process.
|
101
|
+
static uint8_t _minRepeats;
|
102
|
+
static NewRemoteReceiverCallBack _callback;
|
103
|
+
static bool _inCallback; // When true, the callback function is being executed; prevents re-entrance.
|
104
|
+
static bool _enabled; // If true, monitoring and decoding is enabled. If false, interruptHandler will return immediately.
|
105
|
+
|
106
|
+
};
|
107
|
+
|
108
|
+
#endif
|