mirror of
https://github.com/google/bumble.git
synced 2026-04-16 00:25:31 +00:00
initial import
This commit is contained in:
131
web/index.html
Normal file
131
web/index.html
Normal file
@@ -0,0 +1,131 @@
|
||||
<html>
|
||||
<head>
|
||||
<script src="https://cdn.jsdelivr.net/pyodide/v0.19.1/full/pyodide.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<button onclick="runUSB()">USB</button>
|
||||
<button onclick="runSerial()">Serial</button>
|
||||
<br />
|
||||
<br />
|
||||
<div>Output:</div>
|
||||
<textarea id="output" style="width: 100%;" rows="30" disabled></textarea>
|
||||
|
||||
<script>
|
||||
function bufferToHex(buffer) {
|
||||
return [...new Uint8Array(buffer)].map(x => x.toString(16).padStart(2, '0')).join('');
|
||||
}
|
||||
|
||||
const output = document.getElementById("output");
|
||||
const code = document.getElementById("code");
|
||||
|
||||
function addToOutput(s) {
|
||||
output.value += s + "\n";
|
||||
}
|
||||
|
||||
output.value = "Initializing...\n";
|
||||
|
||||
async function main() {
|
||||
let pyodide = await loadPyodide({
|
||||
indexURL: "https://cdn.jsdelivr.net/pyodide/v0.19.1/full/",
|
||||
})
|
||||
output.value += "Ready!\n"
|
||||
|
||||
return pyodide;
|
||||
}
|
||||
|
||||
let pyodideReadyPromise = main();
|
||||
|
||||
async function readLoop(port, packet_source) {
|
||||
const reader = port.readable.getReader()
|
||||
try {
|
||||
while (true) {
|
||||
console.log('@@@ Reading...')
|
||||
const { done, value } = await reader.read()
|
||||
if (done) {
|
||||
console.log("--- DONE!")
|
||||
break
|
||||
}
|
||||
|
||||
console.log('@@@ Serial data:', bufferToHex(value))
|
||||
if (packet_source.delegate !== undefined) {
|
||||
packet_source.delegate.data_received(value)
|
||||
} else {
|
||||
console.warn('@@@ delegate not set yet, dropping data')
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
reader.releaseLock()
|
||||
}
|
||||
}
|
||||
|
||||
async function runUSB() {
|
||||
const device = await navigator.usb.requestDevice({
|
||||
filters: [
|
||||
{
|
||||
classCode: 0xE0,
|
||||
subclassCode: 0x01
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
if (device.configuration === null) {
|
||||
await device.selectConfiguration(1);
|
||||
}
|
||||
await device.claimInterface(0)
|
||||
}
|
||||
|
||||
async function runSerial() {
|
||||
const ports = await navigator.serial.getPorts()
|
||||
console.log('Paired ports:', ports)
|
||||
|
||||
const port = await navigator.serial.requestPort()
|
||||
await port.open({ baudRate: 1000000 })
|
||||
const writer = port.writable.getWriter()
|
||||
}
|
||||
|
||||
async function run() {
|
||||
|
||||
let pyodide = await pyodideReadyPromise;
|
||||
try {
|
||||
const script = await(await fetch('scanner.py')).text()
|
||||
await pyodide.loadPackage('micropip')
|
||||
await pyodide.runPythonAsync(`
|
||||
import micropip
|
||||
await micropip.install('../dist/bumble-0.0.36.dev0+g3adbfe7.d20210807-py3-none-any.whl')
|
||||
`)
|
||||
let output = await pyodide.runPythonAsync(script)
|
||||
addToOutput(output)
|
||||
|
||||
const pythonMain = pyodide.globals.get('main')
|
||||
const packet_source = {}
|
||||
const packet_sink = {
|
||||
on_packet: (packet) => {
|
||||
// Variant A, with the conversion done in Javascript
|
||||
const buffer = packet.toJs()
|
||||
console.log(`$$$ on_packet: ${bufferToHex(buffer)}`)
|
||||
// TODO: create an sync queue here instead of blindly calling write without awaiting
|
||||
/*await*/ writer.write(buffer)
|
||||
packet.destroy()
|
||||
|
||||
// Variant B, with the conversion `to_js` done at the Python layer
|
||||
// console.log(`$$$ on_packet: ${bufferToHex(packet)}`)
|
||||
// /*await*/ writer.write(packet)
|
||||
}
|
||||
}
|
||||
serialLooper = readLoop(port, packet_source)
|
||||
pythonResult = await pythonMain(packet_source, packet_sink)
|
||||
console.log(pythonResult)
|
||||
serialResult = await serialLooper
|
||||
writer.releaseLock()
|
||||
await port.close()
|
||||
console.log('### done')
|
||||
} catch (err) {
|
||||
addToOutput(err);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
63
web/scanner.py
Normal file
63
web/scanner.py
Normal file
@@ -0,0 +1,63 @@
|
||||
# Copyright 2021-2022 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Imports
|
||||
# -----------------------------------------------------------------------------
|
||||
from bumble.device import Device
|
||||
from bumble.transport import PacketParser
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
class ScannerListener(Device.Listener):
|
||||
def on_advertisement(self, address, ad_data, rssi, connectable):
|
||||
address_type_string = ('P', 'R', 'PI', 'RI')[address.address_type]
|
||||
print(f'>>> {address} [{address_type_string}]: RSSI={rssi}, {ad_data}')
|
||||
|
||||
|
||||
class HciSource:
|
||||
def __init__(self, host_source):
|
||||
self.parser = PacketParser()
|
||||
host_source.delegate = self
|
||||
|
||||
def set_packet_sink(self, sink):
|
||||
self.parser.set_packet_sink(sink)
|
||||
|
||||
# host source delegation
|
||||
def data_received(self, data):
|
||||
print('*** DATA from JS:', data)
|
||||
buffer = bytes(data.to_py())
|
||||
self.parser.feed_data(buffer)
|
||||
|
||||
|
||||
# class HciSink:
|
||||
# def __init__(self, host_sink):
|
||||
# self.host_sink = host_sink
|
||||
|
||||
# def on_packet(self, packet):
|
||||
# print(f'>>> PACKET from Python: {packet}')
|
||||
# self.host_sink.on_packet(packet)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
async def main(host_source, host_sink):
|
||||
print('### Starting Scanner')
|
||||
hci_source = HciSource(host_source)
|
||||
hci_sink = host_sink
|
||||
device = Device.with_hci('Bumble', 'F0:F1:F2:F3:F4:F5', hci_source, hci_sink)
|
||||
device.listener = ScannerListener()
|
||||
await device.power_on()
|
||||
await device.start_scanning()
|
||||
|
||||
print('### Scanner started')
|
||||
Reference in New Issue
Block a user