拔掉串行设备会导致错误“文件描述符错误”;重新初始化串口最终会收到不一致的数据

问题描述

以下 node.js 脚本扫描自定义 FTDI 设备的所有端口,一旦找到该设备,它就会检查其序列号和温度。 console.log 显示

Serial number: 1003
Temperature: 28

如果我拔掉设备,我会收到以下错误Port closed: bad file descriptor。当我重新插入设备时,我得到了一些未定义的行为。有时我得到正确的序列号但温度不正确:

Serial number: 1003
Temperature: 0

有时我会收到来自设备的回复 unkNown command代码显示在下面的代码段中)。但是,如果我在 Visual Studio Code 中调试脚本,在 ftdiPort = new serialPort(path,{baudrate: 115200}); 处设置断点并在重新连接设备后等待 4 秒以上继续,我会得到正确的数据。

VSC serialport debug

代码

'use strict';
const serialPort = require('serialport');
let ftdiPort;

searchFtdiPort();

//Check all ports every 1 second if device is connected
function searchFtdiPort() {
    let checkPorts = setInterval(function() {
        serialPort.list().then(ports => {
            for(let i = 0; i < ports.length; i++) {
                if(ports[i].manufacturer == 'FTDI') {
                    openFtdiPort(ports[i].path);
                    clearInterval(checkPorts);
                    break;
                }
            }
        });
    },1000);
}

//When device is connected,open port and ask for serial number and temperature
function openFtdiPort(path) {
    ftdiPort = new serialPort(path,{baudrate: 115200});
    let Readline = require('@serialport/parser-readline');
    let parser = ftdiPort.pipe(new Readline({delimiter: '\n'}));
    ftdiPort.on('open',function() {
        getSerial(path);
        getTemperature(path);
    });
    ftdiPort.on('error',function(error) {
        console.log('Port error: ',error.message);
    });
    ftdiPort.on('close',function(info) {
        console.log('Port closed: ',info.message);
        searchFtdiPort();
    });
    parser.on('data',function(data) {
        parseFtdiData(data);
    });
}

function parseFtdiData(data) {
    let key = res[0];
    let value = res[1];
    switch(key) {
        case 'serial':
            console.log('Serial number:',value);
            break;
        case 'fmcw_temp':
            console.log('Temperature:',value);
            break;
        default:
            console.log('Key not specified.');
            break;
    }
}

function getSerial(path) {
    let serialCmd = 'get_serial\n';
    ftdiPort.write(serialCmd,function(error) {
        if(error) {
            console.log('Writing on port Failed: ',error.message);
            return;
        }
        console.log('Write',serialCmd,'on',path);
    });
}
function getTemperature(path) {
    let serialCmd = 'fmcw_temp\n';
    ftdiPort.write(serialCmd,path);
    });
}

Linux 上的调试信息(例如,这里我得到的是 unkNown command 而不是 temperature=0):

user@linux-ayq9:~/Desktop/Service> DEBUG=* node test.js 
  serialport/bindings loading LinuxBinding +0ms
  serialport/stream .list +0ms
  serialport/stream opening path: /dev/ttyUSB0 +51ms
  serialport/binding-abstract open +0ms
  serialport/stream _read queueing _read for after open +1ms
  serialport/bindings/poller Creating poller +0ms
  serialport/stream opened path: /dev/ttyUSB0 +0ms
  serialport/stream _write 11 bytes of data +1ms
  serialport/binding-abstract write 11 bytes +2ms
  serialport/stream _read reading { start: 0,toRead: 65536 } +0ms
  serialport/binding-abstract read +1ms
  serialport/bindings/unixWrite Starting write 11 bytes offset 0 bytesToWrite 11 +0ms
  serialport/bindings/unixRead Starting read +0ms
  serialport/bindings/unixWrite write returned: wrote 11 bytes +0ms
  serialport/bindings/unixWrite Finished writing 11 bytes +1ms
  serialport/stream binding.write write finished +2ms
  serialport/stream _write 10 bytes of data +0ms
  serialport/binding-abstract write 10 bytes +1ms
Write get_serial
 on /dev/ttyUSB0
  serialport/bindings/unixWrite Starting write 10 bytes offset 0 bytesToWrite 10 +0ms
  serialport/bindings/unixRead read error { [Error: EAGAIN: resource temporarily unavailable,read] errno: -11,code: 'EAGAIN',syscall: 'read' } +1ms
  serialport/bindings/unixRead waiting for readable because of code: EAGAIN +0ms
  serialport/bindings/poller Polling for "readable" +3ms
  serialport/bindings/unixWrite write returned: wrote 10 bytes +1ms
  serialport/bindings/unixWrite Finished writing 10 bytes +0ms
  serialport/stream binding.write write finished +1ms
Write fmcw_temp
 on /dev/ttyUSB0
  serialport/bindings/poller received "readable" +16ms
  serialport/bindings/unixRead Starting read +16ms
  serialport/bindings/unixRead Finished read 48 bytes +0ms
  serialport/stream binding.read finished { bytesRead: 48 } +15ms
Serial number: 1003
Temperature: 28
  serialport/stream _read reading { start: 48,toRead: 65488 } +0ms
  serialport/binding-abstract read +16ms
  serialport/bindings/unixRead Starting read +0ms
  serialport/bindings/unixRead read error { [Error: EAGAIN: resource temporarily unavailable,syscall: 'read' } +1ms
  serialport/bindings/unixRead waiting for readable because of code: EAGAIN +0ms
  serialport/bindings/poller Polling for "readable" +1ms
  serialport/bindings/poller error [Error: bad file descriptor] +3s
  serialport/stream binding.read error [Error: bad file descriptor] +3s
  serialport/stream disconnected [Error: bad file descriptor] +0ms
  serialport/stream #close +1ms
  serialport/binding-abstract close +3s
  serialport/stream _read queueing _read for after open +0ms
  serialport/bindings/poller Stopping poller +2ms
  serialport/bindings/poller Destroying poller +1ms
  serialport/stream binding.close finished +1ms
Port closed:  bad file descriptor
  serialport/stream .list +1s
  serialport/stream .list +1s
  serialport/stream .list +1s
  serialport/stream opening path: /dev/ttyUSB0 +44ms
  serialport/binding-abstract open +3s
  serialport/stream _read queueing _read for after open +0ms
  serialport/bindings/poller Creating poller +3s
  serialport/stream opened path: /dev/ttyUSB0 +2ms
  serialport/stream _write 11 bytes of data +0ms
  serialport/binding-abstract write 11 bytes +2ms
  serialport/stream _read reading { start: 0,toRead: 65536 } +0ms
  serialport/binding-abstract read +0ms
  serialport/bindings/unixWrite Starting write 11 bytes offset 0 bytesToWrite 11 +6s
  serialport/bindings/unixRead Starting read +6s
  serialport/bindings/unixWrite write returned: wrote 11 bytes +0ms
  serialport/bindings/unixWrite Finished writing 11 bytes +0ms
  serialport/stream binding.write write finished +0ms
  serialport/stream _write 10 bytes of data +0ms
  serialport/binding-abstract write 10 bytes +0ms
Write get_serial
 on /dev/ttyUSB0
  serialport/bindings/unixWrite Starting write 10 bytes offset 0 bytesToWrite 10 +0ms
  serialport/bindings/unixRead read error { [Error: EAGAIN: resource temporarily unavailable,syscall: 'read' } +0ms
  serialport/bindings/unixRead waiting for readable because of code: EAGAIN +1ms
  serialport/bindings/poller Polling for "readable" +2ms
  serialport/bindings/unixWrite write returned: wrote 10 bytes +1ms
  serialport/bindings/unixWrite Finished writing 10 bytes +0ms
  serialport/stream binding.write write finished +1ms
Write fmcw_temp
 on /dev/ttyUSB0
  serialport/bindings/poller received "readable" +21ms
  serialport/bindings/unixRead Starting read +21ms
  serialport/bindings/unixRead Finished read 71 bytes +0ms
  serialport/stream binding.read finished { bytesRead: 71 } +22ms
UnkNown command: get_serial
UnkNown command: fmcw_temp
  serialport/stream _read reading { start: 71,toRead: 65465 } +0ms
  serialport/binding-abstract read +23ms
  serialport/bindings/unixRead Starting read +1ms
  serialport/bindings/unixRead read error { [Error: EAGAIN: resource temporarily unavailable,syscall: 'read' } +0ms
  serialport/bindings/unixRead waiting for readable because of code: EAGAIN +0ms
  serialport/bindings/poller Polling for "readable" +1ms

因此在连接丢失后重新初始化端口似乎无法正常工作。我不知道这是 node.js 串行端口的一般问题,还是我使用的包不正确。也许这与我的 Linux 发行版有关(顺便说一下,它是 openSuse 15.1)。 如果有人能在这里帮助我,我会很高兴。谢谢。

解决方法

如前所述,如果您在重新连接设备后等待 4 秒以上继续,您会获得正确的数据,这意味着缓冲区没有被清除或之前的操作仍在进行中。

似乎嵌入式设备可能正忙于处理先前的命令或某些中间缓冲区没有被清除。