简体   繁体   中英

Node.js and serialport ; Callback method?

I'm trying to list the all serial ports and select the port name that begins with /dev/cu.usbmodem. For context; it's an arduino hooked up to a RaspberryPi running node. The Raspberry Pi has a habit of renaming the ports every time it is rebooted.

So far I have this:

com.list(function (err, ports) {
  ports.forEach(function(port) {
    var arduinoPort = port.comName;
if (arduinoPort.substring(0, 16) == "/dev/cu.usbmodem") {
      var SERIALPORT_ID = arduinoPort;
    }
  });
});

This takes long enough that this next statement fails as the SERIALPORT_ID variable has yet to be declared;

var serialPort = new com.SerialPort(SERIALPORT_ID, {
  baudrate: 57600,
  parser: com.parsers.readline('\r\n')
});

What callback or structuring technique will make the second statement wait for the first one to declare the variable before executing?

The function below assumes that in your result ports, there is only one serial port. I changed your ports.forEach to a standard for loop. I believe the work going on in this loop was synchronous. I think forEach is synchronous, but I know for(var i = 0; ....) is sync, and if we only have one proper 'port' then we want to be able to skip looping over the other results. This logic can easily be changed if my assumption on 'only one good port' is incorrect.

function getSerialPort(callback) {
    'use strict';

    com.list(function (err, ports) {

        for (var i = 0; i < ports.length; i++) {//ports.forEach works too, but I know this is sync, and that's what we want in this case so we can break out of the loop when we find the right port
            var port = ports[i];
            var arduinoPort = port.comName;

            if (arduinoPort.substring(0, 16) === "/dev/cu.usbmodem") {

                var serialPort = new com.SerialPort(arduinoPort, {
                    baudrate: 57600,
                    parser: com.parsers.readline('\r\n')
                });

                callback(serialPort);
                return;//I'm not sure what return does in a ports.forEach situation, so I changed it to a standard for loop, so that we know that this is breaking us out of it.
            }
        }
    });
}

getSerialPort(function (serialPort) {
    'use strict';
    console.log('Serial Port: ' + serialPort);
});

The Raspberry Pi has a habit of renaming the ports every time it is rebooted.

Well, you could also create some udev rules for the USB hardware you are using, so that the arduino will always be mapped to the same serial port. Assuming you are running debian...

vim /etc/udev/rules.d/98-usb-serial.rules

SUBSYSTEM=="tty", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0044", ATTRS{serial}=="64935343733351F072D0", SYMLINK+="arduinoUno"
SUBSYSTEM=="tty", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0043", ATTRS{serial}=="7523230313535121B0E1", SYMLINK+="arduinoMega"

To find out the vendor id, product id and serial number of a usb device use:

dmesg
lsusb

Unplug the device in question, plug it back in and it should be mapped to:

/dev/arduinoUno
/dev/arduinoMega

Or you can do that to look for the right port and connect automagically! It works great on OS X and Ubuntu, I haven't tested it yet on Raspi, but you get the idea. Thanks to ChrisCM for the "for" :)

var myPort;

function getSerialPort(callback) {

    com.list(function (err, ports) {

        for (var i = 0; i < ports.length; i++) {//ports.forEach works too, but I know this is sync, and that's what we want in this case so we can break out of the loop when we find the right port
            var port = ports[i];

                if(port.pnpId.indexOf("duino") != -1 || port.manufacturer.indexOf("duino") != -1 || port.comName.indexOf('moti') != -1){ // it look for "duino" somewhere
                    myPort = new SerialPort(port.comName,{
                    baudrate: 115200,
                    parser: serialport.parsers.readline("\r\n"),
                });

                callback(serialPort);
                return;//I'm not sure what return does in a ports.forEach situation, so I changed it to a standard for loop, so that we know that this is breaking us out of it.
            }
        }
    });
}

getSerialPort(function (myPort) {
    console.log('Serial Port: ' + myPort);
});

You can also output all the port specs using:

console.log("pnpId: " + port.pnpId);
console.log("manufacturer: " + port.manufacturer);
console.log("comName: " + port.comName);
console.log("serialNumber: " + port.serialNumber);
console.log("vendorId: " + port.vendorId);
console.log("productId: " + port.productId);

to find a pattern you could use for automatic connection.

Hope it helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM