111 lines
2.5 KiB
JavaScript
111 lines
2.5 KiB
JavaScript
import CloudLog from "../logging/CloudLog";
|
|
|
|
const PANDA_VENDOR_ID = 0xbbaa;
|
|
//const PANDA_PRODUCT_ID = 0xddcc;
|
|
|
|
const BUFFER_SIZE = 0x10 * 256;
|
|
|
|
export default class Panda {
|
|
constructor() {
|
|
this.device = null;
|
|
}
|
|
|
|
connect() {
|
|
// Must be called via a mouse click handler, per Chrome restrictions.
|
|
return navigator.usb
|
|
.requestDevice({ filters: [{ vendorId: PANDA_VENDOR_ID }] })
|
|
.then(device => {
|
|
this.device = device;
|
|
return device.open();
|
|
})
|
|
.then(() => this.device.selectConfiguration(1))
|
|
.then(() => this.device.claimInterface(0));
|
|
}
|
|
|
|
async health() {
|
|
const controlParams = {
|
|
requestType: "vendor",
|
|
recipient: "device",
|
|
request: 0xd2,
|
|
value: 0,
|
|
index: 0
|
|
};
|
|
try {
|
|
return await this.device.controlTransferIn(controlParams, 13);
|
|
} catch (err) {
|
|
CloudLog.error({ event: "Panda.health failed", error: err });
|
|
}
|
|
}
|
|
|
|
parseCanBuffer(buffer) {
|
|
const messages = [];
|
|
|
|
for (let i = 0; i < buffer.byteLength; i += 0x10) {
|
|
const dat = buffer.slice(i, i + 0x10);
|
|
|
|
const datView = Buffer.from(dat);
|
|
const f1 = datView.readInt32LE(0),
|
|
f2 = datView.readInt32LE(4);
|
|
|
|
const address = f1 >>> 21;
|
|
|
|
const busTime = f2 >>> 16;
|
|
const data = new Buffer(dat.slice(8, 8 + (f2 & 0xf)));
|
|
const source = (f2 >> 4) & 0xf & 0xff;
|
|
|
|
messages.push([
|
|
address,
|
|
busTime,
|
|
data.toString("hex").padEnd(16, "0"),
|
|
source
|
|
]);
|
|
}
|
|
|
|
return messages;
|
|
}
|
|
|
|
async mockCanRecv() {
|
|
const promise = new Promise(resolve =>
|
|
setTimeout(
|
|
() =>
|
|
resolve({
|
|
time: performance.now() / 1000,
|
|
canMessages: [[0, Math.random() * 65000, "".padEnd(16, "0"), 0]]
|
|
}),
|
|
100
|
|
)
|
|
);
|
|
return await promise;
|
|
}
|
|
|
|
async canRecv() {
|
|
let result = null,
|
|
receiptTime = null,
|
|
attempts = 0;
|
|
|
|
while (result === null) {
|
|
try {
|
|
result = await this.device.transferIn(1, BUFFER_SIZE);
|
|
receiptTime = performance.now() / 1000;
|
|
} catch (err) {
|
|
console.warn("can_recv failed, retrying");
|
|
attempts = Math.min(++attempts, 10);
|
|
await wait(attempts * 100);
|
|
}
|
|
}
|
|
|
|
await wait(0);
|
|
|
|
return {
|
|
time: receiptTime,
|
|
canMessages: this.parseCanBuffer(result.data.buffer)
|
|
};
|
|
}
|
|
}
|
|
|
|
async function wait(ms) {
|
|
return new Promise(function(resolve, reject) {
|
|
setTimeout(resolve, ms);
|
|
});
|
|
}
|