control-freak-ide/server/nodejs/nxapp/protocols/Serial.js
plastic-hub-dev-node-saturn 538369cff7 latest
2021-05-12 18:35:18 +02:00

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;
});