From 912f4eedea97a2130cf76ce6002d5be967dabcca Mon Sep 17 00:00:00 2001 From: xianii Date: Thu, 1 Aug 2024 16:47:41 +0800 Subject: [PATCH 1/3] replace autoconnect with verify connect --- src/routes/webhid.svelte | 75 +++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/src/routes/webhid.svelte b/src/routes/webhid.svelte index 4cf050b..ff1b7b0 100644 --- a/src/routes/webhid.svelte +++ b/src/routes/webhid.svelte @@ -4,17 +4,11 @@ import { onMount } from 'svelte'; const dispatch = createEventDispatcher(); + let hidDeviceFWVer = ''; + let hidDeviceReady = false; export let hidDevice = null; let wantConnect = false; onMount(() => { - navigator.hid.addEventListener('connect', ({ device }) => { - console.log(`HID connected: ${device.productName}`); - if (!hidDevice && device.vendorId == 0xcafe) { - wantConnect = true; - handleConnection(); - } - }); - navigator.hid.addEventListener('disconnect', ({ device }) => { console.log(`HID disconnected: ${device.productName}`); if (device.vendorId == 0xcafe) { @@ -37,10 +31,19 @@ } async function handleConnectClick() { let ret = await openFirstDeviceById(0xcafe); + hidDeviceReady = false; + hidDeviceFWVer = ''; if (ret < 0) { hidDevice = null; } else { hidDevice = ret; + let rand = Math.floor(Math.random() * 256); + hidDevice.sendReport(0, new Uint8Array([0x5e, rand, 0x5e ^ rand, 4, 0x0e, 0xad, 0xbe, 0xef])); + setTimeout(async () => { + if (!hidDeviceReady) { + await handleDisconnectClick(); + } + }, 300); } } async function handleDisconnectClick() { @@ -88,30 +91,14 @@ return hidDevice; } - function dataPaser(data) { - if (data.length != 64) { - return; - } - if (data[0] != 0x5e) { - return; - } - if (data[2] != (data[0] ^ data[1])) { - return; - } - if (data[4] != (data[2] ^ data[3])) { - return; - } - // function buf2hex(buffer) { - // return [...new Uint8Array(buffer)].map((x) => x.toString(16).padStart(2, '0')).join(' '); - // } - // console.log("hid", buf2hex(data.buffer)); + function dataFrameParser(data) { + let idx = 6; let validDataType = (dt) => { if (dataTypes.has(dt)) { return dataTypes.get(dt); } return null; }; - let idx = 5; let getDataFrame = () => { let dataType = validDataType(data[idx]); if (!dataType) { @@ -144,6 +131,40 @@ dispatch('message', output); } } + function versionFrameParser(data) { + let idx = 6 + 32; + let version = ''; + while (data[idx] != 0x00) { + version += String.fromCharCode(data[idx++]); + } + console.log('version', version); + hidDeviceReady = true; + hidDeviceFWVer = version; + } + function dataParser(data) { + if (data.length != 64) { + return; + } + if (data[0] != 0x5e) { + return; + } + if (data[2] != (data[0] ^ data[1])) { + return; + } + if (data[4] != (data[2] ^ data[3])) { + return; + } + if (data[5] == 0x00) { + // data frame + if (hidDeviceReady) { + dataFrameParser(data); + } + } + if (data[5] == 0xfe) { + // version frame + versionFrameParser(data); + } + } function reportPaser(event) { const { data, device, reportId } = event; @@ -151,7 +172,7 @@ device.close(); return; } - dataPaser(new Uint8Array(data.buffer)); + dataParser(new Uint8Array(data.buffer)); } From 11e92d62987a677deb31fce06b2f70a56ef7155e Mon Sep 17 00:00:00 2001 From: xianii Date: Thu, 1 Aug 2024 16:48:08 +0800 Subject: [PATCH 2/3] fmt --- postcss.config.js | 10 +-- src/routes/+page.svelte | 2 +- src/routes/chartData.svelte | 2 +- src/routes/dataHandler.js | 150 ++++++++++++++++----------------- src/routes/realtimeData.svelte | 4 +- svelte.config.js | 8 +- tailwind.config.js | 34 ++++---- vite.config.js | 11 ++- 8 files changed, 109 insertions(+), 112 deletions(-) diff --git a/postcss.config.js b/postcss.config.js index 2e7af2b..0f77216 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,6 +1,6 @@ export default { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -} + plugins: { + tailwindcss: {}, + autoprefixer: {} + } +}; diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index e343c05..635030c 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -22,7 +22,7 @@
- +
diff --git a/src/routes/chartData.svelte b/src/routes/chartData.svelte index 7c2a6a3..0894faa 100644 --- a/src/routes/chartData.svelte +++ b/src/routes/chartData.svelte @@ -118,7 +118,7 @@ display: true, position: 'right', suggestedMin: -2.0, - suggestedMax: 6 + suggestedMax: 6 }, mv: { type: 'linear', diff --git a/src/routes/dataHandler.js b/src/routes/dataHandler.js index fdef20c..7d12734 100644 --- a/src/routes/dataHandler.js +++ b/src/routes/dataHandler.js @@ -1,132 +1,132 @@ let temperatureDataSet = { - name: "温度", + name: '温度', head: 0x00, - postfix: "℃", + postfix: '℃', v: 0, postProc: (v) => { - let temp + let temp; if (v >= 0x8000) { - temp = 0x10000 - v + temp = 0x10000 - v; } else { - temp = v + temp = v; } - return temp / 10 + return temp / 10; }, print: (self) => { - return self.v.toFixed(1) + self.postfix - }, -} + return self.v.toFixed(1) + self.postfix; + } +}; let freqDataSet = { - name: "输出频率", + name: '输出频率', head: 0x10, - postfix: "Hz", + postfix: 'Hz', v: 0, postProc: (v) => { - return v / 10 + return v / 10; }, print: (self) => { - return self.v.toFixed(1) + self.postfix - }, -} + return self.v.toFixed(1) + self.postfix; + } +}; let voltPostProc = (adc) => { - let mv = 1.277 * adc - 96 + let mv = 1.277 * adc - 96; if (mv < 50) { - mv = 0 + mv = 0; } - return mv / 1000 -} + return mv / 1000; +}; let currentPostProc = (adc) => { - let mA = 4.07 * adc - 12610 + let mA = 4.07 * adc - 12610; if (mA < 140 && mA > -80) { - mA = 0 + mA = 0; } - return mA / 1000 -} + return mA / 1000; +}; let voltOutDataSet = { - name: "输出电压", + name: '输出电压', head: 0x11, - postfix: "V", + postfix: 'V', v: 0, postProc: voltPostProc, print: (self) => { - return self.v.toFixed(2) + self.postfix - }, -} + return self.v.toFixed(2) + self.postfix; + } +}; let currentInDataSet = { - name: "输入电流", + name: '输入电流', head: 0x12, - postfix: "A", + postfix: 'A', v: 0, postProc: currentPostProc, print: (self) => { - return self.v.toFixed(2) + self.postfix - }, -} + return self.v.toFixed(2) + self.postfix; + } +}; let voltInDataSet = { - name: "输入电压", + name: '输入电压', head: 0x13, - postfix: "V", + postfix: 'V', v: 0, postProc: voltPostProc, print: (self) => { - return self.v.toFixed(2) + self.postfix - }, -} + return self.v.toFixed(2) + self.postfix; + } +}; let currentOutDataSet = { - name: "输出电流", + name: '输出电流', head: 0x14, - postfix: "A", + postfix: 'A', v: 0, postProc: currentPostProc, print: (self) => { - return self.v.toFixed(2) + self.postfix - }, -} + return self.v.toFixed(2) + self.postfix; + } +}; let ratioDataSet = { - name: "输出占空比", + name: '输出占空比', head: 0x18, - postfix: "%", + postfix: '%', v: 0, postProc: (v) => { - return v / 10 + return v / 10; }, print: (self) => { - return self.v.toFixed(1) + self.postfix - }, -} + return self.v.toFixed(1) + self.postfix; + } +}; let powerDataSet = { - name: "峰值功率", + name: '峰值功率', head: 0xf0, - postfix: "W", + postfix: 'W', v: 0, print: (self) => { - return self.v.toFixed(1) + self.postfix - }, -} + return self.v.toFixed(1) + self.postfix; + } +}; let delayDataSet = { - name: "点火延迟", + name: '点火延迟', head: 0x72, - postfix: "ms", + postfix: 'ms', v: 0, print: (self) => { - return (self.v / 1000).toFixed(1) + self.postfix - }, -} + return (self.v / 1000).toFixed(1) + self.postfix; + } +}; let worktimeDataSet = { - name: "燃烧时间", + name: '燃烧时间', head: 0x74, - postfix: "ms", + postfix: 'ms', v: 0, print: (self) => { - return (self.v / 1000).toFixed(0) + self.postfix - }, -} + return (self.v / 1000).toFixed(0) + self.postfix; + } +}; let timestampDataSet = { - name: "时间戳", + name: '时间戳', head: 0x7f, - postfix: "us", - v: 0, -} + postfix: 'us', + v: 0 +}; export let dataTypesArray = new Array( temperatureDataSet, @@ -140,7 +140,7 @@ export let dataTypesArray = new Array( delayDataSet, worktimeDataSet, timestampDataSet -) +); export const dataTypes = new Map([ [0x00, temperatureDataSet], [0x10, freqDataSet], @@ -152,16 +152,16 @@ export const dataTypes = new Map([ [0xf0, powerDataSet], [0x72, delayDataSet], [0x74, worktimeDataSet], - [0x7f, timestampDataSet], -]) + [0x7f, timestampDataSet] +]); export function dataUpdate(datas) { datas.forEach((element) => { if (dataTypes.has(element.head)) { - dataTypes.get(element.head).v = element.v + dataTypes.get(element.head).v = element.v; } - }) - powerDataSet.v = voltOutDataSet.v * currentInDataSet.v + }); + powerDataSet.v = voltOutDataSet.v * currentInDataSet.v; if (freqDataSet.v > 0.0 && freqDataSet.v < 100.0) { - powerDataSet.v = (powerDataSet.v * freqDataSet.v) / 100 + powerDataSet.v = (powerDataSet.v * freqDataSet.v) / 100; } } diff --git a/src/routes/realtimeData.svelte b/src/routes/realtimeData.svelte index de0dc5f..91315f4 100644 --- a/src/routes/realtimeData.svelte +++ b/src/routes/realtimeData.svelte @@ -1,9 +1,7 @@
diff --git a/svelte.config.js b/svelte.config.js index d9241c1..b6bfc30 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -9,12 +9,12 @@ const config = { adapter: adapter({ // default options are shown. On some platforms // these options are set automatically — see below - pages: "build", - assets: "build", + pages: 'build', + assets: 'build', fallback: 'index.html', precompress: false, - strict: true, - }), + strict: true + }) }, preprocess: vitePreprocess() }; diff --git a/tailwind.config.js b/tailwind.config.js index 0c34ad3..e0ef76f 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,26 +1,26 @@ /** @type {import('tailwindcss').Config} */ export default { - content: ["./src/**/*.{html,js,svelte,ts}"], - plugins: [require("daisyui")], + content: ['./src/**/*.{html,js,svelte,ts}'], + plugins: [require('daisyui')], daisyui: { themes: [ { mytheme: { - primary: "#fb7185", - secondary: "#c084fc", - accent: "#fde047", - neutral: "#44403c", - "base-100": "#1c1917", - info: "#0ea5e9", - success: "#22c55e", - warning: "#f97316", - error: "#b91c1c", - }, + primary: '#fb7185', + secondary: '#c084fc', + accent: '#fde047', + neutral: '#44403c', + 'base-100': '#1c1917', + info: '#0ea5e9', + success: '#22c55e', + warning: '#f97316', + error: '#b91c1c' + } }, - "cupcake", - ], + 'cupcake' + ] }, theme: { - extend: {}, - }, -} + extend: {} + } +}; diff --git a/vite.config.js b/vite.config.js index 4962eb3..1870d34 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,10 +1,9 @@ -import { sveltekit } from "@sveltejs/kit/vite" -import { defineConfig } from "vite" +import { sveltekit } from '@sveltejs/kit/vite'; +import { defineConfig } from 'vite'; export default defineConfig({ plugins: [sveltekit()], ssr: { - noExternal: - ['chart.js/**'] - }, -}) + noExternal: ['chart.js/**'] + } +}); From 903f882034f1f95396dc4ddfe4b69522fb88f858 Mon Sep 17 00:00:00 2001 From: xianii Date: Thu, 1 Aug 2024 16:53:39 +0800 Subject: [PATCH 3/3] update Favicon resource --- src/lib/favicon.png | Bin 0 -> 13212 bytes src/routes/nav.svelte | 3 ++- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 src/lib/favicon.png diff --git a/src/lib/favicon.png b/src/lib/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..6ab1311906059b70b511a9335248ee2e09a07e88 GIT binary patch literal 13212 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 JUiC%v{{Ul$P4WN$ literal 0 HcmV?d00001 diff --git a/src/routes/nav.svelte b/src/routes/nav.svelte index dd53687..3f3333b 100644 --- a/src/routes/nav.svelte +++ b/src/routes/nav.svelte @@ -3,6 +3,7 @@ const dispatch = createEventDispatcher(); import { IconSun } from '@tabler/icons-svelte'; import { IconMoon } from '@tabler/icons-svelte'; + import Favicon from '$lib/favicon.png'; import Webhid from './webhid.svelte'; import RealtimeData from './realtimeData.svelte'; @@ -16,7 +17,7 @@