initial import

This commit is contained in:
Gilles Boccon-Gibod
2022-05-16 19:42:31 -07:00
commit 6ac91f7dec
185 changed files with 32064 additions and 0 deletions

131
web/index.html Normal file
View 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
View 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')