You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
webserial/script.js

141 lines
4.1 KiB
JavaScript

// Globals
const addDeviceMessage = `Add a device...         `
const addPort = document.getElementById('add-port')
const autoscrollCheckbox = document.getElementById('autoscroll-checkbox');
const baud = document.getElementById('baud');
const clearButton = document.getElementById('clear-button');
const connectButton = document.getElementById('connect-button')
const refreshPorts = document.getElementById('refresh-ports');
const scrollableElement = document.getElementById('scrollable-element');
const select = document.getElementById('serial-select');
let autoscroll = true;
let serialPorts = [];
let reader;
// Event Listeners
addPort.addEventListener('click', async () => {
const port = await navigator.serial.requestPort();
serialPorts.push(port);
updateSerialSelect(serialPorts);
});
autoscrollCheckbox.addEventListener('change', (e) => {
autoscroll = e.target.checked;
if (autoscroll) {
scrollToBottom();
}
});
clearButton.addEventListener('click', () => {
while (scrollableElement.firstChild) {
scrollableElement.removeChild(scrollableElement.firstChild);
}
});
connectButton.addEventListener('click', async () => {
const selectedPort = serialPorts[select.selectedIndex]
const baudRate = Math.round(baud.value)
if (selectedPort) {
await connectToSerialPort(selectedPort, baudRate);
}
});
refreshPorts.addEventListener('click', async () => {
while (select.children.length > 1) {
select.removeChild(select.lastChild);
}
ports = await navigator.serial.getPorts();
console.log(ports)
ports.forEach(port => {
const option = buildPortOption(port)
select.appendChild(option);
});
});
// Functions
function buildPortOption(port) {
const option = document.createElement('option');
option.value = port;
try {
const info = port.getInfo();
if (info && 'usbVendorId' in info && 'usbProductId' in info) {
const { usbVendorId, usbProductId } = info;
option.text = `Device ${usbVendorId}:${usbProductId}`;
} else {
console.error('getInfo() did not return expected properties:', info);
option.text = 'Unknown Device';
}
} catch (error) {
console.error('Error retrieving port information:', error);
option.text = 'Unknown Device';
}
return option;
}
function addText(text) {
const newText = document.createElement('p');
newText.textContent = `${new Date().toLocaleTimeString()} ${text}`;
scrollableElement.appendChild(newText);
if (autoscroll) {
scrollToBottom();
}
}
function scrollToBottom() {
scrollableElement.scrollTop = scrollableElement.scrollHeight;
}
// Async Functions
async function connectToSerialPort(port, baud) {
await port.open({ baudRate: baud });
let buffer = ''
const textDecoder = new TextDecoderStream();
const readableStreamClosed = port.readable.pipeTo(textDecoder.writable);
const reader = textDecoder.readable.getReader();
try {
while (true) {
const { value, done } = await reader.read();
if (done) {
break;
}
buffer += value;
while (buffer.includes('\n')) {
const newlineIndex = buffer.indexOf('\n');
const line = buffer.slice(0, newlineIndex);
buffer = buffer.slice(newlineIndex + 1);
addText(line);
}
}
} catch (error) {
console.error('Error reading data from serial port:', error);
} finally {
reader.releaseLock();
await readableStreamClosed.catch(() => { });
await port.close();
}
}
async function updateSerialSelect(ports) {
if (ports.length < 1) {
const option = document.createElement('option');
option.text = addDeviceMessage;
select.innerHTML = ''
select.appendChild(option)
return;
}
ports.forEach(port => {
const option = buildPortOption(port)
select.appendChild(option);
});
select.removeChild(select.firstElementChild);
}