Fix outdated code
This commit is contained in:
parent
87ddfbcdb6
commit
2a0edcdb5e
src
198
src/lib/utils.ts
198
src/lib/utils.ts
@ -1,3 +1,4 @@
|
||||
import { NiimbotPacket, PacketParser, RequestCommandId, ResponseCommandId, Utils } from "@mmote/niimbluelib";
|
||||
import child_process from "child_process";
|
||||
|
||||
interface TsharkJson {
|
||||
@ -21,6 +22,27 @@ export interface TsharkJsonNormalized {
|
||||
data: string;
|
||||
}
|
||||
|
||||
export const plainTextProcess = (data: Buffer): TsharkJsonNormalized[] => {
|
||||
const lines = data.toString().split(/(?:\r\n|\r|\n)/g);
|
||||
const result: TsharkJsonNormalized[] = [];
|
||||
|
||||
for (const line of lines) {
|
||||
const lineTrimmed = line.trim();
|
||||
const direction = lineTrimmed.substring(0, 2);
|
||||
const data = lineTrimmed.substring(2);
|
||||
|
||||
if (direction == "<<" || direction == ">>") {
|
||||
result.push({
|
||||
time: 0,
|
||||
proto: "usb",
|
||||
direction,
|
||||
data,
|
||||
});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
export const runTshark = async (path: string): Promise<TsharkJsonNormalized[]> => {
|
||||
const tshark = process.env.TSHARK_PATH || "tshark";
|
||||
|
||||
@ -103,3 +125,179 @@ export const runTshark = async (path: string): Promise<TsharkJsonNormalized[]> =
|
||||
resolve(normalized);
|
||||
});
|
||||
};
|
||||
|
||||
export interface ParseResult extends TsharkJsonNormalized {
|
||||
packets: { typeStr: string; packet: NiimbotPacket; info?: string }[];
|
||||
error: string;
|
||||
}
|
||||
|
||||
export const extractPacketInfo = (p: NiimbotPacket): string => {
|
||||
if (p.command === RequestCommandId.SetPageSize && p.dataLength >= 4) {
|
||||
const rows = Utils.bytesToI16(p.data.slice(0, 2));
|
||||
const cols = Utils.bytesToI16(p.data.slice(2, 4));
|
||||
return `${cols}x${rows}px, ${cols / 8}x${rows / 8}mm 203dpi`;
|
||||
}
|
||||
|
||||
if (p.command === RequestCommandId.PrintBitmapRow) {
|
||||
const row = Utils.bytesToI16(p.data.slice(0, 2));
|
||||
const w = (p.data.length - 6) * 8;
|
||||
return `row=${row} width=${w} x${p.data[5]}`;
|
||||
}
|
||||
|
||||
if (p.command === RequestCommandId.PrintBitmapRowIndexed) {
|
||||
const row = Utils.bytesToI16(p.data.slice(0, 2));
|
||||
return `row=${row} x${p.data[5]}`;
|
||||
}
|
||||
|
||||
if (p.command === RequestCommandId.PrintEmptyRow) {
|
||||
const row = Utils.bytesToI16(p.data.slice(0, 2));
|
||||
return `row=${row} x${p.data[2]}`;
|
||||
}
|
||||
|
||||
if ([RequestCommandId.PrintQuantity, ResponseCommandId.In_PrinterInfoPrinterCode].includes(p.command as number)) {
|
||||
return `${Utils.bytesToI16(p.data.slice(0, 2))}`;
|
||||
}
|
||||
|
||||
if ([RequestCommandId.SetDensity, RequestCommandId.SetLabelType].includes(p.command as number)) {
|
||||
return `${p.data[0]}`;
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
export const parseDump = (dump: TsharkJsonNormalized[]): ParseResult[] => {
|
||||
let rxBuf: Uint8Array = new Uint8Array();
|
||||
let txBuf: Uint8Array = new Uint8Array();
|
||||
const results: ParseResult[] = [];
|
||||
|
||||
for (const d of dump) {
|
||||
let data: Uint8Array = Utils.hexToBuf(d.data);
|
||||
|
||||
if (d.direction === "<<") {
|
||||
rxBuf = Utils.u8ArrayAppend(rxBuf, data);
|
||||
|
||||
if (rxBuf.length > 1 && !Utils.hasSubarrayAtPos(rxBuf, NiimbotPacket.HEAD, 0)) {
|
||||
rxBuf = new Uint8Array();
|
||||
results.push({ ...d, error: "Dropping invalid buffer", packets: [] });
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (Utils.hasSubarrayAtPos(data, [0x03, ...NiimbotPacket.HEAD], 0)) data = data.slice(1); // drop 03 prefix
|
||||
|
||||
txBuf = Utils.u8ArrayAppend(txBuf, data);
|
||||
|
||||
if (txBuf.length > 1 && !Utils.hasSubarrayAtPos(txBuf, NiimbotPacket.HEAD, 0)) {
|
||||
txBuf = new Uint8Array();
|
||||
results.push({ ...d, error: "Dropping invalid buffer", packets: [] });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const packets: NiimbotPacket[] = PacketParser.parsePacketBundle(d.direction === "<<" ? rxBuf : txBuf);
|
||||
|
||||
if (packets.length > 0) {
|
||||
results.push({
|
||||
...d,
|
||||
error: "",
|
||||
packets: packets.map((packet) => ({
|
||||
packet,
|
||||
typeStr: (d.direction === ">>" ? RequestCommandId[packet.command] : ResponseCommandId[packet.command]) ?? "?",
|
||||
info: extractPacketInfo(packet),
|
||||
})),
|
||||
});
|
||||
|
||||
if (d.direction === "<<") {
|
||||
rxBuf = new Uint8Array();
|
||||
} else {
|
||||
txBuf = new Uint8Array();
|
||||
}
|
||||
} else {
|
||||
results.push({ ...d, error: "No packets", packets: [] });
|
||||
}
|
||||
} catch (_e) {
|
||||
results.push({ ...d, error: "Fragment", packets: [] });
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
export const detectImage = (parsed: ParseResult[]): ImageData | null => {
|
||||
let dimensions: { rows: number; cols: number } | undefined;
|
||||
let image: ImageData | undefined;
|
||||
let pageStarted = false;
|
||||
|
||||
for (const d of parsed) {
|
||||
for (const { packet } of d.packets) {
|
||||
if (packet.command === RequestCommandId.SetPageSize && packet.dataLength >= 4 && pageStarted) {
|
||||
dimensions = {
|
||||
rows: Utils.bytesToI16(packet.data.slice(0, 2)),
|
||||
cols: Utils.bytesToI16(packet.data.slice(2, 4)),
|
||||
};
|
||||
const data = new Uint8ClampedArray(dimensions.rows * dimensions.cols * 4).fill(0x55);
|
||||
image = new ImageData(data, dimensions.cols, dimensions.rows, { colorSpace: "srgb" });
|
||||
} else if (packet.command === RequestCommandId.PageStart) {
|
||||
pageStarted = true;
|
||||
} else if (packet.command === RequestCommandId.PageEnd && pageStarted && image !== undefined) {
|
||||
return image;
|
||||
} else if (packet.command === RequestCommandId.PrintEmptyRow && image !== undefined) {
|
||||
const row = Utils.bytesToI16(packet.data.slice(0, 2));
|
||||
const repeats = packet.data[2];
|
||||
|
||||
for (let repeat = 0; repeat < repeats; repeat++) {
|
||||
for (let i = 0; i < image.width; i++) {
|
||||
const idx = image.width * (row + repeat) * 4 + i * 4;
|
||||
image.data[idx] = 0xf6;
|
||||
image.data[idx + 1] = 0xf6;
|
||||
image.data[idx + 2] = 0xf6;
|
||||
image.data[idx + 3] = 0xf6;
|
||||
}
|
||||
}
|
||||
} else if (packet.command === RequestCommandId.PrintBitmapRow && image !== undefined) {
|
||||
const row = Utils.bytesToI16(packet.data.slice(0, 2));
|
||||
const repeats = packet.data[5];
|
||||
const data = packet.data.slice(6);
|
||||
console.log(Utils.bufToHex(data, ""));
|
||||
console.log(row, repeats);
|
||||
|
||||
for (let repeat = 0; repeat < repeats; repeat++) {
|
||||
for (let byteIdx = 0; byteIdx < data.length; byteIdx++) {
|
||||
const b = data[byteIdx];
|
||||
|
||||
for (let bit = 0; bit < 8; bit++) {
|
||||
const idx = image.width * (row + repeat) * 4 + byteIdx * 4 * 8 + bit * 4;
|
||||
if ((b & (1 << (7 - bit))) !== 0) {
|
||||
image.data[idx] = 0x00;
|
||||
image.data[idx + 1] = 0x00;
|
||||
image.data[idx + 2] = 0x00;
|
||||
image.data[idx + 3] = 0xff;
|
||||
} else {
|
||||
image.data[idx] = 0xf3;
|
||||
image.data[idx + 1] = 0xd3;
|
||||
image.data[idx + 2] = 0xff;
|
||||
image.data[idx + 3] = 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (packet.command === RequestCommandId.PrintBitmapRowIndexed && image !== undefined) {
|
||||
const row = Utils.bytesToI16(packet.data.slice(0, 2));
|
||||
const repeats = packet.data[5];
|
||||
console.log(row, repeats);
|
||||
|
||||
for (let repeat = 0; repeat < repeats; repeat++) {
|
||||
for (let i = 0; i < image.width; i++) {
|
||||
const idx = image.width * (row + repeat) * 4 + i * 4;
|
||||
image.data[idx] = 0xbb;
|
||||
image.data[idx + 1] = 0x38;
|
||||
image.data[idx + 2] = 0x3e;
|
||||
image.data[idx + 3] = 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
@ -1,16 +1,18 @@
|
||||
<script lang="ts">
|
||||
import { PUBLIC_BASE_URL } from "$env/static/public";
|
||||
import type { TsharkJsonNormalized } from "$lib/utils";
|
||||
import { detectImage, parseDump, type ParseResult, type TsharkJsonNormalized } from "$lib/utils";
|
||||
import { Utils, PacketParser, RequestCommandId, ResponseCommandId } from "@mmote/niimbluelib";
|
||||
import Dropzone from "svelte-file-dropzone";
|
||||
|
||||
let data: TsharkJsonNormalized[] = [];
|
||||
let parsed: ParseResult[] = [];
|
||||
let error: string = "";
|
||||
let uploading: boolean = false;
|
||||
let rx: boolean = true;
|
||||
let tx: boolean = true;
|
||||
let showInfo: boolean = true;
|
||||
let showTime: boolean = true;
|
||||
let canvas: HTMLCanvasElement;
|
||||
|
||||
let allPacketTypes: { rx: string[]; tx: string[] } = {
|
||||
tx: Object.values(RequestCommandId)
|
||||
@ -22,6 +24,10 @@
|
||||
};
|
||||
let disabledPacketTypes: string[] = [];
|
||||
|
||||
const invert = () => {
|
||||
disabledPacketTypes = [...allPacketTypes.rx, ...allPacketTypes.tx].filter((e) => !disabledPacketTypes.includes(e));
|
||||
};
|
||||
|
||||
const switchPacket = (p: string) => {
|
||||
if (disabledPacketTypes.includes(p)) {
|
||||
disabledPacketTypes = disabledPacketTypes.filter((e) => e !== p);
|
||||
@ -48,6 +54,17 @@
|
||||
|
||||
if (resp.ok) {
|
||||
data = json as TsharkJsonNormalized[];
|
||||
parsed = parseDump(data);
|
||||
|
||||
const image = detectImage(parsed);
|
||||
// console.log(image)
|
||||
|
||||
if (image !== null) {
|
||||
canvas.width = image.width;
|
||||
canvas.height = image.height;
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx?.putImageData(image, 0, 0);
|
||||
}
|
||||
} else if ("error" in json) {
|
||||
error = json.error;
|
||||
}
|
||||
@ -58,39 +75,20 @@
|
||||
|
||||
const formatHex = (hex: string) => {
|
||||
return hex
|
||||
.toUpperCase()
|
||||
.replace(/^(03)?(5555)([A-F0-9]{2})([A-F0-9]{2})(.*?)([A-F0-9]{2})(AAAA)$/, "$1 $2 $3 $4 $5 $6 $7");
|
||||
.toLowerCase()
|
||||
.replace(/^(03)?(5555)([a-f0-9]{2})([a-f0-9]{2})(.*?)([a-f0-9]{2})(aaaa)$/, "$1 $2 $3 $4 $5 $6 $7");
|
||||
};
|
||||
|
||||
const formatInfo = (direction: string, hex: string): { typeStr: string; msg: string } => {
|
||||
try {
|
||||
const infos = [];
|
||||
|
||||
if (hex.startsWith("035555")) hex = hex.slice(2);
|
||||
|
||||
const buf = Utils.hexToBuf(hex);
|
||||
const packets = PacketParser.parsePacketBundle(buf);
|
||||
// if(comment += ResponseCommandId[packet.command])
|
||||
infos.push(
|
||||
...packets.map((p) => {
|
||||
let msg = "";
|
||||
if (direction === ">>") {
|
||||
msg = RequestCommandId[p.command];
|
||||
if (p.command === RequestCommandId.SetPageSize && p.dataLength >= 4) {
|
||||
const cols = Utils.bytesToI16(p.data.slice(0, 2));
|
||||
const rows = Utils.bytesToI16(p.data.slice(2, 4));
|
||||
msg += ` (${rows}x${cols}px, ${rows / 8}x${cols / 8}mm 203dpi)`;
|
||||
}
|
||||
} else {
|
||||
msg = ResponseCommandId[p.command];
|
||||
}
|
||||
return msg;
|
||||
})
|
||||
);
|
||||
return { typeStr: infos.join(", "), msg: infos.join(", ") || "???" };
|
||||
} catch (e) {
|
||||
return { typeStr: "Invalid", msg: "❌" };
|
||||
const isPacketDisplayed = (r: ParseResult) => {
|
||||
if (r.packets.length > 0) {
|
||||
const first = r.packets[0].typeStr;
|
||||
const allEqual = r.packets.every((val) => val.typeStr === first);
|
||||
if (allEqual && disabledPacketTypes.includes(first)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -104,7 +102,7 @@
|
||||
<div class="error">{error}</div>
|
||||
{/if}
|
||||
|
||||
<div class="filters">
|
||||
<div class="page-row">
|
||||
<input type="checkbox" bind:checked={rx} id="rx" />
|
||||
<label for="rx">rx</label>
|
||||
|
||||
@ -118,7 +116,11 @@
|
||||
<label for="info">show info</label>
|
||||
</div>
|
||||
|
||||
<div class="filters">
|
||||
<div class="page-row">
|
||||
<button class="pill" on:click={() => invert()}>Invert packet filter</button>
|
||||
</div>
|
||||
|
||||
<div class="page-row">
|
||||
{#each allPacketTypes.tx as t}
|
||||
<button class="parsed tx pill {disabledPacketTypes.includes(t) && 'disabled'}" on:click={() => switchPacket(t)}
|
||||
>{t}</button
|
||||
@ -126,7 +128,7 @@
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<div class="filters">
|
||||
<div class="page-row">
|
||||
{#each allPacketTypes.rx as t}
|
||||
<button class="parsed rx pill {disabledPacketTypes.includes(t) && 'disabled'}" on:click={() => switchPacket(t)}
|
||||
>{t}</button
|
||||
@ -134,18 +136,35 @@
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<div class="page-row">
|
||||
<div>Preview</div>
|
||||
<canvas bind:this={canvas} width="20" height="10"></canvas>
|
||||
</div>
|
||||
|
||||
<div class="data">
|
||||
{#each data as d}
|
||||
{@const info = formatInfo(d.direction, d.data)}
|
||||
{#if ((d.direction === "<<" && rx) || (d.direction === ">>" && tx)) && !disabledPacketTypes.includes(info.typeStr)}
|
||||
{#each parsed as d}
|
||||
{#if ((d.direction === "<<" && rx) || (d.direction === ">>" && tx)) && isPacketDisplayed(d)}
|
||||
<div class="row">
|
||||
{#if showTime}
|
||||
<span class="time pill">{d.time.toFixed(3)}</span>
|
||||
{/if}
|
||||
|
||||
<span class="{d.direction == '<<' ? 'rx' : 'tx'} pill">{d.direction}</span>
|
||||
|
||||
<span class="hex pill">{formatHex(d.data)}</span>
|
||||
|
||||
{#if showInfo}
|
||||
<span class="parsed pill {d.direction == '<<' ? 'rx' : 'tx'}">{info.msg}</span>
|
||||
{#if d.error}
|
||||
<span class="parsed pill">{d.error}</span>
|
||||
{:else}
|
||||
{#each d.packets as p}
|
||||
<span class="parsed pill {d.direction == '<<' ? 'rx' : 'tx'}">
|
||||
{p.typeStr}
|
||||
{#if p.info}({p.info}){/if}
|
||||
<button class="hide" title="Hide" on:click={() => switchPacket(p.typeStr)}>x</button>
|
||||
</span>
|
||||
{/each}
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
@ -158,16 +177,21 @@
|
||||
margin: 16px 64px;
|
||||
}
|
||||
|
||||
canvas {
|
||||
border: 1px solid #292929;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.filters {
|
||||
.page-row {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.pill {
|
||||
background: none;
|
||||
padding: 0 0.3em;
|
||||
border-radius: 4px;
|
||||
border: 1px solid gray;
|
||||
@ -209,11 +233,20 @@
|
||||
}
|
||||
|
||||
.pill.parsed.rx.disabled {
|
||||
color: #747474;
|
||||
color: #585858;
|
||||
border-color: #042e04;
|
||||
background-color: rgba(11, 156, 11, 0.1);
|
||||
}
|
||||
|
||||
.pill.parsed .hide {
|
||||
color: #a7a7a7;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.hex {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { json, type RequestHandler } from "@sveltejs/kit";
|
||||
import { writeFile, unlink } from "node:fs/promises";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { runTshark } from "$lib/utils";
|
||||
import { runTshark, plainTextProcess } from "$lib/utils";
|
||||
|
||||
export const POST: RequestHandler = async ({ request }) => {
|
||||
const formData = await request.formData();
|
||||
@ -15,7 +15,14 @@ export const POST: RequestHandler = async ({ request }) => {
|
||||
return json({ error: "No file" }, { status: 400 });
|
||||
}
|
||||
|
||||
await writeFile(path, Buffer.from(await file.arrayBuffer()));
|
||||
const buf = Buffer.from(await file.arrayBuffer());
|
||||
await writeFile(path, buf);
|
||||
|
||||
if(file.name.endsWith(".txt")) {
|
||||
const out = plainTextProcess(buf)
|
||||
return json(out);
|
||||
}
|
||||
|
||||
const out = await runTshark(path);
|
||||
return json(out);
|
||||
} catch (e) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user