Fix outdated code

This commit is contained in:
MultiMote 2025-02-16 22:46:47 +03:00
parent 87ddfbcdb6
commit 2a0edcdb5e
3 changed files with 280 additions and 42 deletions
src

@ -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 = [];
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;
}
}
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: "❌" };
}
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) {