-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
179 lines (150 loc) · 5.86 KB
/
Copy pathindex.js
File metadata and controls
179 lines (150 loc) · 5.86 KB
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
var EventEmitter = require('events').EventEmitter
var util = require('util')
var SerialPort = require('serialport')
var NCEDCC = function (devicePath, callback) {
var self = this
EventEmitter.call(self)
self._useDirectMode = false
self._commandQueue = []
self._currentCommand = null
self.sp = new SerialPort(devicePath, { baudRate: 9600 })
self.sp.on('error', function (err) {
callback(err)
})
self.sp.on('open', function () {
self.sp.on('data', function (data) {
self.emit('RECV', data) // DEBUG HOOK
if (self._currentCommand) {
// Handle response coming back in multiple chunks
self._currentCommand.responseBuffer = Buffer.concat([self._currentCommand.responseBuffer, data])
if (self._currentCommand.responseBuffer.length === self._currentCommand.expectedResponseLength) {
self.emit('response', self._currentCommand.responseBuffer)
if (typeof self._currentCommand.callback === 'function') {
self._currentCommand.callback(null, self._currentCommand.responseBuffer)
}
// switch to the next command in the queue
self._commandQueue.shift()
if (self._commandQueue[0] !== undefined) {
self._execCommand(self._commandQueue[0])
}
}
}
})
// We're alive!
callback(null)
self.emit('ready')
})
self.on('command', function (newCommand) {
self._commandQueue.push(newCommand)
if (newCommand === self._commandQueue[0]) {
self._execCommand(self._commandQueue[0])
}
})
}
util.inherits(NCEDCC, EventEmitter)
// _execCommand should not be called by clients
NCEDCC.prototype._execCommand = function (newCommand) {
this._currentCommand = newCommand
this.emit('SEND', newCommand.command)
this.sp.write(newCommand.command)
}
NCEDCC.prototype._issueCommand = function (cmd, responseSize, callback) {
var newCommand = {
command: cmd,
responseBuffer: Buffer.alloc(0),
expectedResponseLength: responseSize,
callback: callback
}
this.emit('command', newCommand)
}
NCEDCC.prototype._throttleCommand = function (address, op, data, callback) {
/*
0xA2 sends speed or function packets to a locomotive.
Command Format: 0xA2 <addr_h> <addr_l> <op_1> <data_1>
Addr_h and Addr_l are the loco address in DCC format.
If a long address is in use, bits 6 and 7 of the high byte are set.
Example: Long address 3 = 0xc0 0x03 Short address 3 = 0x00 0x03
op_1 data_1
01 0-7f Reverse 28 speed command *BUGGY, DO NOT USE!
02 0-7f Forward 28 speed command *BUGGY, DO NOT USE!
03 0-7f Reverse 128 speed command
04 0-7f Forward 128 speed command
05 0 Estop reverse command
06 0 Estop forward command
07 0-1f Function group 1 (same format as DCC packet for FG1
08 0-0f Function group 2 (same format as DCC packet for FG2
09 0-0f Function group 3 (same format as DCC packet for FG3
0a 0-7f Set reverse consist address for lead loco
0b 0-7f Set forward consist address for lead loco
0c 0-7f Set reverse consist address for rear loco
0d 0-7f Set forward consist address for rear loco
0e 0-7f Set reverse consist address for additional loco
0f 0-7f Set forward consist address for additional loco
10 0 Del loco from consist
11 0 Kill consist
12 0-9 Set momentum
15 0-ff Functions 13-20 control (bit 0=F13, bit 7=F20)
16 0-ff Functions 21-28 control (bit 0=F21, bit 7=F28)
17 0-3f Assign this loco to cab number in data_1
Returns: ! = success
1 = bad loco address
*/
this._issueCommand(Buffer.from([0xa2, ((address >> 8) & 0xff), (address & 0x0ff), op, data]), 1, callback)
}
NCEDCC.prototype._accessoryCommand = function (address, op, data, callback) {
/*
Command Format: 0xAD <addr_h> <addr_l> <op_1> <data_1>
The address range is 1-2047
Addr_h and Addr_l are the accessory/signal address (NOT in DCC format).
Example:
Accessory Address 513 = 0x02 0x01
Accessory Address 6 = 0x00 0x06
NOTE: Accy/signal address 0 is not a valid address;
address 2044 is the broadcast address
Op_1 Data_1
01 0-255 NCE macro number 0-255
02 0-255 Duplicate of Op_1 command
03 0 Accessory Normal direction (ON)
04 0 Accessory Reverse direction (OFF)
05 0-1f Signal Aspect 0-31
05-7f reserved
Returns: ! = success
reserved 1 = bad accy address
*/
this._issueCommand(Buffer.from([0xad, ((address >> 8) & 0xff), (address & 0x0ff), op, data]), 1, callback)
}
// Command station methods
NCEDCC.prototype.getVersion = function (callback) {
this._issueCommand(Buffer.from([0xaa]), 3, callback)
}
// return capabilities of the command station
NCEDCC.prototype.getOptions = function (callback) {
callback(undefined, { 'hasProgrammingTrack': true, 'supportsDirectMode': true })
}
NCEDCC.prototype.enterProgramTrackMode = function (useDirectMode, callback) {
this._useDirectMode = useDirectMode
this._issueCommand(Buffer.from([0x9e]), 1, callback)
}
NCEDCC.prototype.exitProgramTrackMode = function (callback) {
this._issueCommand(Buffer.from([0x9f]), 1, callback)
}
NCEDCC.prototype.writeCV = function (cv, value, callback) {
// paged 0xa0; direct 0xa8
this._issueCommand(Buffer.from([(this._useDirectMode ? 0xa8 : 0xa0), ((cv >> 8) & 0xff), (cv & 0x0ff), value]), 1, callback)
}
NCEDCC.prototype.readCV = function (cv, callback) {
// paged 0xa1; direct 0xa9
this._issueCommand(Buffer.from([(this._useDirectMode ? 0xa9 : 0xa1), ((cv >> 8) & 0xff), (cv & 0x0ff)]), 2, callback)
}
NCEDCC.prototype.setTurnout = function (address, state, callback) {
this._accessoryCommand(address, state ? 0x3 : 0x4, callback)
}
NCEDCC.prototype.setSignal = function (address, aspect, callback) {
this._accessoryCommand(address, 0x05, aspect, callback)
}
NCEDCC.prototype.setSpeedAndDirection = function (locoAddress, speed, direction, callback) {
this._throttleCommand(locoAddress, direction ? 0x03 : 0x04, speed, callback)
}
module.exports = {
NCEDCC: NCEDCC
}