Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.4k views
in Technique[技术] by (71.8m points)

node.js - Unplugging serial device causes error 'bad file descriptor'; reinitialising the serial port ends up receiving inconsistent data

The following node.js script scans all ports for a custom FTDI device and once the device is found, it checks its serial number and temperature. console.log shows:

Serial number: 1003
Temperature: 28

If I unplug the device I get the following error: Port closed: bad file descriptor. When I re-plug the device I get some undefined behaviour. Sometimes I get the correct serial number but an incorrect temperature:

Serial number: 1003
Temperature: 0

Sometimes I get the reply unknown command from the device (code is not shown in the snippet below). However if I debug the script in Visual Studio Code, set a breakpoint at ftdiPort = new serialPort(path, {baudRate: 115200}); and wait 4+ seconds to go on after reconnecting the device, I get the correct data.

VSC serialport debug

Code:

'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: '
'}));
    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
';
    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
';
    ftdiPort.write(serialCmd, function(error) {
        if(error) {
            console.log('Writing on port failed: ', error.message);
            return;
        }
        console.log('Write', serialCmd, 'on', path);
    });
}

DEBUG information on Linux (here I get unknown command instead of temperature=0 for example):

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, 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" +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, read] errno: -11, code: 'EAGAIN', 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, read] errno: -11, code: 'EAGAIN', syscall: 'read' } +0ms
  serialport/bindings/unixRead waiting for readable because of code: EAGAIN +0ms
  serialport/bindings/poller Polling for "readable" +1ms

So reinitialising the port after a connection loss seems to not working properly. I don't know if it's a general problem with node.js serialport, or if I am using the package incorrectly. Maybe it's something with my Linux distribution (it's openSuse 15.1 by the way). I would be glad if someone could help me out here. Thank you.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As mentioned if you wait 4+ seconds to go on after reconnecting the device, you get the correct data means the buffer are not getting cleared or previous operation is still in progress.

It appears that the embedded device may be busy processing previous command or some intermediate buffer is not getting cleared.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...