import { autoResetRef, createInjectionState, watchDebounced, } from "@vueuse/core"; import { shallowRef, reactive, ref, computed, onMounted, onUnmounted, watchEffect, } from "vue"; import { Mutex } from "async-mutex"; import { OscilloscopeApiClient } from "@/APIClient"; import { AuthManager } from "@/utils/AuthManager"; import { useAlertStore } from "@/components/Alert"; import { useRequiredInjection } from "@/utils/Common"; import type { HubConnection } from "@microsoft/signalr"; import type { IOscilloscopeHub, IOscilloscopeReceiver, } from "@/utils/signalR/TypedSignalR.Client/server.Hubs"; import { getHubProxyFactory, getReceiverRegister, } from "@/utils/signalR/TypedSignalR.Client"; import type { OscilloscopeDataResponse, OscilloscopeFullConfig, } from "@/utils/signalR/server.Hubs"; export type OscilloscopeDataType = { x: number[]; y: number[] | number[][]; xUnit: "s" | "ms" | "us" | "ns"; yUnit: "V" | "mV" | "uV"; adFrequency: number; adVpp: number; adMax: number; adMin: number; }; // 默认配置 const DEFAULT_CONFIG: OscilloscopeFullConfig = { captureEnabled: false, triggerLevel: 128, triggerRisingEdge: true, horizontalShift: 0, decimationRate: 50, captureFrequency: 100, }; // 采样频率常量(后端返回) const [useProvideOscilloscope, useOscilloscopeState] = createInjectionState( () => { // Global Store const alert = useRequiredInjection(useAlertStore); // Data const oscData = shallowRef(); const clearOscilloscopeData = () => { oscData.value = undefined; }; // SignalR Hub const oscilloscopeHub = shallowRef<{ connection: HubConnection; proxy: IOscilloscopeHub; } | null>(null); const oscilloscopeReceiver: IOscilloscopeReceiver = { onDataReceived: async (data) => { analyzeOscilloscopeData(data); }, }; onMounted(() => { initHub(); }); onUnmounted(() => { clearHub(); }); function initHub() { if (oscilloscopeHub.value) return; const connection = AuthManager.createHubConnection("OscilloscopeHub"); const proxy = getHubProxyFactory("IOscilloscopeHub").createHubProxy(connection); getReceiverRegister("IOscilloscopeReceiver").register( connection, oscilloscopeReceiver, ); connection.start(); oscilloscopeHub.value = { connection, proxy }; } function clearHub() { if (!oscilloscopeHub.value) return; oscilloscopeHub.value.connection.stop(); oscilloscopeHub.value = null; } function reinitializeHub() { clearHub(); initHub(); } function getHubProxy() { if (!oscilloscopeHub.value) throw new Error("Hub not initialized"); return oscilloscopeHub.value.proxy; } // 互斥锁 const operationMutex = new Mutex(); // 状态 const isApplying = ref(false); const isCapturing = ref(false); const isAutoApplying = ref(false); // 配置 const config = reactive({ ...DEFAULT_CONFIG }); watchDebounced( config, () => { if (!isAutoApplying.value) return; if ( !isApplying.value || !isCapturing.value || !operationMutex.isLocked() ) { applyConfiguration(); } }, { debounce: 200, maxWait: 1000 }, ); // 应用配置 const applyConfiguration = async () => { if (operationMutex.isLocked()) { alert.warn("有其他操作正在进行中,请稍后再试", 3000); return; } const release = await operationMutex.acquire(); isApplying.value = true; try { const proxy = getHubProxy(); const success = await proxy.initialize(config); if (success) { alert.success("示波器配置已应用", 2000); } else { throw new Error("应用失败"); } } catch (error) { if (error instanceof Error && error.message === "Hub not initialized") reinitializeHub(); alert.error("应用配置失败", 3000); } finally { isApplying.value = false; release(); } }; // 重置配置 const resetConfiguration = () => { Object.assign(config, { ...DEFAULT_CONFIG }); alert.info("配置已重置", 2000); }; // 采样点数(由后端数据决定) const sampleCount = ref(0); // 采样周期(ns),由adFrequency计算 const samplePeriodNs = computed(() => oscData.value?.adFrequency ? 1_000_000_000 / oscData.value.adFrequency : 200, ); const analyzeOscilloscopeData = (resp: OscilloscopeDataResponse) => { // 解析波形数据 const binaryString = atob(resp.waveformData); const bytes = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) { bytes[i] = binaryString.charCodeAt(i); } sampleCount.value = bytes.length; // 构建时间轴 const x = Array.from( { length: bytes.length }, (_, i) => (i * samplePeriodNs.value) / 1000, // us ); const y = Array.from(bytes); oscData.value = { x, y, xUnit: "us", yUnit: "V", adFrequency: resp.aDFrequency, adVpp: resp.aDVpp, adMax: resp.aDMax, adMin: resp.aDMin, }; }; // 获取数据 const getOscilloscopeData = async () => { try { const proxy = getHubProxy(); const resp = await proxy.getData(); analyzeOscilloscopeData(resp); } catch (error) { alert.error("获取示波器数据失败", 3000); } }; // 启动捕获 const startCapture = async () => { if (operationMutex.isLocked()) { alert.warn("有其他操作正在进行中,请稍后再试", 3000); return; } isCapturing.value = true; const release = await operationMutex.acquire(); try { const proxy = getHubProxy(); const started = await proxy.startCapture(); if (!started) throw new Error("无法启动捕获"); alert.info("开始捕获...", 2000); } catch (error) { alert.error("捕获失败", 3000); isCapturing.value = false; } finally { release(); } }; // 停止捕获 const stopCapture = async () => { if (!isCapturing.value) { alert.warn("当前没有正在进行的捕获操作", 2000); return; } isCapturing.value = false; const release = await operationMutex.acquire(); try { const proxy = getHubProxy(); const stopped = await proxy.stopCapture(); if (!stopped) throw new Error("无法停止捕获"); alert.info("捕获已停止", 2000); } catch (error) { alert.error("停止捕获失败", 3000); } finally { release(); } }; const toggleCapture = async () => { if (isCapturing.value) { await stopCapture(); } else { await startCapture(); } }; // 更新触发参数 const updateTrigger = async (level: number, risingEdge: boolean) => { const client = AuthManager.createClient(OscilloscopeApiClient); try { const ok = await client.updateTrigger(level, risingEdge); if (ok) { config.triggerLevel = level; config.triggerRisingEdge = risingEdge; alert.success("触发参数已更新", 2000); } else { throw new Error(); } } catch { alert.error("更新触发参数失败", 2000); } }; // 更新采样参数 const updateSampling = async ( horizontalShift: number, decimationRate: number, ) => { const client = AuthManager.createClient(OscilloscopeApiClient); try { const ok = await client.updateSampling(horizontalShift, decimationRate); if (ok) { config.horizontalShift = horizontalShift; config.decimationRate = decimationRate; alert.success("采样参数已更新", 2000); } else { throw new Error(); } } catch { alert.error("更新采样参数失败", 2000); } }; // 手动刷新RAM const refreshRAM = async () => { const client = AuthManager.createClient(OscilloscopeApiClient); try { const ok = await client.refreshRAM(); if (ok) { // alert.success("RAM已刷新", 2000); } else { throw new Error(); } } catch { alert.error("刷新RAM失败", 2000); } }; // 生成测试数据 const generateTestData = () => { const freq = 5_000_000; const duration = 0.001; // 1ms const points = Math.floor(freq * duration); const x = Array.from( { length: points }, (_, i) => (i * 1_000_000_000) / freq / 1000, ); const y = Array.from({ length: points }, (_, i) => Math.floor(Math.sin(i * 0.01) * 127 + 128), ); oscData.value = { x, y, xUnit: "us", yUnit: "V", adFrequency: freq, adVpp: 2.0, adMax: 255, adMin: 0, }; alert.success("测试数据生成成功", 2000); }; return { oscData, config, isApplying, isCapturing, isAutoApplying, sampleCount, samplePeriodNs, applyConfiguration, resetConfiguration, clearOscilloscopeData, getOscilloscopeData, startCapture, stopCapture, toggleCapture, updateTrigger, updateSampling, refreshRAM, generateTestData, }; }, ); export { useProvideOscilloscope, useOscilloscopeState, DEFAULT_CONFIG };