add support for importing logs

This commit is contained in:
peli 2020-06-24 22:33:31 -07:00
Родитель f878008d47
Коммит 64d7393094
5 изменённых файлов: 153 добавлений и 60 удалений

Просмотреть файл

@ -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'

99
src/logparser.ts Normal file
Просмотреть файл

@ -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
}