Вам нужен какой-то тайм-аут, чтобы определить, не отвечает ли порт. Я также настоятельно рекомендую вам проверить данные ответа и отправить что-то большее, чем простая AT-команда, потому что многие другие устройства реагируют на AT-команды, такие как контроллеры RGB для игровых ПК и некоторые телефоны Android, настроенные как модемы.
Что-то вроде следующего должно работать:
function checkPort (path, callback) { // callback(error, path)
let sock = new SerialPort(path, { baudRate: 9600 }, (err, data) => {
let timer = setTimeout(() => {
callback(new Error('Timeout'));
}, 100); // 100ms should be enough. If not increase it
sock.on('data', (err, data) => {
clearTimeout(timer); // clear the timer
if (err) {
return callback(err);
}
else {
return callback(null, path);
}
})
sock.write("AT");
})
}
Теперь вы можете проверить, какой порт подключен:
function findConnectedPort (callback) {
SerialPort.list().then(ports => {
portCount = ports.length;
ports.forEach(port => {
checkPort(port.path, (err, foundPath) => {
if (err) {
// Ignore errors or deal with them how you want
}
else {
// Great! Got response. Return the path:
if (portCount > 0) { // prevent calling callback
// more than once
callback(null, foundPath);
}
portCount = 0;
}
portCount--;
if (portCount <= 0) {
// Well, none of the ports responded so we
// return an error:
callback(new Error('Not found'));
}
})
})
})
}
Теперь, чтобы найти подключенный порт, просто выполните:
findConnectedPort((err,path) => {
if (err) {
console.error(err);
}
else {
console.log("RTU CONNECTED at " + path);
// Do what you need with the port here...
}
})
Обещания и асинхронность/ожидание
Пока код выше работает. Для асинхронного кода, который требует большого количества условной логики, подобной этой, я считаю, что использовать async/await гораздо проще. Для этого вам нужно преобразовать свой код, чтобы он возвращал обещания:
function checkPort (path) {
return new Promise((resolve, reject) => {
let sock = new SerialPort(path, { baudRate: 9600 }, (err, data) => {
let timer = setTimeout(() => {
reject(new Error('Timeout'));
}, 100); // 100ms should be enough. If not increase it
sock.on('data', (err, data) => {
clearTimeout(timer); // clear the timer
if (err) {
return reject(err);
}
else {
return resolve(path);
}
})
sock.write("AT");
})
});
}
Теперь цикл for легче понять, хотя теперь вы не можете использовать forEach
или map
или filter
или любые методы массива. Вам нужно использовать for
или while
, если вы хотите использовать async/await:
async function findConnectedPort () {
let ports = await SerialPort.list();
for (let i=0; i<ports.length; i++) {
let port = ports[i];
try {
// return the first successful result:
return await checkPort(port.path);
}
catch (err) {
// ignore errors or handle them how you like
// just remember that we use an error to signal
// a timeout which simply means no device
// responded
}
}
// we didn't find anything. In this case I prefer to return
// nothing instead of returning an error:
return null;
}
Теперь вы можете просто получить подключенный порт, выполнив:
async function main () {
let connectedPath = await findConnectedPort();
if (connectedPath === null) {
console.log('No devices found!');
}
else {
// Do what you need with the port here...
}
}
main();
person
slebetman
schedule
23.10.2020