-
Notifications
You must be signed in to change notification settings - Fork 0
/
piswitch.js
164 lines (141 loc) · 4.01 KB
/
piswitch.js
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
158
159
160
161
162
163
164
/*
* PiSwitch.js - RC-Switch for Raspberry Pi
* usage: see README.md
*
* Inspired by RC-Switch for Arduino:
* https://code.google.com/p/rc-switch/
*
* Adapted for node and Raspberry Pi by tjanson:
* https://github.com/tjanson/PiSwitch
*/
var wpi = require('wiring-pi');
var config = require('./config.js').defaults;
var dict = require('./dict.js');
var firstInit = true;
/*
* needs to be called once to initialize wiring-pi
* on repeated calls, previous values will persist unless overwritten
*/
function setup(opts) {
oldPin = config.pin;
oldMode = config.mode;
for (var key in opts) {
config[key] = (opts[key] !== undefined) ? opts[key] : config[key];
}
if (firstInit) {
wpi.setup(config.mode);
firstInit = false;
} else {
if (oldMode !== config.mode) {
// not sure if this would lead to problems, so let's just forbid it
console.warn("WARN [transmitter.js] mode change ignored; mode is final");
config.mode = oldMode;
}
if (oldPin !== config.pin) {
wpi.pinMode(oldPin, wpi.INPUT);
}
}
wpi.pinMode(config.pin, wpi.OUTPUT);
}
/*
* input must be one of:
* - binary code,
* - tristate,
* - correctly declared manufacturer code
*/
function send(code, type, off) {
if (typeof code !== 'string') {
console.error("ERROR [piswitch.js] send() requires string");
return;
}
if (typeof type === 'undefined') { // :)
type = 'binary'
}
if (typeof type !== 'string'
|| (type !== 'binary' && type !== 'tristate'
&& typeof dict.types[type] === 'undefined')
) {
console.error("ERROR [piswitch.js] unknown code type: " + type);
}
code = code.toLowerCase();
// check against regexp patterns and reject non-matches
var pattern;
if (type === 'binary') {
pattern = /^[01]*$/;
} else if (type === 'tristate') {
pattern = /^[01f]*$/;
} else {
pattern = dict.types[type].regexp;
}
if (!pattern.test(code)) {
console.error("ERROR [piswitch.js] bad input (type: " + type + ")");
return;
}
// translate as necessary
if (type === 'binary') {
code = code.split('');
} else if (type === 'tristate') {
code = triToBin(code);
} else if (type !== 'binary') {
code = manufacturerToBin(code, type, off);
}
// transmission consists of repeated binary code
// plus 'sync' signals before, in-between, and after
transmission = ['s'];
for (var i = 0; i < config.repeats; i++) {
transmission = transmission.concat(code, 's');
}
transmit(binToWave(transmission));
}
function manufacturerToBin(code, type, off) {
var d = dict.types[type];
var format = d.format;
var tristate = '';
// the code often consists of several digit groups with
// different translation schemes
// the character `code[i]` belongs to digit group `format[i]`
// and the translation is found in `map[group][char]`
for (var i = 0; i < format.length; i++) {
tristate += d.map[format[i]][code[i]];
}
tristate += (typeof off !== 'undefined' && off) ? d.off : d.on;
return triToBin(tristate);
}
function triToBin(code) {
return convert(code, dict.tribit);
}
function binToWave(code) {
return convert(code, dict.wave[config.protocol]);
}
function convert(code, mapping) {
return flatten(Array.prototype.map.call(code, function(token){
return mapping[token];
}));
}
// flattens one depth
function flatten(array) {
var flattened = [];
for (var i = 0; i < array.length; ++i) {
var current = array[i];
for (var j = 0; j < current.length; ++j) {
flattened.push(current[j]);
}
}
return flattened;
}
/*
* accepts an array of numbers, which represent the delay before
* switching from HIGH to LOW or vice-versa
*
* e.g.: transmit([1,3,1,1]) will produce this waveform: ^|___|^|_
*/
function transmit(wave) {
level = wpi.HIGH;
for (var i = 0; i < wave.length; i++) {
wpi.digitalWrite(config.pin, level);
wpi.delayMicroseconds(config.pulseLength * wave[i]);
level = (level === wpi.HIGH) ? wpi.LOW : wpi.HIGH;
}
}
exports.setup = setup;
exports.send = send;