简体   繁体   中英

Nodejs serial port to tcp

Is there a way to establish a host to stream a serial connection over tcp using nodejs - I want to stream the sensor data from the iot device on my computer to a connected computer to a web server. streaming of the raw data is fine - the remote computer will process it. I was looking into net and serialport npm packages - but im unsure of how to marry the two...

Thanks!

Pretty much each vendor or device has its own serial communication protocol. Usually these devices also use packets with headers, checksums, but each device does this in a different way.

The first question is really, to what extend you want to forward the packet headers and checksum information. You may want to translate incoming packets to events or perhaps already to some kind of JSON message.

Assuming that you just want to forward the data in raw format without any pre-processing, it is still valuable to determine where a packet starts and ends. When you flush data over TCP/IP it's best not to do so halfway one of those serial packets.

For instance, it could be that your device is a barcode scanner. Most barcode scanners send a CR (carriage return) at the end of each scan. It would make sense to actively read incoming bytes looking for a CR character. Then each time a CR character is noticed you flush your buffer of bytes.

But well, it isn't always a CR. Some devices package their data between STX (0x02) and ETX (0x03) characters. And there are some that send fixed-length packages (eg 12 bytes per message).

Just for clarity, you could end up sending your data every 100 bytes while a message is actually 12 bytes. That would break some of the packet. Once in a while your TCP receiver would receive an incomplete packet. Having said all that. You could also add all this logic on the TCP receiving side. When an incomplete packet is received, you could keep it in a buffer in the assumption that the next incoming packet will contain the missing bytes.

Note that there are commercial RS232-to-ethernet devices that you can buy of the shelf and configure (~100EUR) that do exactly what you want. And often in the setup of that kind device you would have the option to configure a flush-character. (eg that CR). MOXA is probably the best you can get. ADAM also makes decent devices. These vendors have been making this kind of devices for ~30 years.

But for the sake of exercise, here we go. First of all, you would need something to communicate with your serial device. I used this one:

npm install serialport@^9.1.0

You can pretty much blindly copy the following code. But obviously you need to set your own RS232 or USB port settings. Look in the manual of your device to determine the baudrate, databits, stopbits, parity and optionally RTS/DTR

import SerialPort from "serialport";

export class RS232Port {
    private port: SerialPort;

    constructor(private listener: (buffer: Buffer) => any, private protocol) {
        this.port = new SerialPort("/dev/ttyS0", {
            baudRate: 38400,
            dataBits: 8,
            stopBits: 1,
            parity: "none",
        });

        // check your RTS/DTR settings.
        // this.port.on('open', () => {
        //    this.port.set({rts: true, dtr: false}, () => {
        //    });
        //});

        const parser = this.port.pipe(this.protocol);
        parser.on('data', (data) => {
            console.log(`received packet:[${toHexString(data)}]`);
            if (this.listener) {
                this.listener(data);
            }
        });
    }

    sendBytes(buffer: Buffer) {
        console.log(`write packet:[${toHexString(buffer)}]`);
        this.port.write(buffer);
    }
}

The code above continuously reads data from a serial device, and uses a "protocol" to determine where messages start/end. And it has a "listener", which is a callback message. It can also send bytes with its sendBytes function.

That brings us to the protocol, which as explained earlier is something that should read until a separator is found.

Because I have no clue what your separator is. I will present you with an alternative, which sends assumes that just waits for a silence. It assumes that when there is no incoming data for a certain time, that the message will be complete.

export class TimeoutProtocol extends Transform {
    maxBufferSize: number;
    currentPacket: [];
    interval: number;
    intervalID: any;

    constructor(options: { interval: number, maxBufferSize: number }) {
        super()
        const _options = { maxBufferSize: 65536, ...options }
        if (!_options.interval) {
            throw new TypeError('"interval" is required')
        }

        if (typeof _options.interval !== 'number' || Number.isNaN(_options.interval)) {
            throw new TypeError('"interval" is not a number')
        }

        if (_options.interval < 1) {
            throw new TypeError('"interval" is not greater than 0')
        }

        if (typeof _options.maxBufferSize !== 'number' || Number.isNaN(_options.maxBufferSize)) {
            throw new TypeError('"maxBufferSize" is not a number')
        }

        if (_options.maxBufferSize < 1) {
            throw new TypeError('"maxBufferSize" is not greater than 0')
        }

        this.maxBufferSize = _options.maxBufferSize
        this.currentPacket = []
        this.interval = _options.interval
        this.intervalID = -1
    }

    _transform(chunk: [], encoding, cb) {
        clearTimeout(this.intervalID)
        for (let offset = 0; offset < chunk.length; offset++) {
            this.currentPacket.push(chunk[offset])
            if (this.currentPacket.length >= this.maxBufferSize) {
                this.emitPacket()
            }
        }
        this.intervalID = setTimeout(this.emitPacket.bind(this), this.interval)
        cb()
    }
    emitPacket() {
        clearTimeout(this.intervalID)
        if (this.currentPacket.length > 0) {
            this.push(Buffer.from(this.currentPacket))
        }
        this.currentPacket = []
    }
    _flush(cb) {
        this.emitPacket()
        cb()
    }
}

Then finally the last piece of the puzzle is a TCP/IP connection. Here you have to determine which end is the client and which end is the server.

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