节点串行端口堆叠侦听器并且没有使用承诺获得完整响应
node serialport stacking listeners and not getting complete response using a promise
我遇到了一个问题,即我尝试使用的基于承诺的代码并不是每次都能得到完整的响应。我将数据侦听器与 .on 一起使用,但将其更改为 .once,因为测试显示我在每次调用时都在堆叠数据侦听器。但无论哪种方式,我偶尔都会得到部分回应。那么我该如何解决这个问题。不是堆叠侦听器,而是每次都获得完整的响应......并使用承诺来完成。
sendPort: function(port, src) {
return new Promise((resolve, reject) => {
// .once, not stacking but sometimes incomplete responses, .on stacking listener
port.once('data', (data) => {
resolve(data); // TODO parse data here or maybe after return
});
port.once('error', (err) => {
reject(err);
});
// have same debug in .then after call showing listerner not removed with .on
Debug.L1('sendport num data listeners: ', port.listenerCount("data"));
port.write(src);
});
这里是调用代码
com.openPort(port).then(port => {
_.pTimeout(3000, com.sendPort(port, NCD.gen(args.cmd)))
.then(received => {
console.log('complete response: ', NCD.parse(received));
Debug.L1('resolved num data listeners: ', port.listenerCount("data"));
})
})
.catch(function(e) {
console.log('error: ', e)
});
这里是使用 .on 调用 4 次的输出,完整的响应应该是 [ 170, 1, 0, 171 ]
debug:1 api command array: +0ms [ 170, 3, 254, 175, 0, 90 ]
debug:1 sendport num data listeners: +1ms 4
complete response: [ 170 ]
debug:1 resolved num data listeners: +2ms 4
另一次响应是 [170, 1, 0],大多数时候我都能得到完整的响应。
.once 的结果类似,但侦听器未堆叠。
debug:1 sendport num data listeners: +0ms 1
complete response: [ 170, 1, 0 ]
debug:1 resolved num data listeners: +1ms 0
想法?想法?关于修复但使用承诺。
我的代码来自我在这里找到的想法。 Nodejs map serial port write to receive data
从 serialport gitter 的人那里得到了一些帮助,所以发布了我想出的一个完整的工作解决方案。底线是你必须使用 .on 然后你必须以某种方式知道你将要返回多少字节。对于我的设备,我返回一个前导字节,然后是第二个字节,告诉后面有多少字节,最后一个字节是校验和。我写这个是为了 "plug in" 他们自己的缓冲区解析器可以一直连接块,直到你告诉它不要通过将完成标志更改为 true 来连接。
所以 sendPort
上面的结果是这样的,其中 port
已经创建并打开 serialPort,cmd
是作为缓冲区发送到设备的命令,parser
是特定于您的设备的函数,它将以块的形式解析返回的缓冲区,直到您说完成为止。
sendPort: function(port, cmd, parser) {
return new Promise((resolve, reject) => {
Debug.L2('port and buffer for write', port, cmd)
let parse = _.Parse(parser); //create object with response and done fields and reference to attached parser
Debug.L1('parse response and done initally, ', parse.response, parse.done);
port.on('data', (chunk) => {
parse.parser(chunk)
// Debug.L1('parsed: ', parse.response)
Debug.L1('parse done after parser call:', parse.done);
if (parse.done) {
resolve(parse.response);
parse.reset() // sets .done to false and clears out .response
Debug.L1('response and done after resolve/complete, ', parse.response, parse.done);
port.reset(); //removes all listners to avoid stacking on next call to sendPort
}
});
port.on('error', (err) => {
reject(err);
});
port.write(cmd);
});
},
Parse 对象看起来像这样
// See sendPort - used with custom parser function to return response and completion flag
Parse: function(parser) {
let parse = function() {}
parse.parser = parser;
parse.reset = function reset() {
this.response = [];
this.done = '';
}
parse.reset(); // used here to intialize response and
return parse
}
然后你需要编写你自己的解析器函数,你传递到这里
let parse = _.Parse(parser);
特定于您的设备。这是用于 NCD ProXR 中继板。
parse: function(chunk) {
for (var byte of chunk) {
this.response.push(byte);
Debug.L1('response being built ', this.response)
}
Debug.L1('current chunck response ', this.response)
// api version where first byte is 170,
if (this.response[1]) { // second slot is number of bits to follow exlcuding checksum
if (this.response.length >= 3 + this.response[1]) { // 3 = 170 + number of bits bit + checksum
this.done = true
}
}
},
为了让它不堆叠 "data" 个侦听器,我在创建端口时添加了一个重置方法,当我知道已检索到完整的响应时可以调用该方法。我使用了 removeALLlisteners,因为我无法让单曲工作,没关系,我知道代码中的任何地方都没有其他 "data" 侦听器。
let serialport = require('serialport'),
createPort: function(sysDevName, opts) {
opts = opts || {};
opts.autoOpen = false; // actually open device later
Debug.L1(sysDevName, opts);
let port = new serialport(sysDevName, opts, (err) => {
if (err) {
Debug.L1("create error" + err.message);
return err;
}
})
port.reset = function() {
this.removeAllListeners("data");
this.removeAllListeners("error");
}
return port;
最后要注意的是 Parse
对象包含一个 .reset
方法,您会看到它和 port.reset
在完成完整响应后被调用。您需要这样做,否则 done 标志不会变为 false,并且 .response
仍将包含前一个并且 "data"
听众将堆叠。
我遇到了一个问题,即我尝试使用的基于承诺的代码并不是每次都能得到完整的响应。我将数据侦听器与 .on 一起使用,但将其更改为 .once,因为测试显示我在每次调用时都在堆叠数据侦听器。但无论哪种方式,我偶尔都会得到部分回应。那么我该如何解决这个问题。不是堆叠侦听器,而是每次都获得完整的响应......并使用承诺来完成。
sendPort: function(port, src) {
return new Promise((resolve, reject) => {
// .once, not stacking but sometimes incomplete responses, .on stacking listener
port.once('data', (data) => {
resolve(data); // TODO parse data here or maybe after return
});
port.once('error', (err) => {
reject(err);
});
// have same debug in .then after call showing listerner not removed with .on
Debug.L1('sendport num data listeners: ', port.listenerCount("data"));
port.write(src);
});
这里是调用代码
com.openPort(port).then(port => {
_.pTimeout(3000, com.sendPort(port, NCD.gen(args.cmd)))
.then(received => {
console.log('complete response: ', NCD.parse(received));
Debug.L1('resolved num data listeners: ', port.listenerCount("data"));
})
})
.catch(function(e) {
console.log('error: ', e)
});
这里是使用 .on 调用 4 次的输出,完整的响应应该是 [ 170, 1, 0, 171 ]
debug:1 api command array: +0ms [ 170, 3, 254, 175, 0, 90 ]
debug:1 sendport num data listeners: +1ms 4
complete response: [ 170 ]
debug:1 resolved num data listeners: +2ms 4
另一次响应是 [170, 1, 0],大多数时候我都能得到完整的响应。
.once 的结果类似,但侦听器未堆叠。
debug:1 sendport num data listeners: +0ms 1
complete response: [ 170, 1, 0 ]
debug:1 resolved num data listeners: +1ms 0
想法?想法?关于修复但使用承诺。
我的代码来自我在这里找到的想法。 Nodejs map serial port write to receive data
从 serialport gitter 的人那里得到了一些帮助,所以发布了我想出的一个完整的工作解决方案。底线是你必须使用 .on 然后你必须以某种方式知道你将要返回多少字节。对于我的设备,我返回一个前导字节,然后是第二个字节,告诉后面有多少字节,最后一个字节是校验和。我写这个是为了 "plug in" 他们自己的缓冲区解析器可以一直连接块,直到你告诉它不要通过将完成标志更改为 true 来连接。
所以 sendPort
上面的结果是这样的,其中 port
已经创建并打开 serialPort,cmd
是作为缓冲区发送到设备的命令,parser
是特定于您的设备的函数,它将以块的形式解析返回的缓冲区,直到您说完成为止。
sendPort: function(port, cmd, parser) {
return new Promise((resolve, reject) => {
Debug.L2('port and buffer for write', port, cmd)
let parse = _.Parse(parser); //create object with response and done fields and reference to attached parser
Debug.L1('parse response and done initally, ', parse.response, parse.done);
port.on('data', (chunk) => {
parse.parser(chunk)
// Debug.L1('parsed: ', parse.response)
Debug.L1('parse done after parser call:', parse.done);
if (parse.done) {
resolve(parse.response);
parse.reset() // sets .done to false and clears out .response
Debug.L1('response and done after resolve/complete, ', parse.response, parse.done);
port.reset(); //removes all listners to avoid stacking on next call to sendPort
}
});
port.on('error', (err) => {
reject(err);
});
port.write(cmd);
});
},
Parse 对象看起来像这样
// See sendPort - used with custom parser function to return response and completion flag
Parse: function(parser) {
let parse = function() {}
parse.parser = parser;
parse.reset = function reset() {
this.response = [];
this.done = '';
}
parse.reset(); // used here to intialize response and
return parse
}
然后你需要编写你自己的解析器函数,你传递到这里
let parse = _.Parse(parser);
特定于您的设备。这是用于 NCD ProXR 中继板。
parse: function(chunk) {
for (var byte of chunk) {
this.response.push(byte);
Debug.L1('response being built ', this.response)
}
Debug.L1('current chunck response ', this.response)
// api version where first byte is 170,
if (this.response[1]) { // second slot is number of bits to follow exlcuding checksum
if (this.response.length >= 3 + this.response[1]) { // 3 = 170 + number of bits bit + checksum
this.done = true
}
}
},
为了让它不堆叠 "data" 个侦听器,我在创建端口时添加了一个重置方法,当我知道已检索到完整的响应时可以调用该方法。我使用了 removeALLlisteners,因为我无法让单曲工作,没关系,我知道代码中的任何地方都没有其他 "data" 侦听器。
let serialport = require('serialport'),
createPort: function(sysDevName, opts) {
opts = opts || {};
opts.autoOpen = false; // actually open device later
Debug.L1(sysDevName, opts);
let port = new serialport(sysDevName, opts, (err) => {
if (err) {
Debug.L1("create error" + err.message);
return err;
}
})
port.reset = function() {
this.removeAllListeners("data");
this.removeAllListeners("error");
}
return port;
最后要注意的是 Parse
对象包含一个 .reset
方法,您会看到它和 port.reset
在完成完整响应后被调用。您需要这样做,否则 done 标志不会变为 false,并且 .response
仍将包含前一个并且 "data"
听众将堆叠。