-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathbus.js
165 lines (137 loc) · 4.15 KB
/
bus.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
165
var SerialPort = require('serialport');
var Promise = require('promise');
var CCCommand = require('./command');
var defaults = require('defaults-deep');
var timeout = require('promise-timeout').timeout;
function CCBus(port, config)
{
this.config = defaults(config, { src: 1, timeout: 1000 });
this.parser = this.parser.bind(this);
this.ser = new SerialPort(port, { baudRate: 9600, parser: this.parser });
this.connectionStatus = 'closed';
this.parserBuffer = new Uint8Array(255+5);
this.parserBuffer.cursor = 0;
this.onOpen = this.onOpen.bind(this);
this.ser.on('open', this.onOpen);
this.onData = this.onData.bind(this);
this.ser.on('data', this.onData);
this.onClose = this.onClose.bind(this);
this.ser.on('close', this.onClose);
this.onError = this.onError.bind(this);
this.ser.on('error', this.onError);
this.devices = {};
this.lastCommand = null;
this.commandChainPromise = Promise.resolve();
}
CCBus.prototype =
{
parser: function parser(emitter, buffer)
{
this.parserBuffer.set(buffer, this.parserBuffer.cursor);
this.parserBuffer.cursor += buffer.length;
while(this.parserBuffer.cursor > 1 && this.parserBuffer.cursor >= this.parserBuffer[1] + 5)
{
// full frame accumulated
var length = this.parserBuffer[1] + 5;
//console.log("length", length);
//copy command from the buffer
var frame = new Uint8Array(length);
frame.set(this.parserBuffer.slice(0, length));
// copy remaining buffer to the begin of the buffer to prepare for next command
this.parserBuffer.set(this.parserBuffer.slice(length, this.parserBuffer.cursor));
this.parserBuffer.cursor -= length;
emitter.emit('data', new CCCommand(frame));
}
},
forEachDevice: function forEachDevice(callback)
{
var dests = Object.keys(this.devices);
dests.forEach(function(dest)
{
callback(this.devices[dest]);
}.bind(this));
},
onOpen: function onOpen()
{
this.forEachDevice(function(device)
{
device.onBusReady();
}.bind(this));
},
onData: function onData(command)
{
//console.log('data', command);
if(command.dest != this.config.src)
return;
var device = this.devices[command.src];
if(device)
{
device.onData(command);
}
if(this.lastCommand)
{
var lastCommand = this.lastCommand;
this.lastCommand = null;
if(command.command == 0)
lastCommand.resolve(command);
else
lastCommand.reject(command);
}
},
onClose: function onClose()
{
this.forEachDevice(function(device)
{
device.onBusClosed();
}.bind(this));
},
onError: function onError(err)
{
console.log("Serial port error", err);
},
registerDevice: function registerDevice(device)
{
this.devices[device.config.dest] = device;
if(this.ser.isOpen())
{
device.onBusReady();
}
},
sendRawCommand: function sendCommand(command)
{
return new Promise(function(resolve, reject)
{
//console.log("will send command");
command.src = this.config.src;
this.ser.write(command.toBuffer(), function(err)
{
//console.log("have sent command");
if(err)
return reject(err);
return resolve();
});
}.bind(this));
},
sendCommand: function sendCommand(command)
{
// Send command with promised reply
// If you use this function, use it exclusively and don't forget to call _onData() if you override onData()
var promise = timeout(new Promise(function(resolve, reject)
{
command.resolve = resolve;
command.reject = reject;
}.bind(this)), this.config.timeout);
// use the command chain to send command only when previous commands have finished
// this way replies can be correctly attributed to commands
this.commandChainPromise = this.commandChainPromise
.catch(function() {})
.then(function()
{
this.lastCommand = command;
return this.sendRawCommand(command);
}.bind(this))
.then(function() { return promise; });
return promise;
},
};
module.exports = exports = CCBus;