1

我遇到了一个问题,即我尝试使用的基于承诺的代码并不是每次都得到完整的响应。我将数据侦听器与 .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映射串口写入接收数据

4

1 回答 1

2

从串口 gitter的人们那里得到了一些帮助,所以发布了一个我想出的完整的解决方案。底线是您必须使用 .on ,然后您必须以某种方式知道要返回多少字节。就我的设备而言,我得到一个前导字节,然后是第二个字节,告诉后面有多少字节,最后一个字节是校验和。我写这篇文章是为了让人们可以“插入”他们自己的缓冲区解析器,该解析器会不断连接块,直到您通过将完成标志更改为 true 来告诉它不要这样做。

所以sendPort上面的结果是这样的,其中port已经创建并打开了serialPortcmd是您作为缓冲区到设备的传出命令,并且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
        }
    }
},

为了避免堆叠“数据”侦听器,我在创建端口时添加了一个重置​​方法,当我知道已检索到完整响应时可以调用该方法。我使用 removeALLlisteners 因为我无法让单曲工作,没关系,我知道代码中没有其他“数据”侦听器在任何地方。

 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"侦听器将堆叠。

于 2016-10-18T19:00:32.737 回答