如何在开发过程中模拟串口?

How can I mock serial port during development?

我正在为我的 Raspberry Pi 开发一个 node.js 应用程序,它从串行端口接收数据,但我没有直接在上面开发应用程序,而是使用我的主计算机。所以我的 app.js 中有这段代码:

var serialport = require("serialport");
var SerialPort = serialport.SerialPort;
var sp = new SerialPort("/dev/ttyACM0", {
    parser: serialport.parsers.readline("\n")
});

sp.on("data", function (rawData) {
...

这在 Rasperry Pi 上运行良好,但我希望能够先 运行 我的开发计算机上的应用程序,而不必注释有关串行端口的每个代码块。

实现此目标的最佳方法是什么?有没有办法模拟串口?

AFAIK,目前没有任何库可以在本机执行此操作。我以前做的是用node-serialport库自带的测试代码为例,eg: https://github.com/Manetos/node-serialport/blob/157e6f9df7989abd72d509c9827d13b2b10258de/test_mocks/linux-hardware.js

如果你看一下那个文件,他们正在为他们自己的测试模拟串口行为,你可以简单地复制他们在那里所做的并在你的东西中使用它,你应该很好去吧。

希望对您有所帮助!

我需要同样的东西,但无法找到具体操作方法的详细信息,但我在搜索中一直遇到这个问题。经过一些研究并在不同领域找到一些模糊的参考资料后,我能够整理出以下内容。希望这对可能登陆这里的其他人有所帮助。

您可以使用自己的扩展 SerialPort - MockBindings class,然后简单地实现自定义 write 函数,该函数将接收数据,形成适当的响应,然后将其发送回来电者。

const MockSerialBinding = require('@serialport/binding-mock');

class EmulatedDeviceSerialBinding extends MockSerialBinding {
    constructor(opt = {}) {
        super(opt);
    }

    // THIS IS THE METHOD THAT GETS TRIGGERED WHEN THE CODE TO TEST WRITES TO A DEVICE
    async write(buffer) {
        // Use this method to detect the supported commands and emulate a response
        const cmd = Buffer.from(buffer).toString();

        let response = 'Unknown Command!'; // Default response

        // Custom logic here to determine the proper response

        super.emitData(response);
    }
}

module.exports = EmulatedDeviceSerialBinding;

为了您的测试,请准备一个使用上述 class 的可以作为目标的假串口设备:

const SerialPort = require('serialport');
SerialPort.Binding = EmulatedDeviceSerialBinding;

// Setup a new mock serial device that can be the target
EmulatedDeviceSerialBinding.createPort('ttyUSB_TestTarget', {
    echo: true,
    readyData: '\r\nhostname@user:~$ ' // This will append a 'prompt' to the end of each response (like a linux terminal would)
});

现在您的逻辑将是相同的,只是您连接到模拟设备端口而不是真实端口。这是 Express Route 中间件的片段:

const SerialPort = require('serialport');
const SerialRegexParser = require('@serialport/parser-regex');

const serialParser = new SerialRegexParser({regex: /(?<Prompt>.*[$#]\s*$)/m});

const serialPortOptions = {
    baudRate: 115200
};

// The req.params.devicePort value be the name of the emulated port
const port = new SerialPort(req.params.devicePort, serialPortOptions, (err) => {
    if (err) {
        return res.status(400).send({error: err.message});
    }
});
port.pipe(serialParser);

// THIS WILL BE TRIGGERED WHEN THE EmulatedDeviceSerialBinding does the emitData call
serialParser.once('data', (data) => {
    if (res.headersSent) return; // We've already responded to the client, we can't send more

    const dataString = Buffer.from(data).toString();

    // Remove the command executed from the beginning if it was echoed
    respDoc.data = dataString.replace(cmdToExecute, '').trimEnd();

    return res.send(respDoc);
});

// Send the command to the device 
// THIS WILL TRIGGER THE EmulatedDeviceSerialBinding.write() FUNCTION
port.write(cmdToExecute, (err) => {
    if (err) {
        return res.status(400).send({error: err.message});
    }
});

程序流程为:

Express 中间件port.write(cmdToExecute) -> EmulatedDeviceSerialBinding.write() -> Express 中间件 serialParser.once('data') 回调

我能够使用 https://sourceforge.net/projects/com0com/

提供的 com0com 调制解调器仿真器实现此目的

它将创建两个相互映射的虚拟 COM 端口(例如 COM5 和 COM6)。您可以将您的应用程序连接到其中一个 COM 端口,并将您的仿真器代码连接到另一个 COM 端口。然后可以将仿真器配置为读取输入并相应地写回。