/** @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; });