зеркало из https://github.com/microsoft/jacdac-ts.git
add support for importing logs
This commit is contained in:
Родитель
f878008d47
Коммит
64d7393094
|
@ -6,6 +6,10 @@
|
|||
font-family: monospace;
|
||||
}
|
||||
|
||||
.hint {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
#log {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
@ -21,28 +25,68 @@
|
|||
<div>
|
||||
<button id="connect">connect to jacdac device</button>
|
||||
</div>
|
||||
<div class="hint">
|
||||
Drag and drop an exported data from your Saleae. Add an Async Serial protocol analyser, 1Mbit, export to
|
||||
CSV/hex.
|
||||
</div>
|
||||
<div id="log">
|
||||
<div>waiting for message...</div>
|
||||
</div>
|
||||
|
||||
<script src="/dist/jacdac.umd.js"></script>
|
||||
<script>
|
||||
async function sniff() {
|
||||
// webusb
|
||||
let bus;
|
||||
async function listenWebUsb() {
|
||||
log('starting')
|
||||
let bus;
|
||||
try {
|
||||
if (bus) {
|
||||
await bus.disconnectAsync();
|
||||
bus = undefined;
|
||||
}
|
||||
bus = await jacdac.requestUSBBus();
|
||||
bus.on('packetreceive', pkt => log(jacdac.printPacket(pkt)))
|
||||
log('started')
|
||||
} catch (err) {
|
||||
log(err)
|
||||
await bus.disconnect()
|
||||
if (bus) {
|
||||
await bus.disconnectAsync()
|
||||
bus = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const connect = document.getElementById("connect");
|
||||
connect.onclick = sniff;
|
||||
// replace
|
||||
async function importLog(file) {
|
||||
if (bus) {
|
||||
await bus.disconnectAsync();
|
||||
bus = undefined;
|
||||
}
|
||||
bus = new jacdac.Bus({ sendPacketAsync: p => { } })
|
||||
bus.on('packetreceive', pkt => log(jacdac.printPacket(pkt)))
|
||||
|
||||
const logDiv = document.getElementById("log");
|
||||
logDiv.innerHTML = ''
|
||||
const text = await file.text();
|
||||
jacdac.replayLog(bus, text);
|
||||
}
|
||||
|
||||
// binding ui
|
||||
const connect = document.getElementById("connect");
|
||||
connect.onclick = listenWebUsb;
|
||||
document.body.ondragover = ev => ev.preventDefault();
|
||||
document.body.ondrop = drop;
|
||||
|
||||
async function drop(ev) {
|
||||
ev.preventDefault();
|
||||
const items = ev.dataTransfer.items;
|
||||
if (!items) return;
|
||||
const item = items[0];
|
||||
if (item.kind === 'file') {
|
||||
const file = item.getAsFile();
|
||||
importLog(file);
|
||||
}
|
||||
}
|
||||
function log(msg) {
|
||||
const logDiv = document.getElementById("log");
|
||||
const line = document.createElement("div");
|
||||
|
|
|
@ -6,7 +6,7 @@ import { ConsolePriority, CMD_CONSOLE_SET_MIN_PRIORITY, SRV_LOGGER, JD_SERVICE_N
|
|||
|
||||
export interface BusOptions {
|
||||
sendPacketAsync: (p: Packet) => Promise<void>;
|
||||
disconnectAsync: () => Promise<void>;
|
||||
disconnectAsync?: () => Promise<void>;
|
||||
}
|
||||
|
||||
export interface PacketEventEmitter {
|
||||
|
@ -107,12 +107,13 @@ export class Bus extends EventEmitter implements PacketEventEmitter {
|
|||
return this.options.sendPacketAsync(p)
|
||||
}
|
||||
|
||||
disconnect(): Promise<void> {
|
||||
disconnectAsync(): Promise<void> {
|
||||
if (this._gcInterval) {
|
||||
clearInterval(this._gcInterval);
|
||||
this._gcInterval = undefined;
|
||||
}
|
||||
return this.options.disconnectAsync()
|
||||
|
||||
return (this.options?.disconnectAsync() || Promise.resolve())
|
||||
.then(() => { this.emit("disconnect") })
|
||||
}
|
||||
|
||||
|
|
|
@ -9,4 +9,5 @@ export * from './device'
|
|||
export * from './bus'
|
||||
export * from './hf2'
|
||||
export * from './sensor'
|
||||
export * from './logparser'
|
||||
export * from './pretty'
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
import { fromHex } from "./utils"
|
||||
import { Bus } from "./bus"
|
||||
import { Packet } from "./packet"
|
||||
|
||||
export interface ParsedFrame {
|
||||
timestamp: number
|
||||
data: Uint8Array
|
||||
info?: string
|
||||
}
|
||||
|
||||
export function parseLog(logcontents: string): ParsedFrame[] {
|
||||
const res: ParsedFrame[] = []
|
||||
let frameBytes = []
|
||||
let lastTime = 0
|
||||
for (let ln of logcontents.split(/\r?\n/)) {
|
||||
let m = /^JD (\d+) ([0-9a-f]+)/i.exec(ln)
|
||||
if (m) {
|
||||
res.push({
|
||||
timestamp: parseInt(m[1]),
|
||||
data: fromHex(m[2])
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
/** Windows, logic 1.*
|
||||
Time [s],Value,Parity Error,Framing Error
|
||||
0.042909760000000,0x00,,Error
|
||||
0.042980320000000,0xD4,,
|
||||
0.042990240000000,0x81,,
|
||||
0.043000160000000,0x10,,
|
||||
0.043010240000000,0x00,,
|
||||
0.043020160000000,0xE8,,
|
||||
0.043030240000000,0xDF,,
|
||||
0.043040160000000,0xCB,,
|
||||
0.043050240000000,0xD1,,
|
||||
0.043060160000000,0x97,,
|
||||
0.043070240000000,0x34,,
|
||||
0.043080160000000,0x37,,
|
||||
0.043090240000000,0x48,,
|
||||
0.043100160000000,0x0C,,
|
||||
0.043110080000000,0x00,,
|
||||
0.043120160000000,0x00,,
|
||||
0.043130080000000,0x00,,
|
||||
0.043140160000000,0x00,,
|
||||
0.043150080000000,0x00,,
|
||||
0.043160160000000,0x00,,
|
||||
0.043170080000000,0x00,,
|
||||
0.043180160000000,0xCA,,
|
||||
0.043190080000000,0x1F,,
|
||||
0.043200160000000,0xDC,,
|
||||
0.043210080000000,0x12,,
|
||||
0.043220160000000,0x46,,
|
||||
0.043230080000000,0x47,,
|
||||
0.043240160000000,0x27,,
|
||||
0.043250080000000,0x1F,,
|
||||
0.043264800000000,0x00,,Error
|
||||
0.063968960000000,0x00,,Error
|
||||
*/
|
||||
m = /^([\d\.]+),(?:Async Serial,)?.*(0x[A-F0-9][A-F0-9])/.exec(ln)
|
||||
if (!m)
|
||||
continue
|
||||
const tm = parseFloat(m[1])
|
||||
if (lastTime && tm - lastTime > 0.1) {
|
||||
res.push({
|
||||
timestamp: lastTime * 1000,
|
||||
data: new Uint8Array(frameBytes),
|
||||
info: "timeout"
|
||||
})
|
||||
frameBytes = []
|
||||
lastTime = 0
|
||||
}
|
||||
|
||||
lastTime = tm
|
||||
if (/(framing error|Error)/.test(ln)) {
|
||||
if (frameBytes.length > 0)
|
||||
res.push({
|
||||
timestamp: lastTime * 1000,
|
||||
data: new Uint8Array(frameBytes),
|
||||
})
|
||||
frameBytes = []
|
||||
lastTime = 0
|
||||
} else {
|
||||
frameBytes.push(parseInt(m[2]))
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
export function replayLog(bus: Bus, text: string): void {
|
||||
const frames = parseLog(text);
|
||||
frames.forEach((frame) => {
|
||||
if (frame.info)
|
||||
console.warn("FRM: " + frame.info)
|
||||
for (const p of Packet.fromFrame(frame.data, frame.timestamp)) {
|
||||
bus.processPacket(p)
|
||||
}
|
||||
})
|
||||
}
|
|
@ -222,55 +222,3 @@ export function printPacket(pkt: Packet, opts: Options = {}): string {
|
|||
|
||||
return (!isNaN(pkt.timestamp) ? Math.round(pkt.timestamp) + "ms: " : "") + pdesc
|
||||
}
|
||||
|
||||
export interface ParsedFrame {
|
||||
timestamp: number
|
||||
data: Uint8Array
|
||||
info?: string
|
||||
}
|
||||
|
||||
export function parseLog(logcontents: string) {
|
||||
const res: ParsedFrame[] = []
|
||||
let frameBytes = []
|
||||
let lastTime = 0
|
||||
for (let ln of logcontents.split(/\r?\n/)) {
|
||||
let m = /^JD (\d+) ([0-9a-f]+)/i.exec(ln)
|
||||
if (m) {
|
||||
res.push({
|
||||
timestamp: parseInt(m[1]),
|
||||
data: U.fromHex(m[2])
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
m = /^([\d\.]+),Async Serial,.*(0x[A-F0-9][A-F0-9])/.exec(ln)
|
||||
if (!m)
|
||||
continue
|
||||
const tm = parseFloat(m[1])
|
||||
if (lastTime && tm - lastTime > 0.1) {
|
||||
res.push({
|
||||
timestamp: lastTime * 1000,
|
||||
data: new Uint8Array(frameBytes),
|
||||
info: "timeout"
|
||||
})
|
||||
frameBytes = []
|
||||
lastTime = 0
|
||||
}
|
||||
|
||||
lastTime = tm
|
||||
if (ln.indexOf("framing error") > 0) {
|
||||
if (frameBytes.length > 0)
|
||||
res.push({
|
||||
timestamp: lastTime * 1000,
|
||||
data: new Uint8Array(frameBytes),
|
||||
})
|
||||
frameBytes = []
|
||||
lastTime = 0
|
||||
} else {
|
||||
frameBytes.push(parseInt(m[2]))
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче