feat: 完成逻辑分析仪前端设计
This commit is contained in:
parent
b139542c4c
commit
9f25391540
|
@ -1,174 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="space-y-4">
|
|
||||||
<!-- 通道状态概览 -->
|
|
||||||
<div class="stats stats-horizontal bg-base-100 shadow flex justify-between">
|
|
||||||
<div class="stat">
|
|
||||||
<div class="stat-title">总通道数</div>
|
|
||||||
<div class="stat-value text-primary">8</div>
|
|
||||||
<div class="stat-desc">逻辑分析仪通道</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="stat">
|
|
||||||
<div class="stat-title">启用通道</div>
|
|
||||||
<div class="stat-value text-success">{{ enabledChannelCount }}</div>
|
|
||||||
<div class="stat-desc">当前激活通道</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="stat">
|
|
||||||
<div class="stat-title">采样率</div>
|
|
||||||
<div class="stat-value text-info">100MHz</div>
|
|
||||||
<div class="stat-desc">最大采样频率</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 通道配置列表 -->
|
|
||||||
<div class="space-y-2">
|
|
||||||
<div class="flex items-center justify-between p-2 bg-base-300 rounded-lg">
|
|
||||||
<span class="font-medium">通道</span>
|
|
||||||
<span class="font-medium">启用</span>
|
|
||||||
<span class="font-medium">标签</span>
|
|
||||||
<span class="font-medium">颜色</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-for="(channel, index) in channels"
|
|
||||||
:key="index"
|
|
||||||
class="flex items-center justify-between p-3 bg-base-200 rounded-lg hover:bg-base-300 transition-colors"
|
|
||||||
>
|
|
||||||
<!-- 通道编号 -->
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<span class="font-mono font-medium w-12">CH{{ index }}</span>
|
|
||||||
<div
|
|
||||||
class="w-3 h-3 rounded-full border-2 border-white shadow-sm"
|
|
||||||
:style="{ backgroundColor: channel.color }"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 启用开关 -->
|
|
||||||
<div class="form-control">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
v-model="channel.enabled"
|
|
||||||
class="toggle toggle-sm toggle-primary"
|
|
||||||
@change="updateChannelStatus(index)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 通道标签 -->
|
|
||||||
<div class="form-control w-32">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model="channel.label"
|
|
||||||
:placeholder="`通道 ${index}`"
|
|
||||||
class="input input-sm input-bordered w-full"
|
|
||||||
:disabled="!channel.enabled"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 颜色选择 -->
|
|
||||||
<div class="form-control">
|
|
||||||
<input
|
|
||||||
type="color"
|
|
||||||
v-model="channel.color"
|
|
||||||
class="w-8 h-8 rounded border-2 border-base-300 cursor-pointer"
|
|
||||||
:disabled="!channel.enabled"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 批量操作 -->
|
|
||||||
<div class="flex gap-2 pt-4">
|
|
||||||
<button @click="enableAllChannels" class="btn btn-primary btn-sm">
|
|
||||||
全部启用
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button @click="disableAllChannels" class="btn btn-outline btn-sm">
|
|
||||||
全部禁用
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button @click="resetChannelLabels" class="btn btn-outline btn-sm">
|
|
||||||
重置标签
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, computed, reactive } from "vue";
|
|
||||||
|
|
||||||
// 通道接口定义
|
|
||||||
interface Channel {
|
|
||||||
enabled: boolean;
|
|
||||||
label: string;
|
|
||||||
color: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 预设配置接口
|
|
||||||
interface Preset {
|
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
channels: Partial<Channel>[];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 默认颜色数组
|
|
||||||
const defaultColors = [
|
|
||||||
"#FF5733",
|
|
||||||
"#33FF57",
|
|
||||||
"#3357FF",
|
|
||||||
"#FF33F5",
|
|
||||||
"#F5FF33",
|
|
||||||
"#33FFF5",
|
|
||||||
"#FF8C33",
|
|
||||||
"#8C33FF",
|
|
||||||
];
|
|
||||||
|
|
||||||
// 通道配置
|
|
||||||
const channels = reactive<Channel[]>(
|
|
||||||
Array.from({ length: 8 }, (_, index) => ({
|
|
||||||
enabled: false,
|
|
||||||
label: `CH${index}`,
|
|
||||||
color: defaultColors[index],
|
|
||||||
})),
|
|
||||||
);
|
|
||||||
|
|
||||||
// 计算启用的通道数量
|
|
||||||
const enabledChannelCount = computed(
|
|
||||||
() => channels.filter((channel) => channel.enabled).length,
|
|
||||||
);
|
|
||||||
|
|
||||||
// 更新通道状态
|
|
||||||
const updateChannelStatus = (index: number) => {
|
|
||||||
console.log(`通道 ${index} 状态更新:`, channels[index].enabled);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 启用所有通道
|
|
||||||
const enableAllChannels = () => {
|
|
||||||
channels.forEach((channel) => {
|
|
||||||
channel.enabled = true;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 禁用所有通道
|
|
||||||
const disableAllChannels = () => {
|
|
||||||
channels.forEach((channel) => {
|
|
||||||
channel.enabled = false;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 重置通道标签
|
|
||||||
const resetChannelLabels = () => {
|
|
||||||
channels.forEach((channel, index) => {
|
|
||||||
channel.label = `CH${index}`;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 应用预设配置
|
|
||||||
const applyPreset = (preset: Preset) => {
|
|
||||||
preset.channels.forEach((presetChannel, index) => {
|
|
||||||
if (index < channels.length && presetChannel) {
|
|
||||||
Object.assign(channels[index], presetChannel);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
|
|
@ -0,0 +1,224 @@
|
||||||
|
import { createInjectionState } from "@vueuse/core";
|
||||||
|
import { generateTestLogicData, type LogicDataType } from ".";
|
||||||
|
import { shallowRef, reactive, ref, computed } from "vue";
|
||||||
|
import {
|
||||||
|
CaptureConfig,
|
||||||
|
LogicAnalyzerClient,
|
||||||
|
GlobalCaptureMode,
|
||||||
|
SignalOperator,
|
||||||
|
SignalValue,
|
||||||
|
type SignalTriggerConfig,
|
||||||
|
} from "@/APIClient";
|
||||||
|
import { AuthManager } from "@/utils/AuthManager";
|
||||||
|
import { useAlertStore } from "@/components/Alert";
|
||||||
|
|
||||||
|
// 通道接口定义
|
||||||
|
export interface Channel {
|
||||||
|
enabled: boolean;
|
||||||
|
label: string;
|
||||||
|
color: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全局模式选项
|
||||||
|
const globalModes = [
|
||||||
|
{
|
||||||
|
value: GlobalCaptureMode.AND,
|
||||||
|
label: "AND",
|
||||||
|
description: "所有条件都满足时触发",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: GlobalCaptureMode.OR,
|
||||||
|
label: "OR",
|
||||||
|
description: "任一条件满足时触发",
|
||||||
|
},
|
||||||
|
{ value: GlobalCaptureMode.NAND, label: "NAND", description: "AND的非" },
|
||||||
|
{ value: GlobalCaptureMode.NOR, label: "NOR", description: "OR的非" },
|
||||||
|
];
|
||||||
|
|
||||||
|
// 操作符选项
|
||||||
|
const operators = [
|
||||||
|
{ value: SignalOperator.Equal, label: "=" },
|
||||||
|
{ value: SignalOperator.NotEqual, label: "≠" },
|
||||||
|
{ value: SignalOperator.LessThan, label: "<" },
|
||||||
|
{ value: SignalOperator.LessThanOrEqual, label: "≤" },
|
||||||
|
{ value: SignalOperator.GreaterThan, label: ">" },
|
||||||
|
{ value: SignalOperator.GreaterThanOrEqual, label: "≥" },
|
||||||
|
];
|
||||||
|
|
||||||
|
// 信号值选项
|
||||||
|
const signalValues = [
|
||||||
|
{ value: SignalValue.Logic0, label: "0" },
|
||||||
|
{ value: SignalValue.Logic1, label: "1" },
|
||||||
|
{ value: SignalValue.NotCare, label: "X" },
|
||||||
|
{ value: SignalValue.Rise, label: "↑" },
|
||||||
|
{ value: SignalValue.Fall, label: "↓" },
|
||||||
|
{ value: SignalValue.RiseOrFall, label: "↕" },
|
||||||
|
{ value: SignalValue.NoChange, label: "—" },
|
||||||
|
{ value: SignalValue.SomeNumber, label: "#" },
|
||||||
|
];
|
||||||
|
|
||||||
|
// 默认颜色数组
|
||||||
|
const defaultColors = [
|
||||||
|
"#FF5733",
|
||||||
|
"#33FF57",
|
||||||
|
"#3357FF",
|
||||||
|
"#FF33F5",
|
||||||
|
"#F5FF33",
|
||||||
|
"#33FFF5",
|
||||||
|
"#FF8C33",
|
||||||
|
"#8C33FF",
|
||||||
|
];
|
||||||
|
|
||||||
|
const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
|
||||||
|
() => {
|
||||||
|
const logicData = shallowRef<LogicDataType>();
|
||||||
|
const alert = useAlertStore();
|
||||||
|
|
||||||
|
// 触发设置相关状态
|
||||||
|
const currentGlobalMode = ref<GlobalCaptureMode>(GlobalCaptureMode.AND);
|
||||||
|
const isApplying = ref(false);
|
||||||
|
|
||||||
|
// 通道配置
|
||||||
|
const channels = reactive<Channel[]>(
|
||||||
|
Array.from({ length: 8 }, (_, index) => ({
|
||||||
|
enabled: false,
|
||||||
|
label: `CH${index}`,
|
||||||
|
color: defaultColors[index],
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
|
// 8个信号通道的配置
|
||||||
|
const signalConfigs = reactive(
|
||||||
|
Array.from({ length: 8 }, (_, index) => ({
|
||||||
|
signalIndex: index,
|
||||||
|
operator: SignalOperator.Equal,
|
||||||
|
value: SignalValue.Logic1,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
|
// 计算启用的通道数量
|
||||||
|
const enabledChannelCount = computed(
|
||||||
|
() => channels.filter((channel) => channel.enabled).length,
|
||||||
|
);
|
||||||
|
|
||||||
|
const enableAllChannels = () => {
|
||||||
|
channels.forEach((channel) => {
|
||||||
|
channel.enabled = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const disableAllChannels = () => {
|
||||||
|
channels.forEach((channel) => {
|
||||||
|
channel.enabled = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setGlobalMode = async (mode: GlobalCaptureMode) => {
|
||||||
|
try {
|
||||||
|
const client = AuthManager.createAuthenticatedLogicAnalyzerClient();
|
||||||
|
const success = await client.setGlobalTrigMode(mode);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
currentGlobalMode.value = mode;
|
||||||
|
alert?.success(
|
||||||
|
`全局触发模式已设置为 ${globalModes.find((m) => m.value === mode)?.label}`,
|
||||||
|
3000,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw new Error("设置失败");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("设置全局触发模式失败:", error);
|
||||||
|
alert?.error("设置全局触发模式失败", 3000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const applyConfiguration = async () => {
|
||||||
|
isApplying.value = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const client = AuthManager.createAuthenticatedLogicAnalyzerClient();
|
||||||
|
|
||||||
|
// 准备配置数据 - 只包含启用的通道
|
||||||
|
const enabledSignals = signalConfigs.filter(
|
||||||
|
(signal, index) => channels[index].enabled,
|
||||||
|
);
|
||||||
|
|
||||||
|
const config = new CaptureConfig({
|
||||||
|
globalMode: currentGlobalMode.value,
|
||||||
|
signalConfigs: enabledSignals.map(
|
||||||
|
(signal) =>
|
||||||
|
({
|
||||||
|
signalIndex: signal.signalIndex,
|
||||||
|
operator: signal.operator,
|
||||||
|
value: signal.value,
|
||||||
|
}) as SignalTriggerConfig,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
// 发送配置
|
||||||
|
const success = await client.configureCapture(config);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
const enabledChannelCount = channels.filter(
|
||||||
|
(ch) => ch.enabled,
|
||||||
|
).length;
|
||||||
|
alert?.success(
|
||||||
|
`配置已成功应用,启用了 ${enabledChannelCount} 个通道和触发条件`,
|
||||||
|
3000,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw new Error("应用配置失败");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("应用配置失败:", error);
|
||||||
|
alert?.error("应用配置失败,请检查设备连接", 3000);
|
||||||
|
} finally {
|
||||||
|
isApplying.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetConfiguration = () => {
|
||||||
|
currentGlobalMode.value = GlobalCaptureMode.AND;
|
||||||
|
|
||||||
|
channels.forEach((channel, index) => {
|
||||||
|
channel.enabled = false;
|
||||||
|
channel.label = `CH${index}`;
|
||||||
|
channel.color = defaultColors[index];
|
||||||
|
});
|
||||||
|
|
||||||
|
signalConfigs.forEach((signal) => {
|
||||||
|
signal.operator = SignalOperator.Equal;
|
||||||
|
signal.value = SignalValue.Logic1;
|
||||||
|
});
|
||||||
|
|
||||||
|
alert?.info("配置已重置", 2000);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
// 原有的逻辑数据
|
||||||
|
logicData,
|
||||||
|
|
||||||
|
// 触发设置状态
|
||||||
|
currentGlobalMode,
|
||||||
|
isApplying,
|
||||||
|
channels,
|
||||||
|
signalConfigs,
|
||||||
|
enabledChannelCount,
|
||||||
|
|
||||||
|
// 选项数据
|
||||||
|
globalModes,
|
||||||
|
operators,
|
||||||
|
signalValues,
|
||||||
|
|
||||||
|
// 触发设置方法
|
||||||
|
enableAllChannels,
|
||||||
|
disableAllChannels,
|
||||||
|
setGlobalMode,
|
||||||
|
applyConfiguration,
|
||||||
|
resetConfiguration,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export { useProvideLogicAnalyzer, useLogicAnalyzerState };
|
|
@ -1,7 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="w-full h-150">
|
<div
|
||||||
|
class="w-full"
|
||||||
|
:class="{
|
||||||
|
'h-48': !analyzer.logicData.value,
|
||||||
|
'h-150': analyzer.logicData.value,
|
||||||
|
}"
|
||||||
|
>
|
||||||
<v-chart
|
<v-chart
|
||||||
v-if="data"
|
v-if="analyzer.logicData.value"
|
||||||
class="w-full h-full"
|
class="w-full h-full"
|
||||||
:option="option"
|
:option="option"
|
||||||
autoresize
|
autoresize
|
||||||
|
@ -9,9 +15,29 @@
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
class="w-full h-full flex items-center justify-center text-gray-500"
|
class="w-full h-full flex flex-col gap-6 items-center justify-center"
|
||||||
>
|
>
|
||||||
暂无数据
|
<div class="text-center">
|
||||||
|
<h3 class="text-xl font-semibold text-slate-600 mb-2">
|
||||||
|
暂无逻辑分析数据
|
||||||
|
</h3>
|
||||||
|
<p class="text-sm text-slate-500">点击下方按钮生成测试数据用于观察</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="group relative px-8 py-3 bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 text-white font-medium rounded-lg shadow-lg hover:shadow-xl transform hover:scale-105 transition-all duration-200 ease-in-out focus:outline-none focus:ring-4 focus:ring-blue-300 active:scale-95"
|
||||||
|
@click="handleGenerateTestData"
|
||||||
|
>
|
||||||
|
<span class="flex items-center gap-2">
|
||||||
|
<RefreshCcw
|
||||||
|
class="w-5 h-5 group-hover:rotate-180 transition-transform duration-300"
|
||||||
|
/>
|
||||||
|
生成测试数据
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
class="absolute inset-0 bg-white opacity-0 group-hover:opacity-20 rounded-lg transition-opacity duration-200"
|
||||||
|
></div>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -19,7 +45,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, shallowRef } from "vue";
|
import { computed, shallowRef } from "vue";
|
||||||
import VChart from "vue-echarts";
|
import VChart from "vue-echarts";
|
||||||
import type { LogicDataType } from "./index";
|
import { generateTestLogicData } from "./index";
|
||||||
|
import { RefreshCcw } from "lucide-vue-next";
|
||||||
|
|
||||||
// Echarts
|
// Echarts
|
||||||
import { use } from "echarts/core";
|
import { use } from "echarts/core";
|
||||||
|
@ -45,6 +72,9 @@ import type {
|
||||||
XAXisOption,
|
XAXisOption,
|
||||||
YAXisOption,
|
YAXisOption,
|
||||||
} from "echarts/types/dist/shared";
|
} from "echarts/types/dist/shared";
|
||||||
|
import { useLogicAnalyzerState } from "./LogicAnalyzerManager";
|
||||||
|
import { useRequiredInjection } from "@/utils/Common";
|
||||||
|
import { isUndefined } from "lodash";
|
||||||
|
|
||||||
use([
|
use([
|
||||||
TooltipComponent,
|
TooltipComponent,
|
||||||
|
@ -65,24 +95,19 @@ type EChartsOption = ComposeOption<
|
||||||
| LineSeriesOption
|
| LineSeriesOption
|
||||||
>;
|
>;
|
||||||
|
|
||||||
// Define props
|
const analyzer = useRequiredInjection(useLogicAnalyzerState);
|
||||||
interface Props {
|
|
||||||
data?: LogicDataType;
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
|
||||||
|
|
||||||
// 添加更新选项来减少重绘
|
// 添加更新选项来减少重绘
|
||||||
const updateOptions = shallowRef({
|
const updateOptions = shallowRef({
|
||||||
notMerge: false,
|
notMerge: false,
|
||||||
lazyUpdate: true,
|
lazyUpdate: true,
|
||||||
silent: false
|
silent: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const option = computed((): EChartsOption => {
|
const option = computed((): EChartsOption => {
|
||||||
if (!props.data) return {};
|
if (isUndefined(analyzer.logicData.value)) return {};
|
||||||
|
|
||||||
const channelCount = props.data.y.length;
|
const channelCount = analyzer.logicData.value.y.length;
|
||||||
const channelSpacing = 2; // 每个通道之间的间距
|
const channelSpacing = 2; // 每个通道之间的间距
|
||||||
|
|
||||||
// 使用单个网格
|
// 使用单个网格
|
||||||
|
@ -100,9 +125,12 @@ const option = computed((): EChartsOption => {
|
||||||
{
|
{
|
||||||
type: "category",
|
type: "category",
|
||||||
boundaryGap: false,
|
boundaryGap: false,
|
||||||
data: props.data!.x.map((x) => x.toFixed(3)),
|
data: analyzer.logicData.value.x.map((x) => x.toFixed(3)),
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
formatter: (value: string) => `${value}${props.data!.xUnit}`,
|
formatter: (value: string) =>
|
||||||
|
analyzer.logicData.value
|
||||||
|
? `${value}${analyzer.logicData.value.xUnit}`
|
||||||
|
: `${value}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -117,8 +145,8 @@ const option = computed((): EChartsOption => {
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
formatter: (value: number) => {
|
formatter: (value: number) => {
|
||||||
const channelIndex = Math.round(value / channelSpacing);
|
const channelIndex = Math.round(value / channelSpacing);
|
||||||
return channelIndex < channelCount
|
return channelIndex < channelCount && analyzer.logicData.value
|
||||||
? props.data!.channelNames[channelIndex]
|
? analyzer.logicData.value.channelNames[channelIndex]
|
||||||
: "";
|
: "";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -127,10 +155,15 @@ const option = computed((): EChartsOption => {
|
||||||
];
|
];
|
||||||
|
|
||||||
// 创建系列数据,每个通道有不同的Y偏移
|
// 创建系列数据,每个通道有不同的Y偏移
|
||||||
const series: LineSeriesOption[] = props.data.y.map((channelData, index) => ({
|
const series: LineSeriesOption[] = analyzer.logicData.value.y.map(
|
||||||
name: props.data!.channelNames[index],
|
(channelData: number[], index: number) => ({
|
||||||
|
name:
|
||||||
|
analyzer.logicData.value?.channelNames?.[index] ??
|
||||||
|
`Channel ${index + 1}`,
|
||||||
type: "line",
|
type: "line",
|
||||||
data: channelData.map((value) => value + index * channelSpacing + 0.2),
|
data: channelData.map(
|
||||||
|
(value: number) => value + index * channelSpacing + 0.2,
|
||||||
|
),
|
||||||
step: "end",
|
step: "end",
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
width: 2,
|
width: 2,
|
||||||
|
@ -147,7 +180,8 @@ const option = computed((): EChartsOption => {
|
||||||
// progressive: 2000,
|
// progressive: 2000,
|
||||||
// 减少动画以避免闪烁
|
// 减少动画以避免闪烁
|
||||||
animation: false,
|
animation: false,
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// 全局动画配置
|
// 全局动画配置
|
||||||
|
@ -164,16 +198,21 @@ const option = computed((): EChartsOption => {
|
||||||
},
|
},
|
||||||
formatter: (params: any) => {
|
formatter: (params: any) => {
|
||||||
if (Array.isArray(params) && params.length > 0) {
|
if (Array.isArray(params) && params.length > 0) {
|
||||||
const timeValue = props.data!.x[params[0].dataIndex];
|
const timeValue = analyzer.logicData.value!.x[params[0].dataIndex];
|
||||||
const dataIndex = params[0].dataIndex;
|
const dataIndex = params[0].dataIndex;
|
||||||
|
|
||||||
let tooltip = `Time: ${timeValue.toFixed(3)}${props.data!.xUnit}<br/>`;
|
let tooltip = `Time: ${timeValue.toFixed(3)}${analyzer.logicData.value!.xUnit}<br/>`;
|
||||||
|
|
||||||
// 显示所有通道在当前时间点的原始数值(0或1)
|
// 显示所有通道在当前时间点的原始数值(0或1)
|
||||||
props.data!.channelNames.forEach((channelName, index) => {
|
if (analyzer.logicData.value) {
|
||||||
const originalValue = props.data!.y[index][dataIndex];
|
analyzer.logicData.value.channelNames.forEach(
|
||||||
|
(channelName: string, index: number) => {
|
||||||
|
const originalValue =
|
||||||
|
analyzer.logicData.value!.y[index][dataIndex];
|
||||||
tooltip += `${channelName}: ${originalValue}<br/>`;
|
tooltip += `${channelName}: ${originalValue}<br/>`;
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return tooltip;
|
return tooltip;
|
||||||
}
|
}
|
||||||
|
@ -207,4 +246,8 @@ const option = computed((): EChartsOption => {
|
||||||
series: series,
|
series: series,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function handleGenerateTestData() {
|
||||||
|
analyzer.logicData.value = generateTestLogicData();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,84 +1,53 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="space-y-4">
|
<div class="space-y-6">
|
||||||
<!-- 全局触发模式配置 -->
|
<!-- 通道状态概览 -->
|
||||||
|
<div class="stats stats-horizontal bg-base-100 shadow flex justify-between">
|
||||||
|
<div class="stat">
|
||||||
|
<div class="stat-title">总通道数</div>
|
||||||
|
<div class="stat-value text-primary">8</div>
|
||||||
|
<div class="stat-desc">逻辑分析仪通道</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat">
|
||||||
|
<div class="stat-title">启用通道</div>
|
||||||
|
<div class="stat-value text-success">{{ enabledChannelCount }}</div>
|
||||||
|
<div class="stat-desc">当前激活通道</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat">
|
||||||
|
<div class="stat-title">采样率</div>
|
||||||
|
<div class="stat-value text-info">100MHz</div>
|
||||||
|
<div class="stat-desc">最大采样频率</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 通道配置 -->
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
|
<!-- 全局触发模式选择 -->
|
||||||
|
<div class="flex flex-row justify-between my-4 mx-2">
|
||||||
|
<div class="flex flex-row gap-4">
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="label-text font-medium">全局触发模式</span>
|
<span class="label-text text-sm">全局触发逻辑</span>
|
||||||
</label>
|
</label>
|
||||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-2">
|
|
||||||
<button
|
|
||||||
v-for="mode in globalModes"
|
|
||||||
:key="mode.value"
|
|
||||||
@click="setGlobalMode(mode.value)"
|
|
||||||
:class="[
|
|
||||||
'btn btn-sm',
|
|
||||||
currentGlobalMode === mode.value ? 'btn-primary' : 'btn-outline',
|
|
||||||
]"
|
|
||||||
>
|
|
||||||
{{ mode.label }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text-alt text-gray-500">
|
|
||||||
选择多路信号触发条件的逻辑组合方式
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 信号触发配置 -->
|
|
||||||
<div class="form-control">
|
|
||||||
<label class="label">
|
|
||||||
<span class="label-text font-medium">信号触发配置</span>
|
|
||||||
</label>
|
|
||||||
<div class="space-y-2">
|
|
||||||
<div
|
|
||||||
v-for="(signal, index) in signalConfigs"
|
|
||||||
:key="index"
|
|
||||||
class="flex items-center gap-2 p-3 bg-base-200 rounded-lg"
|
|
||||||
>
|
|
||||||
<span class="text-sm font-medium w-16">CH{{ index }}</span>
|
|
||||||
|
|
||||||
<!-- 操作符选择 -->
|
|
||||||
<select
|
<select
|
||||||
v-model="signal.operator"
|
v-model="currentGlobalMode"
|
||||||
class="select select-sm select-bordered w-32"
|
@change="setGlobalMode(currentGlobalMode)"
|
||||||
>
|
class="select select-sm select-bordered w-full"
|
||||||
<option v-for="op in operators" :key="op.value" :value="op.value">
|
|
||||||
{{ op.label }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 信号值选择 -->
|
|
||||||
<select
|
|
||||||
v-model="signal.value"
|
|
||||||
class="select select-sm select-bordered w-32"
|
|
||||||
>
|
>
|
||||||
<option
|
<option
|
||||||
v-for="val in signalValues"
|
v-for="mode in globalModes"
|
||||||
:key="val.value"
|
:key="mode.value"
|
||||||
:value="val.value"
|
:value="mode.value"
|
||||||
>
|
>
|
||||||
{{ val.label }}
|
{{ mode.label }} - {{ mode.description }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 启用/禁用开关 -->
|
|
||||||
<div class="form-control">
|
|
||||||
<label class="label cursor-pointer gap-2">
|
|
||||||
<span class="label-text text-sm">启用</span>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
v-model="signal.enabled"
|
|
||||||
class="toggle toggle-sm toggle-primary"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 操作按钮 -->
|
<div class="flex flex-row gap-4">
|
||||||
<div class="flex gap-2 pt-4">
|
<button @click="toggleAllChannels" class="btn btn-primary btn-sm">
|
||||||
|
{{ enabledChannelCount > 0 ? "全部禁用" : "全部启用" }}
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="applyConfiguration"
|
@click="applyConfiguration"
|
||||||
:disabled="isApplying"
|
:disabled="isApplying"
|
||||||
|
@ -95,172 +64,313 @@
|
||||||
重置
|
重置
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<!-- 状态指示 -->
|
<!-- 通道列表 -->
|
||||||
|
<div class="space-y-2">
|
||||||
|
<!-- 表头 - 小屏幕单列时显示 -->
|
||||||
<div
|
<div
|
||||||
v-if="lastApplyResult"
|
class="flex items-center gap-2 p-2 bg-base-300 rounded-lg text-sm font-medium lg:hidden"
|
||||||
class="alert alert-sm"
|
|
||||||
:class="lastApplyResult.success ? 'alert-success' : 'alert-error'"
|
|
||||||
>
|
>
|
||||||
<span>{{ lastApplyResult.message }}</span>
|
<span class="w-16">通道</span>
|
||||||
|
<span class="w-20">启用/触发</span>
|
||||||
|
<span class="w-32">标签</span>
|
||||||
|
<span class="w-16">颜色</span>
|
||||||
|
<span class="w-32">触发操作</span>
|
||||||
|
<span class="w-32">触发值</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 通道配置网格 -->
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||||
|
<!-- 左列 (CH0-CH3) -->
|
||||||
|
<div class="space-y-2">
|
||||||
|
<!-- 左列表头 - 大屏幕时显示 -->
|
||||||
|
<div
|
||||||
|
class="hidden lg:flex items-center gap-2 p-2 bg-base-300 rounded-lg text-sm font-medium"
|
||||||
|
>
|
||||||
|
<span class="w-16">通道</span>
|
||||||
|
<span class="w-20">启用</span>
|
||||||
|
<span class="w-32">标签</span>
|
||||||
|
<span class="w-16">颜色</span>
|
||||||
|
<span class="w-32">触发操作</span>
|
||||||
|
<span class="w-32">触发值</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 左列通道 (0-3) -->
|
||||||
|
<div
|
||||||
|
v-for="(channel, index) in channels.slice(0, 4)"
|
||||||
|
:key="index"
|
||||||
|
class="flex items-center gap-2 p-3 bg-base-200 rounded-lg hover:bg-base-300 transition-colors"
|
||||||
|
>
|
||||||
|
<!-- 通道编号和颜色指示 -->
|
||||||
|
<div class="flex items-center gap-2 w-16">
|
||||||
|
<span class="font-mono font-medium">CH{{ index }}</span>
|
||||||
|
<div
|
||||||
|
class="w-3 h-3 rounded-full border-2 border-white shadow-sm"
|
||||||
|
:style="{ backgroundColor: channel.color }"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 通道启用开关(同时控制触发) -->
|
||||||
|
<div class="form-control w-20">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
v-model="channel.enabled"
|
||||||
|
class="toggle toggle-sm toggle-primary"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 通道标签 -->
|
||||||
|
<div class="form-control w-32">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
v-model="channel.label"
|
||||||
|
:placeholder="`通道 ${index}`"
|
||||||
|
class="input input-sm input-bordered w-full"
|
||||||
|
:disabled="!channel.enabled"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 颜色选择 -->
|
||||||
|
<div class="form-control w-16">
|
||||||
|
<input
|
||||||
|
type="color"
|
||||||
|
v-model="channel.color"
|
||||||
|
class="w-8 h-8 rounded border-2 border-base-300 cursor-pointer"
|
||||||
|
:disabled="!channel.enabled"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 触发操作符选择 -->
|
||||||
|
<select
|
||||||
|
v-model="signalConfigs[index].operator"
|
||||||
|
class="select select-sm select-bordered w-32"
|
||||||
|
:disabled="!channel.enabled"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="op in operators"
|
||||||
|
:key="op.value"
|
||||||
|
:value="op.value"
|
||||||
|
>
|
||||||
|
{{ op.label }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 触发信号值选择 -->
|
||||||
|
<select
|
||||||
|
v-model="signalConfigs[index].value"
|
||||||
|
class="select select-sm select-bordered w-32"
|
||||||
|
:disabled="!channel.enabled"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="val in signalValues"
|
||||||
|
:key="val.value"
|
||||||
|
:value="val.value"
|
||||||
|
>
|
||||||
|
{{ val.label }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右列 (CH4-CH7) - 仅在大屏幕显示 -->
|
||||||
|
<div class="hidden lg:block space-y-2">
|
||||||
|
<!-- 右列表头 -->
|
||||||
|
<div
|
||||||
|
class="flex items-center gap-2 p-2 bg-base-300 rounded-lg text-sm font-medium"
|
||||||
|
>
|
||||||
|
<span class="w-16">通道</span>
|
||||||
|
<span class="w-20">启用/触发</span>
|
||||||
|
<span class="w-32">标签</span>
|
||||||
|
<span class="w-16">颜色</span>
|
||||||
|
<span class="w-32">触发操作</span>
|
||||||
|
<span class="w-32">触发值</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右列通道 (4-7) -->
|
||||||
|
<div
|
||||||
|
v-for="(channel, index) in channels.slice(4, 8)"
|
||||||
|
:key="index + 4"
|
||||||
|
class="flex items-center gap-2 p-3 bg-base-200 rounded-lg hover:bg-base-300 transition-colors"
|
||||||
|
>
|
||||||
|
<!-- 通道编号和颜色指示 -->
|
||||||
|
<div class="flex items-center gap-2 w-16">
|
||||||
|
<span class="font-mono font-medium">CH{{ index + 4 }}</span>
|
||||||
|
<div
|
||||||
|
class="w-3 h-3 rounded-full border-2 border-white shadow-sm"
|
||||||
|
:style="{ backgroundColor: channel.color }"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 通道启用开关(同时控制触发) -->
|
||||||
|
<div class="form-control w-20">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
v-model="channel.enabled"
|
||||||
|
class="toggle toggle-sm toggle-primary"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 通道标签 -->
|
||||||
|
<div class="form-control w-32">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
v-model="channel.label"
|
||||||
|
:placeholder="`通道 ${index + 4}`"
|
||||||
|
class="input input-sm input-bordered w-full"
|
||||||
|
:disabled="!channel.enabled"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 颜色选择 -->
|
||||||
|
<div class="form-control w-16">
|
||||||
|
<input
|
||||||
|
type="color"
|
||||||
|
v-model="channel.color"
|
||||||
|
class="w-8 h-8 rounded border-2 border-base-300 cursor-pointer"
|
||||||
|
:disabled="!channel.enabled"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 触发操作符选择 -->
|
||||||
|
<select
|
||||||
|
v-model="signalConfigs[index + 4].operator"
|
||||||
|
class="select select-sm select-bordered w-32"
|
||||||
|
:disabled="!channel.enabled"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="op in operators"
|
||||||
|
:key="op.value"
|
||||||
|
:value="op.value"
|
||||||
|
>
|
||||||
|
{{ op.label }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 触发信号值选择 -->
|
||||||
|
<select
|
||||||
|
v-model="signalConfigs[index + 4].value"
|
||||||
|
class="select select-sm select-bordered w-32"
|
||||||
|
:disabled="!channel.enabled"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="val in signalValues"
|
||||||
|
:key="val.value"
|
||||||
|
:value="val.value"
|
||||||
|
>
|
||||||
|
{{ val.label }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 小屏幕时继续显示 CH4-CH7 -->
|
||||||
|
<div class="lg:hidden space-y-2">
|
||||||
|
<div
|
||||||
|
v-for="(channel, index) in channels.slice(4, 8)"
|
||||||
|
:key="index + 4"
|
||||||
|
class="flex items-center gap-2 p-3 bg-base-200 rounded-lg hover:bg-base-300 transition-colors"
|
||||||
|
>
|
||||||
|
<!-- 通道编号和颜色指示 -->
|
||||||
|
<div class="flex items-center gap-2 w-16">
|
||||||
|
<span class="font-mono font-medium">CH{{ index + 4 }}</span>
|
||||||
|
<div
|
||||||
|
class="w-3 h-3 rounded-full border-2 border-white shadow-sm"
|
||||||
|
:style="{ backgroundColor: channel.color }"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 通道启用开关(同时控制触发) -->
|
||||||
|
<div class="form-control w-20">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
v-model="channel.enabled"
|
||||||
|
class="toggle toggle-sm toggle-primary"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 通道标签 -->
|
||||||
|
<div class="form-control w-32">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
v-model="channel.label"
|
||||||
|
:placeholder="`通道 ${index + 4}`"
|
||||||
|
class="input input-sm input-bordered w-full"
|
||||||
|
:disabled="!channel.enabled"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 颜色选择 -->
|
||||||
|
<div class="form-control w-16">
|
||||||
|
<input
|
||||||
|
type="color"
|
||||||
|
v-model="channel.color"
|
||||||
|
class="w-8 h-8 rounded border-2 border-base-300 cursor-pointer"
|
||||||
|
:disabled="!channel.enabled"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 触发操作符选择 -->
|
||||||
|
<select
|
||||||
|
v-model="signalConfigs[index + 4].operator"
|
||||||
|
class="select select-sm select-bordered w-32"
|
||||||
|
:disabled="!channel.enabled"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="op in operators"
|
||||||
|
:key="op.value"
|
||||||
|
:value="op.value"
|
||||||
|
>
|
||||||
|
{{ op.label }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 触发信号值选择 -->
|
||||||
|
<select
|
||||||
|
v-model="signalConfigs[index + 4].value"
|
||||||
|
class="select select-sm select-bordered w-32"
|
||||||
|
:disabled="!channel.enabled"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="val in signalValues"
|
||||||
|
:key="val.value"
|
||||||
|
:value="val.value"
|
||||||
|
>
|
||||||
|
{{ val.label }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, computed } from "vue";
|
import { useRequiredInjection } from "@/utils/Common";
|
||||||
import { useEquipments } from "@/stores/equipments";
|
import { useLogicAnalyzerState } from "./LogicAnalyzerManager";
|
||||||
import {
|
|
||||||
CaptureConfig,
|
|
||||||
LogicAnalyzerClient,
|
|
||||||
GlobalCaptureMode,
|
|
||||||
SignalOperator,
|
|
||||||
SignalValue,
|
|
||||||
type SignalTriggerConfig,
|
|
||||||
} from "@/APIClient";
|
|
||||||
import { AuthManager } from "@/utils/AuthManager";
|
|
||||||
|
|
||||||
// 使用设备配置
|
const {
|
||||||
const equipments = useEquipments();
|
currentGlobalMode,
|
||||||
|
isApplying,
|
||||||
|
channels,
|
||||||
|
signalConfigs,
|
||||||
|
enabledChannelCount,
|
||||||
|
globalModes,
|
||||||
|
operators,
|
||||||
|
signalValues,
|
||||||
|
enableAllChannels,
|
||||||
|
disableAllChannels,
|
||||||
|
setGlobalMode,
|
||||||
|
applyConfiguration,
|
||||||
|
resetConfiguration,
|
||||||
|
} = useRequiredInjection(useLogicAnalyzerState);
|
||||||
|
|
||||||
// 当前全局模式
|
const toggleAllChannels = () => {
|
||||||
const currentGlobalMode = ref<GlobalCaptureMode>(GlobalCaptureMode.AND);
|
if (enabledChannelCount.value > 0) {
|
||||||
|
disableAllChannels();
|
||||||
// 加载状态
|
|
||||||
const isApplying = ref(false);
|
|
||||||
const lastApplyResult = ref<{ success: boolean; message: string } | null>(null);
|
|
||||||
|
|
||||||
// 全局模式选项
|
|
||||||
const globalModes = [
|
|
||||||
{
|
|
||||||
value: GlobalCaptureMode.AND,
|
|
||||||
label: "AND",
|
|
||||||
description: "所有条件都满足时触发",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: GlobalCaptureMode.OR,
|
|
||||||
label: "OR",
|
|
||||||
description: "任一条件满足时触发",
|
|
||||||
},
|
|
||||||
{ value: GlobalCaptureMode.NAND, label: "NAND", description: "AND的非" },
|
|
||||||
{ value: GlobalCaptureMode.NOR, label: "NOR", description: "OR的非" },
|
|
||||||
];
|
|
||||||
|
|
||||||
// 操作符选项
|
|
||||||
const operators = [
|
|
||||||
{ value: SignalOperator.Equal, label: "=" },
|
|
||||||
{ value: SignalOperator.NotEqual, label: "≠" },
|
|
||||||
{ value: SignalOperator.LessThan, label: "<" },
|
|
||||||
{ value: SignalOperator.LessThanOrEqual, label: "≤" },
|
|
||||||
{ value: SignalOperator.GreaterThan, label: ">" },
|
|
||||||
{ value: SignalOperator.GreaterThanOrEqual, label: "≥" },
|
|
||||||
];
|
|
||||||
|
|
||||||
// 信号值选项
|
|
||||||
const signalValues = [
|
|
||||||
{ value: SignalValue.Logic0, label: "0" },
|
|
||||||
{ value: SignalValue.Logic1, label: "1" },
|
|
||||||
{ value: SignalValue.NotCare, label: "X" },
|
|
||||||
{ value: SignalValue.Rise, label: "↑" },
|
|
||||||
{ value: SignalValue.Fall, label: "↓" },
|
|
||||||
{ value: SignalValue.RiseOrFall, label: "↕" },
|
|
||||||
{ value: SignalValue.NoChange, label: "—" },
|
|
||||||
{ value: SignalValue.SomeNumber, label: "#" },
|
|
||||||
];
|
|
||||||
|
|
||||||
// 8个信号通道的配置
|
|
||||||
const signalConfigs = reactive(
|
|
||||||
Array.from({ length: 8 }, (_, index) => ({
|
|
||||||
signalIndex: index,
|
|
||||||
operator: SignalOperator.Equal,
|
|
||||||
value: SignalValue.Logic1,
|
|
||||||
enabled: false,
|
|
||||||
})),
|
|
||||||
);
|
|
||||||
|
|
||||||
// 设置全局触发模式
|
|
||||||
const setGlobalMode = async (mode: GlobalCaptureMode) => {
|
|
||||||
try {
|
|
||||||
const client = AuthManager.createAuthenticatedLogicAnalyzerClient();
|
|
||||||
const success = await client.setGlobalTrigMode(mode);
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
currentGlobalMode.value = mode;
|
|
||||||
lastApplyResult.value = {
|
|
||||||
success: true,
|
|
||||||
message: `全局触发模式已设置为 ${globalModes.find((m) => m.value === mode)?.label}`,
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error("设置失败");
|
enableAllChannels();
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("设置全局触发模式失败:", error);
|
|
||||||
lastApplyResult.value = {
|
|
||||||
success: false,
|
|
||||||
message: "设置全局触发模式失败",
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 应用完整配置
|
|
||||||
const applyConfiguration = async () => {
|
|
||||||
isApplying.value = true;
|
|
||||||
lastApplyResult.value = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const client = AuthManager.createAuthenticatedLogicAnalyzerClient();
|
|
||||||
|
|
||||||
// 准备配置数据
|
|
||||||
const enabledSignals = signalConfigs.filter((signal) => signal.enabled);
|
|
||||||
const config = new CaptureConfig({
|
|
||||||
globalMode: currentGlobalMode.value,
|
|
||||||
signalConfigs: enabledSignals.map(
|
|
||||||
(signal) =>
|
|
||||||
({
|
|
||||||
signalIndex: signal.signalIndex,
|
|
||||||
operator: signal.operator,
|
|
||||||
value: signal.value,
|
|
||||||
}) as SignalTriggerConfig,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
// 发送配置
|
|
||||||
const success = await client.configureCapture(config);
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
lastApplyResult.value = {
|
|
||||||
success: true,
|
|
||||||
message: `配置已成功应用,启用了 ${enabledSignals.length} 个通道`,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
throw new Error("应用配置失败");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("应用配置失败:", error);
|
|
||||||
lastApplyResult.value = {
|
|
||||||
success: false,
|
|
||||||
message: "应用配置失败,请检查设备连接",
|
|
||||||
};
|
|
||||||
} finally {
|
|
||||||
isApplying.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 重置配置
|
|
||||||
const resetConfiguration = () => {
|
|
||||||
currentGlobalMode.value = GlobalCaptureMode.AND;
|
|
||||||
signalConfigs.forEach((signal) => {
|
|
||||||
signal.operator = SignalOperator.Equal;
|
|
||||||
signal.value = SignalValue.Logic1;
|
|
||||||
signal.enabled = false;
|
|
||||||
});
|
|
||||||
lastApplyResult.value = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 清除状态消息
|
|
||||||
setTimeout(() => {
|
|
||||||
if (lastApplyResult.value) {
|
|
||||||
lastApplyResult.value = null;
|
|
||||||
}
|
|
||||||
}, 5000);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { exp } from "mathjs";
|
||||||
import LogicalWaveFormDisplay from "./LogicalWaveFormDisplay.vue";
|
import LogicalWaveFormDisplay from "./LogicalWaveFormDisplay.vue";
|
||||||
|
|
||||||
type LogicDataType = {
|
type LogicDataType = {
|
||||||
|
@ -75,4 +76,4 @@ function generateTestLogicData(): LogicDataType {
|
||||||
|
|
||||||
export { LogicalWaveFormDisplay, generateTestLogicData, type LogicDataType };
|
export { LogicalWaveFormDisplay, generateTestLogicData, type LogicDataType };
|
||||||
export { default as TriggerSettings } from './TriggerSettings.vue'
|
export { default as TriggerSettings } from './TriggerSettings.vue'
|
||||||
export { default as ChannelConfig } from './ChannelConfig.vue'
|
export { useProvideLogicAnalyzer , useLogicAnalyzerState } from './LogicAnalyzerManager.ts'
|
|
@ -1,18 +1,25 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-base-100 flex flex-col">
|
<div class="bg-base-100 flex flex-col gap-10 mb-5">
|
||||||
<!-- 逻辑信号展示 -->
|
<!-- 逻辑信号展示 -->
|
||||||
<div class="card bg-base-200 shadow-xl">
|
<div class="card bg-base-200 shadow-xl">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="card-title">
|
<h2 class="card-title flex justify-between items-center">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
<Zap class="w-5 h-5" />
|
<Zap class="w-5 h-5" />
|
||||||
逻辑信号分析
|
逻辑信号分析
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<button class="btn btn-sm btn-error" @click="handleDeleteData">
|
||||||
|
清空
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
<LogicalWaveFormDisplay :data="generateTestLogicData()" />
|
<LogicalWaveFormDisplay />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 触发设置 -->
|
<!-- 触发设置 -->
|
||||||
<div class="card bg-base-200 shadow-xl mt-4">
|
<div class="card bg-base-200 shadow-xl">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="card-title">
|
<h2 class="card-title">
|
||||||
<Settings class="w-5 h-5" />
|
<Settings class="w-5 h-5" />
|
||||||
|
@ -21,17 +28,6 @@
|
||||||
<TriggerSettings />
|
<TriggerSettings />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 通道配置 -->
|
|
||||||
<div class="card bg-base-200 shadow-xl mt-4">
|
|
||||||
<div class="card-body">
|
|
||||||
<h2 class="card-title">
|
|
||||||
<Layers class="w-5 h-5" />
|
|
||||||
通道配置
|
|
||||||
</h2>
|
|
||||||
<ChannelConfig />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -42,8 +38,14 @@ import {
|
||||||
LogicalWaveFormDisplay,
|
LogicalWaveFormDisplay,
|
||||||
generateTestLogicData,
|
generateTestLogicData,
|
||||||
TriggerSettings,
|
TriggerSettings,
|
||||||
ChannelConfig
|
|
||||||
} from "@/components/LogicAnalyzer";
|
} from "@/components/LogicAnalyzer";
|
||||||
|
import { useProvideLogicAnalyzer } from "@/components/LogicAnalyzer";
|
||||||
|
|
||||||
|
const analyzer = useProvideLogicAnalyzer();
|
||||||
|
|
||||||
|
function handleDeleteData() {
|
||||||
|
analyzer.logicData.value = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
// 使用全局设备配置
|
// 使用全局设备配置
|
||||||
const equipments = useEquipments();
|
const equipments = useEquipments();
|
||||||
|
|
Loading…
Reference in New Issue