您现在的位置是:网站首页> HTML&JS
chrome里JS操作硬件
- HTML&JS
- 2023-10-16
- 442人已阅读
chrome里js操作硬件
操作串口
页面部分
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<link rel="stylesheet" href="/cloudSerial/css/bootstrap.min.css">
<link rel="manifest" href="/cloudSerial/manifest.json">
</head>
<style>
.banner {
align-content: center;
display: none;
justify-content: center;
width: 100%;
}
</style>
<body>
<nav class="navbar navbar-default navbar-fixed-top" style="background-color: #009966;">
<div class="container navbar-left">
<div class="navbar-header">
<!--<a class="navbar-brand " href="#">
<img src="img/rtlogo.png" width="25px" height="25px" onclick="menu()">
</a>-->
<text class="navbar-text" style="color: white;font-size: 20px;">串口调试助手</text>
<text id="serialID" class="navbar-text" style="color: white;font-size: 20px;"></text>
<text id="serialStatus" class="navbar-text" style="color: white;font-size: 20px;"></text>
</div>
</div>
</nav>
<div class="col-sm-12" id="contentDis " style="padding-top: 100px; ">
<div class="col-sm-3">
<div class="panel panel-default">
<div class="panel-heading">串口配置</div>
<div class="panel-body">
<text>串口号:</text>
<input type="text" name="" id="portName">
<button class="btn btn-info" id="portSelectBtn" onclick="portSelect()">选择串口</button>
<br /><br />
<text>波特率:</text>
<select id="baudRate" style="width:100px">
<option value="">1200</option>
<option value="">2400</option>
<option value="">4800</option>
<option value="" selected="selected">9600</option>
<option value="">115200</option>
</select><br /><br />
<text>校验位:</text>
<select id="parity" style="width:100px">
<option value="">none</option>
<option value="">odd</option>
<option value="">even</option>
</select><br /><br />
<text>数据位:</text>
<select id="dataBits" style="width:100px">
<option value="">8</option>
<option value="">7</option>
<option value="">6</option>
<option value="">5</option>
</select><br /><br />
<text>停止位:</text>
<select id="stopBits" style="width:100px">
<option value="">1</option>
<option value="">2</option>
</select><br /><br />
<button class="btn btn-info" onclick="serialOpen()" id="btnOpen">打开</button>
<button class="btn btn-info" style="margin-left: 20px;" onclick="serialClose()" id="btnClose">关闭</button>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">控制</div>
<div class="panel-body">
<!-- <input type="checkbox" name="options" id="hexOption" > 16进制/字符串:发送
<br />
<br />
<input type="checkbox" name="options2" id="hexOption2"> 16进制/字符串:接收
<br />
<br /> -->
<button class="btn btn-info" id="receiverClear" onclick="receiverClear()">
清空接收区
</button>
</div>
</div>
</div>
<div class="col-sm-9">
<textarea rows="20" cols="80" id="receiverText">欢迎使用网页版串口助手。</textarea>
<div style="margin-top: 10px;">
<textarea rows="1" cols="60" style="float: left;" id="sendText"></textarea>
<button class="btn-info" style="margin-left: 10px;" onclick="serialSend()">
发送
</button>
</div>
</div>
<script type="text/javascript" src="/cloudSerial/js/jquery.min.js"></script>
<script type="text/javascript" src="/cloudSerial/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/cloudSerial/js/index.js"></script>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/cloudSerial/sw.js',{scope:'/cloudSerial/'})
.then(registration => {
console.log('SW registered with scope:', registration.scope);
})
.catch(err => {
console.error('Registration failed:', err);
});
});
}
</script>
</body>
</html>
JS部分
let port = null;
let reader = null;
// serialReceive();
if ("serial" in navigator) {
// The Web Serial API is supported.
console.log("The Web Serial API is supported");
} else {
console.log("The Web Serial API is not supported");
}
async function portSelect() {
port = await navigator.serial.requestPort();
console.log(JSON.stringify(port.getInfo()));
// let ele = document.createElement('option');
// ele.setAttribute("value",JSON.stringify(port.getInfo()));
// ele.setAttribute("selected","selected");
// ele.innerHTML=JSON.stringify(port.getInfo())
// $("#portName")[0].appendChild(ele);
if (port) {
$("#portName").val(JSON.stringify(port.getInfo()));
}
}
//打开串口
async function serialOpen() {
if (port == null) {
alert('打开串口出错');
return;
}
let opt = {
baudRate: 9600,
parity: 0,
dataBits: 8,
stopBits: 1
};
opt.baudRate = parseInt($('#baudRate option:selected').text());
opt.parity = $('#parity option:selected').text();
// switch (tmp) {
// case "none":
// opt.parityMode = 0;
// break;
// case "odd":
// opt.parityMode = 1;
// break;
// case "even":
// opt.parityMode = 2;
// break;
// }
opt.dataBits = parseInt($('#dataBits option:selected').text());
opt.stopBits = parseInt($('#stopBits option:selected').text());
// Wait for the serial port to open.
await port.open(opt);
$("#btnOpen").attr('disabled', 'disabled');
// while (port.readable) {
reader = port.readable.getReader();
try {
while (true) {
const {
value,
done
} = await reader.read();
if (done) {
// Allow the serial port to be closed later.
reader.releaseLock();
break;
}
if (value) {
//value is a Uint8Array.
console.log(value);
const strvalue = new TextDecoder("utf-8").decode(value);
console.log(strvalue);
const temp = $("#receiverText").val();
$("#receiverText").val(temp + strvalue);
}
}
} catch (error) {
// TODO: Handle non-fatal read error.
}
// }
}
//关闭串口
async function serialClose() {
$('#btnOpen').removeAttr('disabled');
try {
await reader.cancel();
await port.close();
} catch (e) {
console.log(e);
//TODO handle the exception
}
}
//串口发送
async function serialSend() {
console.log(document.getElementById("sendText").value.length);
if (document.getElementById("sendText").value.length == 0) {
alert("发送内容不能为空");
return;
}
// console.log(document.getElementById("hexOption").checked);
// hexOption = document.getElementById("hexOption").checked;
const data = $("#sendText").val();
//是否选中16进制
// if (hexOption) {
// const writer = port.writable.getWriter();
// const data = new Uint8Array([104, 101, 108, 108, 111]); // hello
// await writer.write(data);
// // Allow the serial port to be closed later.
// writer.releaseLock();
// } else {
const textEncoder = new TextEncoderStream();
const writableStreamClosed = textEncoder.readable.pipeTo(port.writable);
const writer = textEncoder.writable.getWriter();
await writer.write(data);
// Allow the serial port to be closed later.
writer.releaseLock();
// }
}
//清空接收区
function receiverClear() {
console.log("clear");
document.getElementById("receiverText").value = "";
}
操作蓝牙
页面部分
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>WebBle</title>
<link rel="stylesheet" href="/webBle/css/bootstrap.min.css">
<link rel="manifest" href="/webBle/manifest.json">
</head>
<body>
<nav class="navbar navbar-default navbar-fixed-top" style="background-color: #009966;">
<div class="container navbar-left">
<div class="navbar-header">
<text class="navbar-text" style="color: white;font-size: 20px;">ble调试助手</text>
<text id="serialID" class="navbar-text" style="color: white;font-size: 20px;"></text>
<text id="serialStatus" class="navbar-text" style="color: white;font-size: 20px;"></text>
</div>
</div>
</nav>
<div class="panel panel-default" style="padding-top: 100px; ">
<div class="panel-heading">
<button id="scanBtn" type="button">scan</button>
</div>
<div class="panel-body">
<table class="table">
<thead>
<tr>
<th scope="col">service</th>
<th scope="col">characteristic</th>
<th scope="col">properties</th>
<th scope="col">value</th>
<th scope="col">
action
</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<script type="text/javascript" src="/webBle/js/jquery.min.js"></script>
<script type="text/javascript" src="/webBle/js/index.js"></script>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/webBle/sw.js', {
scope: '/webBle/'
})
.then(registration => {
console.log('SW registered with scope:', registration.scope);
})
.catch(err => {
console.error('Registration failed:', err);
});
});
}
</script>
</body>
</html>
JS代码部分
index.js
let newservices = [];
$("#scanBtn")[0].addEventListener('click', function() {
console.log('Requesting any Bluetooth Device...');
navigator.bluetooth.requestDevice({
// filters: [...] <- Prefer filters to save energy & show relevant devices.
// filters: [{
// services: ['6e400001-b5a3-f393-e0a9-e50e24dcca9e']
// }]
// acceptAllAdvertisements: true,
// keepRepeatedDevices: true,
acceptAllDevices: true,
optionalServices: [
'6e400001-b5a3-f393-e0a9-e50e24dcca9e',
"alert_notification",
"automation_io",
"battery_service",
"blood_pressure",
"body_composition",
"bond_management",
"continuous_glucose_monitoring",
"current_time",
"cycling_power",
"cycling_power",
"cycling_speed_and_cadence",
"device_information",
"environmental_sensing",
"generic_access",
"generic_attribute",
"glucose",
"health_thermometer",
"heart_rate",
"human_interface_device",
"immediate_alert",
"indoor_positioning",
"internet_protocol_support",
"link_loss",
"location_and_navigation",
"next_dst_change",
"phone_alert_status",
"pulse_oximeter",
"reference_time_update",
"running_speed_and_cadence",
"scan_parameters",
"tx_power",
"user_data",
"weight_scale"
]
})
.then(device => {
console.log('Connecting to GATT Server...');
return device.gatt.connect();
})
.then(server => {
// Note that we could also get all services that match a specific UUID by
// passing it to getPrimaryServices().
console.log('Getting Services...');
return server.getPrimaryServices();
})
.then(services => {
return overrideServices(services);
})
.catch(error => {
console.log('Argh! ' + error);
});
});
function overrideServices(services) {
console.log('Getting Characteristics...');
let queue = Promise.resolve();
services.forEach(service => {
queue = queue.then(_ => service.getCharacteristics().then(characteristics => {
console.log('> Service: ' + service.uuid);
let properties;
characteristics.forEach(characteristic => {
console.log(service);
console.log(characteristic);
properties = getSupportedProperties(characteristic)
console.log('>> Characteristic: ' + characteristic.uuid + ' ' + properties);
newservices.push({
"serive": service,
"characteristic": characteristic,
"properties": properties
})
var eletr = document.createElement('tr');
eletr.setAttribute("id", characteristic.uuid);
eletr.innerHTML = `<tr>
<th scope="row">` + service.uuid + `</th>
<td>` + characteristic.uuid +
`</td>
<td>` + properties +
`</td>
<td><input type="text" name="" id="" value="" /></td>
<td>
<button type="button" >read</button>
<button type="button" >write</button></td>
</tr>`;
$('tbody')[0].appendChild(eletr);
if (properties.indexOf("NOTIFY") != -1) {
characteristic.startNotifications()
characteristic.addEventListener('characteristicvaluechanged', function(event) {
const value = event.target.value;
console.log('Received ' + value);
console.log(value.buffer, value.byteLength);
console.log(String.fromCharCode.apply(null, new Uint8Array(value.buffer)));
$('#' + characteristic.uuid + ' input').val(String.fromCharCode.apply(null, new Uint8Array(value.buffer)));
});
}
if (properties.indexOf("READ") != -1) {
$('#' + characteristic.uuid + ' button')[0].addEventListener("click", function() {
const value = characteristic.readValue();
$('#' + characteristic.uuid + ' input').val(String.fromCharCode.apply(null, new Uint8Array(value.buffer)));
});
}
if (properties.indexOf("WRITE") != -1) {
$('#' + characteristic.uuid + ' button')[1].addEventListener("click", function() {
// Writing 1 is the signal to reset energy expended.
const inputValue = $('#' + characteristic.uuid + ' input').val();
const value = stringToUint8Array(inputValue);
characteristic.writeValue(value);
});
}
});
}));
});
return queue;
}
function stringToUint8Array(str) {
var arr = [];
for (var i = 0, j = str.length; i < j; ++i) {
arr.push(str.charCodeAt(i));
}
var tmpUint8Array = new Uint8Array(arr);
return tmpUint8Array
}
/* Utils */
function getSupportedProperties(characteristic) {
let supportedProperties = [];
for (const p in characteristic.properties) {
if (characteristic.properties[p] === true) {
supportedProperties.push(p.toUpperCase());
}
}
return '[' + supportedProperties.join(', ') + ']';
}
sw.js
const cacheName = 'cache-v1';
const precacheResources = [
'/webBle/',
'/webBle/index.html',
'/webBle/js/index.js',
'/webBle/js/jquery.min.js',
'/webBle/js/bootstrap.min.js',
'/webBle/css/bootstrap.min.css',
'/webBle/image/android-launchericon-48-48.png',
'/webBle/image/android-launchericon-96-96.png',
'/webBle/image/android-launchericon-72-72.png',
'/webBle/image/android-launchericon-144-144.png',
'/webBle/image/android-launchericon-192-192.png',
'/webBle/image/android-launchericon-512-512.png'
];
self.addEventListener('install', event => {
console.log('Service worker install event!');
event.waitUntil(
caches.open(cacheName)
.then(cache => {
return cache.addAll(precacheResources);
})
);
});
self.addEventListener('activate', event => {
console.log('Service worker activate event!');
});
self.addEventListener('fetch', event => {
console.log('Fetch intercepted for:', event.request.url);
event.respondWith(caches.match(event.request)
.then(cachedResponse => {
if (cachedResponse) {
return cachedResponse;
}
return fetch(event.request);
})
);
});
上一篇:Js实现web应用浏览器通知
下一篇:chrome UDP