440 lines
11 KiB
JavaScript
440 lines
11 KiB
JavaScript
/** @module nxapp/protocols/Serial */
|
|
define([
|
|
'dcl/dcl',
|
|
"xide/utils",
|
|
"xide/utils/StringUtils",
|
|
"nxapp/types/Types",
|
|
'nxapp/protocols/ProtocolBase',
|
|
"dojo/node!child_process",
|
|
"dojo/node!util",
|
|
"nxapp/utils/_console",
|
|
"xdojo/has",
|
|
"dojo/node!xcf-server-misc/serialport",
|
|
"dojo/node!@serialport/parser-delimiter",
|
|
"dojo/Deferred"
|
|
], function (dcl, utils, StringUtils, types, ProtocolBase, child, nUtil, _console, has, com, Delimiter, Deferred) {
|
|
|
|
|
|
// const Transform = Stream.Transform;
|
|
|
|
/*
|
|
class DelimiterParser extends Transform {
|
|
constructor(options) {
|
|
options = options || {}
|
|
super(options)
|
|
|
|
if (options.delimiter === undefined) {
|
|
throw new TypeError('"delimiter" is not a bufferable object')
|
|
}
|
|
|
|
if (options.delimiter.length === 0) {
|
|
throw new TypeError('"delimiter" has a 0 or undefined length')
|
|
}
|
|
|
|
this.includeDelimiter = options.includeDelimiter !== undefined ? options.includeDelimiter : false
|
|
this.delimiter = _Buffer.from(options.delimiter)
|
|
this.buffer = _Buffer.alloc(0)
|
|
}
|
|
|
|
_transform(chunk, encoding, cb) {
|
|
let data = _Buffer.concat([this.buffer, chunk])
|
|
let position
|
|
while ((position = data.indexOf(this.delimiter)) !== -1) {
|
|
this.push(data.slice(0, position + (this.includeDelimiter ? this.delimiter.length : 0)))
|
|
data = data.slice(position + this.delimiter.length)
|
|
}
|
|
this.buffer = data
|
|
cb()
|
|
}
|
|
|
|
_flush(cb) {
|
|
this.push(this.buffer)
|
|
this.buffer = _Buffer.alloc(0)
|
|
cb()
|
|
}
|
|
}
|
|
*/
|
|
|
|
//_console.log('serialport', delimiter);
|
|
|
|
|
|
var debug = true;
|
|
var debugErrors = true;
|
|
var debugConnect = true;
|
|
var debugData = true;
|
|
var console = _console;
|
|
var Module = dcl(ProtocolBase, {
|
|
declaredClass: "nxapp.protocols.Serial",
|
|
_socket: null,
|
|
protocolName: 'serial',
|
|
instance: null,
|
|
client: null,
|
|
sshOptions: null,
|
|
/**
|
|
* Creates a proper SSH2 option object
|
|
* @param host
|
|
* @param port
|
|
* @param deviceOptions
|
|
* @returns {Object}
|
|
*/
|
|
getOptions: function (host, port, deviceOptions, lineBreak) {
|
|
var options = {
|
|
baudRate: 19200,
|
|
parity: 'none', //'none', 'even', 'mark', 'odd', 'space'
|
|
rtscts: false,
|
|
xon: false,
|
|
xoff: false,
|
|
xany: false,
|
|
hupcl: true,
|
|
cts: false,
|
|
dtr: true,
|
|
dts: false,
|
|
brk: false,
|
|
rts: false,
|
|
dataBits: 8,
|
|
stopBits: 1,
|
|
bufferSize: 64 * 1024
|
|
//parser: com.parsers.raw
|
|
};
|
|
return utils.mixin(options, deviceOptions);
|
|
},
|
|
onConnected: function () {
|
|
debugConnect && console.log('# ' + this.protocolName + ' - Protocol:: onConnected ' + this.options.host + ' : ' + this.options.port + ' @ ' + this.protocolName);
|
|
this.connection.connected = true;
|
|
this.delegate.onConnect2(this.connection);
|
|
},
|
|
onError: function (error, options) {
|
|
this.delegate.onError(this.connection, utils.mixin({
|
|
code: error
|
|
}, options), this.options);
|
|
},
|
|
onClose: function () {
|
|
this.delegate.onClose(this.connection, this.options);
|
|
},
|
|
connect: function () {
|
|
try {
|
|
if (!com) {
|
|
console.warn('serial port was not loaded!')
|
|
com = global.nRequire('serialport');
|
|
console.warn('got serial port : ' + (com != null));
|
|
}
|
|
} catch (e) {
|
|
console.error('cant load serial port', e);
|
|
}
|
|
|
|
if (!com || !com.parsers) {
|
|
console.error('----heavy error! It seems that node-js module "serial-port" has not been installed correctly ' + has('serialport'));
|
|
return this.onError('----heavy error! It seems that node-js module "serial-port" has not been installed correctly ' + has('serialport'), com);
|
|
}
|
|
if (!has('serialport')) {
|
|
console.error('have no serial port flag enabled, abort!');
|
|
return this.onError('have no serial no port');
|
|
}
|
|
|
|
try {
|
|
var _options = this.options;
|
|
|
|
if (!has('serialport')) {
|
|
return this.onError('have no serial port');
|
|
}
|
|
|
|
if (!_options || !_options.driver) {
|
|
debugConnect && console.error('no driver in options', _options);
|
|
return this;
|
|
}
|
|
|
|
|
|
var self = this;
|
|
var host = _options.host;
|
|
var port = _options.port;
|
|
var deviceOptions = utils.getJson(_options.options || {});
|
|
if (deviceOptions.debug === true) {
|
|
debug = true;
|
|
}
|
|
var responseSettings = _options.responseSettings || {};
|
|
|
|
if (deviceOptions.baudRate) {
|
|
deviceOptions.baudRate = parseInt(deviceOptions.baudRate);
|
|
delete deviceOptions.baudRate;
|
|
}
|
|
if (deviceOptions.stopbits) {
|
|
deviceOptions.stopBits = parseInt(deviceOptions.stopbits);
|
|
delete deviceOptions.stopbits;
|
|
}
|
|
if (deviceOptions.databits) {
|
|
deviceOptions.dataBits = parseInt(deviceOptions.databits);
|
|
delete deviceOptions.databits;
|
|
}
|
|
var options = this.getOptions(host, port, deviceOptions, responseSettings.delimiter);
|
|
|
|
|
|
|
|
var connectionOptions = options;
|
|
this.serialOptions = options;
|
|
this.protocol = this.protocolName;
|
|
|
|
if (options.baudRate && _.isString(options.baudRate)) {
|
|
options.baudRate = parseInt(options.baudRate);
|
|
}
|
|
if (options.stopbits) {
|
|
options.stopBits = parseInt(options.stopbits);
|
|
delete deviceOptions.stopbits;
|
|
}
|
|
if (options.databits) {
|
|
options.dataBits = parseInt(options.databits);
|
|
delete options.databits;
|
|
}
|
|
|
|
// debugConnect && console.log('open serial port: options', options);
|
|
debugConnect && console.log('Serial->connecting to ' + host + ' with', utils.inspect(options));
|
|
|
|
var serialPort = new com(host, options);
|
|
this.client = serialPort;
|
|
|
|
serialPort.on('error', function (data) {
|
|
self.onError(data.toString(), data);
|
|
});
|
|
|
|
try {
|
|
serialPort.on('open', function (err) {
|
|
if (err) {
|
|
var errorString = err.level + ":" + err.message;
|
|
self.onError(errorString);
|
|
self.lastError = errorString;
|
|
debugErrors || self.isDebug() && console.warn('Serial->Connection - Error :: ' + host + ':' + err);
|
|
return;
|
|
}
|
|
self.onConnected();
|
|
let del = '\n';
|
|
try {
|
|
const dat = {
|
|
d: responseSettings.delimiter
|
|
}
|
|
const t = JSON.parse(JSON.stringify(dat));
|
|
del = t.d;
|
|
|
|
} catch (e) {
|
|
_console.error('error parsing delimitter ', e);
|
|
}
|
|
|
|
if(del==='\\n'){
|
|
del = '\n'
|
|
}
|
|
|
|
if(del==='\\r'){
|
|
del = '\r'
|
|
}
|
|
|
|
|
|
const parser = serialPort.pipe(new Delimiter({
|
|
delimiter: del || '\r'
|
|
}))
|
|
|
|
parser.on('data', function (data) {
|
|
if (debugData || self.isDebug()) {
|
|
console.log('Serial->onData ' + data.toString());
|
|
}
|
|
self.onData(data.toString() + responseSettings.delimiter, data);
|
|
});
|
|
|
|
});
|
|
} catch (e) {
|
|
debugErrors || this.isDebug() && console.error('Serial->connect error :: code: ', e);
|
|
}
|
|
|
|
serialPort.on('close', function (code) {
|
|
try {
|
|
debugConnect || self.isDebug() && console.log('Serial->close :: code: ', code);
|
|
self.onClose();
|
|
serialPort.close();
|
|
} catch (e) {
|
|
debugConnect || self.isDebug() && console.error('Serial->close :: code: ', e);
|
|
}
|
|
});
|
|
this._socket = {};
|
|
this._socket.writable = true;
|
|
return this;
|
|
} catch (e) {
|
|
debugConnect || this.isDebug() && console.error('error connection serial ', e);
|
|
self.onError(e.message);
|
|
console.trace();
|
|
|
|
return this;
|
|
}
|
|
},
|
|
onData: function (string, buffer) {
|
|
this.delegate.onData(this.connection, string, buffer);
|
|
},
|
|
onCommandError: function (cmd, options) {
|
|
debug || this.isDebug() && console.log('SERIAL->CommandError ' + cmd + ' id ' + options.id + ' src ' + options.src);
|
|
try {
|
|
this.delegate.onData(this.connection, utils.mixin({
|
|
cmd: cmd,
|
|
event: types.EVENTS.ON_COMMAND_ERROR
|
|
}, options));
|
|
} catch (e) {
|
|
console.error('---', e);
|
|
}
|
|
},
|
|
onFinish: function (cmd, options) {
|
|
debug || this.isDebug() && console.log('SERIAL->onFinish ' + cmd + ' id ' + options.id + ' src ' + options.src);
|
|
try {
|
|
this.delegate.onData(this.connection, utils.mixin({
|
|
cmd: cmd,
|
|
event: types.EVENTS.ON_COMMAND_FINISH
|
|
}, options));
|
|
|
|
} catch (e) {
|
|
console.error('onFinish-Error:', e);
|
|
}
|
|
},
|
|
send: function (cmd, options) {
|
|
|
|
if (cmd == null) {
|
|
console.error('SERIAL invalid command');
|
|
return;
|
|
}
|
|
options = options || {
|
|
id: utils.createUUID()
|
|
};
|
|
|
|
|
|
var intArray = utils.bufferFromDecString(cmd);
|
|
var buffer = new Buffer(intArray);
|
|
var str = buffer.toString();
|
|
this.isDebug() && console.log("Serial - Sending command: " + str);
|
|
var connection = this.client;
|
|
connection.write(buffer);
|
|
},
|
|
close: function () {
|
|
if (this.client) {
|
|
this.client.close();
|
|
}
|
|
}
|
|
});
|
|
/**
|
|
* Serial protocol client
|
|
* @class module:nxapp/protocols/Serial
|
|
* @extends module:nxapp/protocols/ProtocolBase
|
|
* @implements module:nxapp/protocols/ProtocolBase
|
|
*/
|
|
|
|
Module.ls = function (query) {
|
|
var dfd = new Deferred();
|
|
if (com) {
|
|
com.list(function (err, ports) {
|
|
ports = ports.filter(function (port) {
|
|
return true; //!!port.pnpId;
|
|
})
|
|
ports = _.map(ports, function (port) {
|
|
return {
|
|
host: port.comName,
|
|
port: "",
|
|
description: port.manufacturer,
|
|
id: port.pnpId
|
|
}
|
|
});
|
|
dfd.resolve(ports);
|
|
});
|
|
} else {
|
|
console.error('have no serial port');
|
|
dfd.reject("serialport nodejs library not present");
|
|
}
|
|
return dfd;
|
|
}
|
|
Module.options = function (query) {
|
|
try {
|
|
var dfd = new Deferred();
|
|
var ECIType = types.ECIType;
|
|
var NetworkGroup = 'Network';
|
|
|
|
function createOption(label, value) {
|
|
return {
|
|
label: label,
|
|
value: label || value
|
|
}
|
|
}
|
|
|
|
var cis = [
|
|
utils.createCI(types.DEVICE_PROPERTY.CF_DEVICE_PORT, ECIType.STRING, '', {
|
|
group: 'Network',
|
|
disabled: true
|
|
}),
|
|
utils.createCI('baudRate', ECIType.ENUMERATION, 115200, {
|
|
group: NetworkGroup,
|
|
title: "Baud rate",
|
|
options: [
|
|
createOption(115200),
|
|
createOption(57600),
|
|
createOption(38400),
|
|
createOption(19200),
|
|
createOption(9600),
|
|
createOption(4800),
|
|
createOption(2400),
|
|
createOption(1800),
|
|
createOption(1200),
|
|
createOption(600),
|
|
createOption(300),
|
|
createOption(200),
|
|
createOption(150),
|
|
createOption(134),
|
|
createOption(110),
|
|
createOption(75),
|
|
createOption(50)
|
|
]
|
|
}),
|
|
utils.createCI('databits', ECIType.ENUMERATION, 8, {
|
|
group: NetworkGroup,
|
|
title: 'Data bits',
|
|
options: [
|
|
createOption(8),
|
|
createOption(7),
|
|
createOption(6),
|
|
createOption(5)
|
|
]
|
|
}),
|
|
utils.createCI('stopbits', ECIType.ENUMERATION, 1, {
|
|
group: NetworkGroup,
|
|
title: 'Stop bits',
|
|
options: [
|
|
createOption(1),
|
|
createOption(2)
|
|
]
|
|
}),
|
|
utils.createCI('parity', ECIType.ENUMERATION, 'none', {
|
|
group: NetworkGroup,
|
|
title: 'Parity',
|
|
options: [
|
|
createOption('none'),
|
|
createOption('even'),
|
|
createOption('mark'),
|
|
createOption('odd'),
|
|
createOption('space')
|
|
]
|
|
}),
|
|
utils.createCI('rtscts', ECIType.BOOL, false, {
|
|
group: NetworkGroup
|
|
}),
|
|
utils.createCI('xon', ECIType.BOOL, false, {
|
|
group: NetworkGroup
|
|
}),
|
|
utils.createCI('xoff', ECIType.BOOL, false, {
|
|
group: NetworkGroup
|
|
}),
|
|
utils.createCI('flowcontrol', ECIType.BOOL, true, {
|
|
group: NetworkGroup
|
|
}),
|
|
utils.createCI('buffersize', ECIType.INTEGER, 65536, {
|
|
group: NetworkGroup
|
|
})
|
|
]
|
|
dfd.resolve(cis);
|
|
return dfd;
|
|
} catch (e) {
|
|
console.error('error', e);
|
|
}
|
|
return dfd;
|
|
}
|
|
return Module;
|
|
});
|