Чтение GPS-приемника с помощью WebUSB

Я пытаюсь использовать WebUSB для чтения GPS-координат с подключенного через USB GPS-приемника из javascript.

Мне удалось подключиться к ресиверу; однако я не уверен, как использовать WebUSB для доступа к сообщениям NMEA.

Пока у меня есть следующий проверочный код:

<html>
  <head>
    <title>WebUSB Serial Sample Application</title>
  </head>


<body>
 <a href="#" id = "click">Connect</a><br>
 <a href="#" id = "send">Send Data</a><br>
 <a href="#" id = "read">Read Data</a><br>
 <script>
 
let y;
let device;

var connectButton = document.getElementById('click')
connectButton.addEventListener('click', function() {
    navigator.usb.requestDevice({
        filters: [{}]
    }).then((selectedDevice) => {
        device = selectedDevice;
        return device.open()
            .then(() => device.selectConfiguration(1))
            .then(() => device.claimInterface(device.configuration.interfaces[0].interfaceNumber))
            .then(() => device.selectAlternateInterface(device.configuration.interfaces[0].interfaceNumber, 0))
            .then(() => {
                y = device;
            })
    });
})

var sendButton = document.getElementById('send')    
var sendDecoder = new TextDecoder()
sendButton.addEventListener('click', async () => {
y.controlTransferOut({
    requestType: 'class',
    recipient: 'interface',
    request: 0x22,
    value: 0x01,
    index: 0x00});
    
y.controlTransferIn({
        requestType: 'standard',
        recipient: 'device',
        request: 0x06,
        value: 0x0302,
        index: 0x409
    }, 255)
        .then(result => {
            let decoder = new TextDecoder()
            console.log(sendDecoder.decode(result.data));
            console.log('sent req');
        }).catch(error => {
            console.log(error);
        });
});

 </script>
 </body>
 </html>

Оператор transferOut позволяет мне читать имя поставщика с устройства. Итак, я знаю, что связан и могу с ним общаться. Я просто не знаю, какие конкретные команды нужны для доступа к широте и долготе с устройства.

ОБНОВЛЕНИЕ. Ниже приведен снимок информации о конфигурации устройства введите описание изображения здесь


person MSquared    schedule 28.01.2021    source источник


Ответы (2)


Есть несколько уровней, которые вам нужно понять, чтобы достичь своей цели. Первый - это интерфейс USB, реализованный в устройстве.

В опубликованном вами примере кода есть два вызова, которые отправляют команды на устройство. Первый - это controlTransferOut (), который отправляет на устройство стандартный USB-запрос CDC-ACM SET_CONTROL_LINE_STATE (0x22) для включения сигнала DTR (0x01). Если ваше устройство реализует протокол USB CDC-ACM, то это то, что нужно сделать для записи, поскольку оно сигнализирует устройству, что программное обеспечение хоста готово к приему данных. Если ваше устройство не поддерживает этот протокол, команда будет проигнорирована или завершится ошибкой. Вы уже заявляете о первом интерфейсе, чтобы понять протокол USB, который реализует интерфейс, вы должны проверить device.configuration.interfaces[0].alternates[0].interfaceClass и device.configuration.interfaces[1].alternates[0].interfaceClass. Устройство USB CDC-ACM будет иметь один интерфейс с классом 2 и один с классом 10. Класс 2 предназначен для интерфейса управления, а класс 10 - для интерфейса данных. Если ваше устройство не имеет этих двух интерфейсов, вероятно, оно не реализует протокол USB CDC-ACM, и вам нужно сначала выяснить, какой протокол оно использует.

Второй вызов, который вы делаете, - это controlTransferIn (), который отправляет стандартный запрос USB GET_DESCRIPTOR (0x06) для чтения строкового дескриптора с устройства. Передача 0x0302 просит его прочитать дескриптор строки (тип 3) в индексе 2. Это будет работать для любого USB-устройства (при условии, что индекс правильный), и поэтому не говорит вам, выяснили ли вы, какой протокол поддерживает интерфейс.

Предполагая, что это интерфейс USB CDC-ACM, вы захотите взглянуть на device.configuration.interfaces[1].alternates[0].endpoints и выяснить номера конечных точек для конечных точек IN и OUT. Это то, что вы передадите transferIn() и transferOut() для отправки и получения данных с устройства.

После того, как вы все это выяснили, вам нужно выяснить, как заставить устройство начать отправку сообщений NMEA. Если вам повезет, то в режиме по умолчанию он автоматически отправит их, и вы можете просто начать звонить transferIn(), чтобы получить их. В противном случае вам придется выяснить, какую команду отправить на устройство, чтобы перевести его в правильный режим. Если у вас есть документация для устройства или пример кода, написанный на других языках, поддерживающих это устройство, то это будет очень полезно для выяснения этого.

person Reilly Grant    schedule 29.01.2021
comment
Спасибо, Рейли. У меня только один интерфейс и class = 255; Итак, это НЕ USB-устройство CDC-ACM. Похоже, что GPS использует набор микросхем Prolific PL2303 ... который, как я обнаружил, упоминался в другом месте на StackOverflow. Однако, используя часть этого примера кода (например, stackoverflow.com / questions / 51605886 /) по-прежнему не работает. Когда я звоню в transferIn ... все просто зависает, и я никогда не получаю обещание. - person MSquared; 29.01.2021
comment
Такой вызов никогда не должен зависать так, вместо того, чтобы возвращать обещание. Если быть точным, это довольно серьезная ошибка. Можете ли вы открыть проблему на crbug.com своим примером кода? - person Reilly Grant; 31.01.2021
comment
Не уверен, какие команды мне нужно отправить, поскольку устройство НЕ использует USB CDC-ACM. Устройство представляет собой GPS-приемник от GlobalSat (bu-353-s4). Он использует набор микросхем Prolific PL2303. После того, как я выберу конфигурацию, запрошу единственный интерфейс и выберу единственный альтернативный (alternates [0]), вызов transferIn к конечной точке 0 (in, interrupt) вернется .... однако ни операторы then, ни catch никогда не выполняются. Когда я пытаюсь отправить transferIn в конечную точку 3 (которая отображается как массовая и входящая), я получаю DOMException: указанная конечная точка не является частью заявленного и выбранного альтернативного интерфейса. - person MSquared; 02.02.2021

Я наконец решил эту проблему. Ответом (во всяком случае для меня) была покупка другого GPS-приемника, в котором реализован интерфейс CDC-ACM, поскольку, кажется, есть больше примеров и лучших документов для этого протокола.

Следующий проверочный код работает:

<html>
  <head>
    <title>WebUSB Serial Sample Application</title>
  </head>


<body>
 <a href="#" id = "click">Connect</a><br>
 <a href="#" id = "read">Read Data</a><br>
 <script>
 
let y;
let device;

var connectButton = document.getElementById('click')
connectButton.addEventListener('click', function() {
    navigator.usb.requestDevice({
        filters: [{}]
    })
    .then((selectedDevice) => {
        device = selectedDevice;
        return device.open();
    })
    .then(() => device.selectConfiguration(1))
    .then(() => device.claimInterface(device.configuration.interfaces[0].interfaceNumber))
    .then(() => device.claimInterface(device.configuration.interfaces[1].interfaceNumber))
    .then(() => device.selectAlternateInterface(device.configuration.interfaces[0].interfaceNumber, 0))
    .then(() => device.selectAlternateInterface(device.configuration.interfaces[1].interfaceNumber, 0))
    .then(() => {
        y = device;
    })
})

var readButton = document.getElementById('read')
var readDecoder = new TextDecoder()
var readLoop = () => {
    y.transferIn(2,64)
        .then(result => {
            let decoder = new TextDecoder()
            console.log(readDecoder.decode(result.data.buffer));
            readLoop();
        }).catch(error => {
            console.log(error);
        });
};

readButton.addEventListener('click', async () => {
    readLoop();
});


 </script>
 </body>
 </html>
person MSquared    schedule 05.02.2021