Merge branch 'master' of ssh://git.swordlost.top:222/SikongJueluo/FPGA_WebLab into dpp
This commit is contained in:
		@@ -148,6 +148,9 @@ class Camera
 | 
			
		||||
        // var resetResult2 = await Reset();
 | 
			
		||||
        // if (!resetResult2.IsSuccessful) return resetResult2;
 | 
			
		||||
 | 
			
		||||
        var autofocusResult = await InitAutoFocus();
 | 
			
		||||
        if (!autofocusResult.IsSuccessful) return autofocusResult;
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1270,6 +1273,32 @@ class Camera
 | 
			
		||||
        var result = await ConfigureRegisters(focusRegisters);
 | 
			
		||||
        if (!result.IsSuccessful) return result;
 | 
			
		||||
 | 
			
		||||
        // 读取寄存器判断初始化是否完毕
 | 
			
		||||
        for (int iteration = 1000; iteration > 0; iteration--)
 | 
			
		||||
        {
 | 
			
		||||
            var readResult = await ReadRegister(0x3029);
 | 
			
		||||
            if (!readResult.IsSuccessful)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"读取自动对焦初始化状态失败: {readResult.Error}");
 | 
			
		||||
                return new(readResult.Error);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            logger.Trace($"自动对焦初始化状态检查, state=0x{readResult.Value:X2}");
 | 
			
		||||
            
 | 
			
		||||
            if (readResult.Value == 0x70)
 | 
			
		||||
            {
 | 
			
		||||
                break; // 初始化完成
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if (iteration == 1)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"自动对焦初始化状态检查超时!! state=0x{readResult.Value:X2}");
 | 
			
		||||
                return new(new Exception($"自动对焦初始化状态检查超时, state=0x{readResult.Value:X2}"));
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            await Task.Delay(1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        logger.Info("OV5640自动对焦功能初始化完成");
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
@@ -1293,10 +1322,7 @@ class Camera
 | 
			
		||||
        logger.Info("已发送单点对焦命令 (0x3022 = 0x03)");
 | 
			
		||||
 | 
			
		||||
        // 步骤2: 读取寄存器 0x3029 的状态,如果返回值为 0x10,代表对焦已完成
 | 
			
		||||
        int iteration = 5000;
 | 
			
		||||
        byte focusStatus;
 | 
			
		||||
 | 
			
		||||
        do
 | 
			
		||||
        for (int iteration = 5000; iteration > 0; iteration--)
 | 
			
		||||
        {
 | 
			
		||||
            var readResult = await ReadRegisters(0x3029);
 | 
			
		||||
            if (!readResult.IsSuccessful)
 | 
			
		||||
@@ -1305,23 +1331,20 @@ class Camera
 | 
			
		||||
                return new(readResult.Error);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            focusStatus = readResult.Value;
 | 
			
		||||
 | 
			
		||||
            if (focusStatus == 0x10)
 | 
			
		||||
            if (readResult.Value == 0x10)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Info("对焦已完成 (0x3029 = 0x10)");
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (iteration-- == 0)
 | 
			
		||||
            if (iteration == 1)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"自动对焦超时,状态: 0x{focusStatus:X2}");
 | 
			
		||||
                return new(new Exception($"自动对焦超时,状态: 0x{focusStatus:X2}"));
 | 
			
		||||
                logger.Error($"自动对焦超时,状态: 0x{readResult.Value:X2}");
 | 
			
		||||
                return new(new Exception($"自动对焦超时,状态: 0x{readResult.Value:X2}"));
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            await Task.Delay(100);
 | 
			
		||||
        }
 | 
			
		||||
        while (focusStatus != 0x10);
 | 
			
		||||
 | 
			
		||||
        // 步骤3: 写寄存器 0x3022 为 0x06,暂停对焦过程,使镜头将保持在此对焦位置
 | 
			
		||||
        var pauseResult = await ConfigureRegisters([[0x3022, 0x06]]);
 | 
			
		||||
@@ -1331,7 +1354,7 @@ class Camera
 | 
			
		||||
            return pauseResult;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        logger.Info($"自动对焦完成并暂停,镜头保持在对焦位置,剩余迭代次数: {iteration}");
 | 
			
		||||
        logger.Info("自动对焦完成并暂停,镜头保持在对焦位置");
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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,322 @@
 | 
			
		||||
import { createInjectionState } from "@vueuse/core";
 | 
			
		||||
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 type LogicDataType = {
 | 
			
		||||
  x: number[];
 | 
			
		||||
  y: number[][]; // 8 channels of digital data (0 or 1)
 | 
			
		||||
  xUnit: "s" | "ms" | "us" | "ns";
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 通道接口定义
 | 
			
		||||
export type 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 channelNames = computed(() => 
 | 
			
		||||
      channels.map(channel => channel.label)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // 添加计算属性:获取启用通道的名称数组
 | 
			
		||||
    const enabledChannelNames = computed(() => 
 | 
			
		||||
      channels.filter(channel => channel.enabled).map(channel => channel.label)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // 添加设置逻辑数据的方法
 | 
			
		||||
    const setLogicData = (data: LogicDataType) => {
 | 
			
		||||
      logicData.value = data;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // 添加生成测试数据的方法
 | 
			
		||||
    const generateTestData = () => {
 | 
			
		||||
      const sampleRate = 10000; // 10kHz sampling
 | 
			
		||||
      const duration = 1;
 | 
			
		||||
      const points = Math.floor(sampleRate * duration);
 | 
			
		||||
 | 
			
		||||
      const x = Array.from({ length: points }, (_, i) => (i / sampleRate) * 1000); // time in ms
 | 
			
		||||
 | 
			
		||||
      // Generate 8 channels with different digital patterns
 | 
			
		||||
      const y = [
 | 
			
		||||
        // Channel 0: Clock signal 100Hz
 | 
			
		||||
        Array.from(
 | 
			
		||||
          { length: points },
 | 
			
		||||
          (_, i) => Math.floor((100 * i) / sampleRate) % 2,
 | 
			
		||||
        ),
 | 
			
		||||
        // Channel 1: Clock/2 signal 50Hz
 | 
			
		||||
        Array.from(
 | 
			
		||||
          { length: points },
 | 
			
		||||
          (_, i) => Math.floor((50 * i) / sampleRate) % 2,
 | 
			
		||||
        ),
 | 
			
		||||
        // Channel 2: Clock/4 signal 25Hz
 | 
			
		||||
        Array.from(
 | 
			
		||||
          { length: points },
 | 
			
		||||
          (_, i) => Math.floor((25 * i) / sampleRate) % 2,
 | 
			
		||||
        ),
 | 
			
		||||
        // Channel 3: Clock/8 signal 12.5Hz
 | 
			
		||||
        Array.from(
 | 
			
		||||
          { length: points },
 | 
			
		||||
          (_, i) => Math.floor((12.5 * i) / sampleRate) % 2,
 | 
			
		||||
        ),
 | 
			
		||||
        // Channel 4: Data signal (pseudo-random pattern)
 | 
			
		||||
        Array.from(
 | 
			
		||||
          { length: points },
 | 
			
		||||
          (_, i) => Math.abs( Math.floor(Math.sin(i * 0.01) * 10) % 2 ),
 | 
			
		||||
        ),
 | 
			
		||||
        // Channel 5: Enable signal (periodic pulse)
 | 
			
		||||
        Array.from(
 | 
			
		||||
          { length: points },
 | 
			
		||||
          (_, i) => (Math.floor(i / 50) % 10) < 3 ? 1 : 0,
 | 
			
		||||
        ),
 | 
			
		||||
        // Channel 6: Reset signal (occasional pulse)
 | 
			
		||||
        Array.from(
 | 
			
		||||
          { length: points },
 | 
			
		||||
          (_, i) => (Math.floor(i / 200) % 20) === 0 ? 1 : 0,
 | 
			
		||||
        ),
 | 
			
		||||
        // Channel 7: Status signal (slow changing)
 | 
			
		||||
        Array.from(
 | 
			
		||||
          { length: points },
 | 
			
		||||
          (_, i) => Math.floor(i / 1000) % 2,
 | 
			
		||||
        ),
 | 
			
		||||
      ];
 | 
			
		||||
 | 
			
		||||
      // 同时更新通道标签为更有意义的名称
 | 
			
		||||
      const testChannelNames = [
 | 
			
		||||
        "CLK",
 | 
			
		||||
        "CLK/2", 
 | 
			
		||||
        "CLK/4",
 | 
			
		||||
        "CLK/8",
 | 
			
		||||
        "PWM",
 | 
			
		||||
        "ENABLE",
 | 
			
		||||
        "RESET",
 | 
			
		||||
        "STATUS"
 | 
			
		||||
      ];
 | 
			
		||||
 | 
			
		||||
      channels.forEach((channel, index) => {
 | 
			
		||||
        channel.label = testChannelNames[index];
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      // 设置逻辑数据
 | 
			
		||||
      setLogicData({ x, y, xUnit: "ms" });
 | 
			
		||||
      
 | 
			
		||||
      alert?.success("测试数据生成成功", 2000);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      // 原有的逻辑数据
 | 
			
		||||
      logicData,
 | 
			
		||||
 | 
			
		||||
      // 触发设置状态
 | 
			
		||||
      currentGlobalMode,
 | 
			
		||||
      isApplying,
 | 
			
		||||
      channels,
 | 
			
		||||
      signalConfigs,
 | 
			
		||||
      enabledChannelCount,
 | 
			
		||||
      channelNames,
 | 
			
		||||
      enabledChannelNames,
 | 
			
		||||
 | 
			
		||||
      // 选项数据
 | 
			
		||||
      globalModes,
 | 
			
		||||
      operators,
 | 
			
		||||
      signalValues,
 | 
			
		||||
 | 
			
		||||
      // 触发设置方法
 | 
			
		||||
      enableAllChannels,
 | 
			
		||||
      disableAllChannels,
 | 
			
		||||
      setGlobalMode,
 | 
			
		||||
      applyConfiguration,
 | 
			
		||||
      resetConfiguration,
 | 
			
		||||
      setLogicData,
 | 
			
		||||
      generateTestData,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export { useProvideLogicAnalyzer, useLogicAnalyzerState };
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,43 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="w-full h-150">
 | 
			
		||||
    <v-chart 
 | 
			
		||||
      v-if="data" 
 | 
			
		||||
      class="w-full h-full" 
 | 
			
		||||
      :option="option" 
 | 
			
		||||
      autoresize 
 | 
			
		||||
  <div
 | 
			
		||||
    class="w-full"
 | 
			
		||||
    :class="{
 | 
			
		||||
      'h-48': !analyzer.logicData.value,
 | 
			
		||||
      'h-150': analyzer.logicData.value,
 | 
			
		||||
    }"
 | 
			
		||||
  >
 | 
			
		||||
    <v-chart
 | 
			
		||||
      v-if="analyzer.logicData.value"
 | 
			
		||||
      class="w-full h-full"
 | 
			
		||||
      :option="option"
 | 
			
		||||
      autoresize
 | 
			
		||||
      :update-options="updateOptions"
 | 
			
		||||
    />
 | 
			
		||||
    <div
 | 
			
		||||
      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="analyzer.generateTestData"
 | 
			
		||||
      >
 | 
			
		||||
        <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>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -19,7 +45,7 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { computed, shallowRef } from "vue";
 | 
			
		||||
import VChart from "vue-echarts";
 | 
			
		||||
import type { LogicDataType } from "./index";
 | 
			
		||||
import { RefreshCcw } from "lucide-vue-next";
 | 
			
		||||
 | 
			
		||||
// Echarts
 | 
			
		||||
import { use } from "echarts/core";
 | 
			
		||||
@@ -45,6 +71,9 @@ import type {
 | 
			
		||||
  XAXisOption,
 | 
			
		||||
  YAXisOption,
 | 
			
		||||
} from "echarts/types/dist/shared";
 | 
			
		||||
import { useLogicAnalyzerState } from "./LogicAnalyzerManager";
 | 
			
		||||
import { useRequiredInjection } from "@/utils/Common";
 | 
			
		||||
import { isUndefined } from "lodash";
 | 
			
		||||
 | 
			
		||||
use([
 | 
			
		||||
  TooltipComponent,
 | 
			
		||||
@@ -65,24 +94,19 @@ type EChartsOption = ComposeOption<
 | 
			
		||||
  | LineSeriesOption
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
// Define props
 | 
			
		||||
interface Props {
 | 
			
		||||
  data?: LogicDataType;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const props = defineProps<Props>();
 | 
			
		||||
const analyzer = useRequiredInjection(useLogicAnalyzerState);
 | 
			
		||||
 | 
			
		||||
// 添加更新选项来减少重绘
 | 
			
		||||
const updateOptions = shallowRef({
 | 
			
		||||
  notMerge: false,
 | 
			
		||||
  lazyUpdate: true,
 | 
			
		||||
  silent: false
 | 
			
		||||
  silent: false,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
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; // 每个通道之间的间距
 | 
			
		||||
 | 
			
		||||
  // 使用单个网格
 | 
			
		||||
@@ -100,9 +124,12 @@ const option = computed((): EChartsOption => {
 | 
			
		||||
    {
 | 
			
		||||
      type: "category",
 | 
			
		||||
      boundaryGap: false,
 | 
			
		||||
      data: props.data!.x.map((x) => x.toFixed(3)),
 | 
			
		||||
      data: analyzer.logicData.value.x.map((x) => x.toFixed(3)),
 | 
			
		||||
      axisLabel: {
 | 
			
		||||
        formatter: (value: string) => `${value}${props.data!.xUnit}`,
 | 
			
		||||
        formatter: (value: string) =>
 | 
			
		||||
          analyzer.logicData.value
 | 
			
		||||
            ? `${value}${analyzer.logicData.value.xUnit}`
 | 
			
		||||
            : `${value}`,
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  ];
 | 
			
		||||
@@ -118,7 +145,7 @@ const option = computed((): EChartsOption => {
 | 
			
		||||
        formatter: (value: number) => {
 | 
			
		||||
          const channelIndex = Math.round(value / channelSpacing);
 | 
			
		||||
          return channelIndex < channelCount
 | 
			
		||||
            ? props.data!.channelNames[channelIndex]
 | 
			
		||||
            ? analyzer.channelNames.value[channelIndex]
 | 
			
		||||
            : "";
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
@@ -127,27 +154,31 @@ const option = computed((): EChartsOption => {
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  // 创建系列数据,每个通道有不同的Y偏移
 | 
			
		||||
  const series: LineSeriesOption[] = props.data.y.map((channelData, index) => ({
 | 
			
		||||
    name: props.data!.channelNames[index],
 | 
			
		||||
    type: "line",
 | 
			
		||||
    data: channelData.map((value) => value + index * channelSpacing + 0.2),
 | 
			
		||||
    step: "end",
 | 
			
		||||
    lineStyle: {
 | 
			
		||||
      width: 2,
 | 
			
		||||
    },
 | 
			
		||||
    areaStyle: {
 | 
			
		||||
      opacity: 0.3,
 | 
			
		||||
      origin: index * channelSpacing,
 | 
			
		||||
    },
 | 
			
		||||
    symbol: "none",
 | 
			
		||||
    // 优化性能配置
 | 
			
		||||
    sampling: "lttb",
 | 
			
		||||
    // large: true,
 | 
			
		||||
    // largeThreshold: 2000,
 | 
			
		||||
    // progressive: 2000,
 | 
			
		||||
    // 减少动画以避免闪烁
 | 
			
		||||
    animation: false,
 | 
			
		||||
  }));
 | 
			
		||||
  const series: LineSeriesOption[] = analyzer.logicData.value.y.map(
 | 
			
		||||
    (channelData: number[], index: number) => ({
 | 
			
		||||
      name: analyzer.channelNames.value[index],
 | 
			
		||||
      type: "line",
 | 
			
		||||
      data: channelData.map(
 | 
			
		||||
        (value: number) => value + index * channelSpacing + 0.2,
 | 
			
		||||
      ),
 | 
			
		||||
      step: "end",
 | 
			
		||||
      lineStyle: {
 | 
			
		||||
        width: 2,
 | 
			
		||||
      },
 | 
			
		||||
      areaStyle: {
 | 
			
		||||
        opacity: 0.3,
 | 
			
		||||
        origin: index * channelSpacing,
 | 
			
		||||
      },
 | 
			
		||||
      symbol: "none",
 | 
			
		||||
      // 优化性能配置
 | 
			
		||||
      sampling: "lttb",
 | 
			
		||||
      // large: true,
 | 
			
		||||
      // largeThreshold: 2000,
 | 
			
		||||
      // progressive: 2000,
 | 
			
		||||
      // 减少动画以避免闪烁
 | 
			
		||||
      animation: false,
 | 
			
		||||
    }),
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    // 全局动画配置
 | 
			
		||||
@@ -164,16 +195,21 @@ const option = computed((): EChartsOption => {
 | 
			
		||||
      },
 | 
			
		||||
      formatter: (params: any) => {
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
          let tooltip = `Time: ${timeValue.toFixed(3)}${props.data!.xUnit}<br/>`;
 | 
			
		||||
          let tooltip = `Time: ${timeValue.toFixed(3)}${analyzer.logicData.value!.xUnit}<br/>`;
 | 
			
		||||
 | 
			
		||||
          // 显示所有通道在当前时间点的原始数值(0或1)
 | 
			
		||||
          props.data!.channelNames.forEach((channelName, index) => {
 | 
			
		||||
            const originalValue = props.data!.y[index][dataIndex];
 | 
			
		||||
            tooltip += `${channelName}: ${originalValue}<br/>`;
 | 
			
		||||
          });
 | 
			
		||||
          if (analyzer.logicData.value) {
 | 
			
		||||
            analyzer.channelNames.value.forEach(
 | 
			
		||||
              (channelName: string, index: number) => {
 | 
			
		||||
                const originalValue =
 | 
			
		||||
                  analyzer.logicData.value!.y[index][dataIndex];
 | 
			
		||||
                tooltip += `${channelName}: ${originalValue}<br/>`;
 | 
			
		||||
              },
 | 
			
		||||
            );
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          return tooltip;
 | 
			
		||||
        }
 | 
			
		||||
@@ -207,4 +243,5 @@ const option = computed((): EChartsOption => {
 | 
			
		||||
    series: series,
 | 
			
		||||
  };
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,266 +1,376 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="space-y-4">
 | 
			
		||||
    <!-- 全局触发模式配置 -->
 | 
			
		||||
    <div class="form-control">
 | 
			
		||||
      <label class="label">
 | 
			
		||||
        <span class="label-text font-medium">全局触发模式</span>
 | 
			
		||||
      </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 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="label">
 | 
			
		||||
        <span class="label-text-alt text-gray-500">
 | 
			
		||||
          选择多路信号触发条件的逻辑组合方式
 | 
			
		||||
        </span>
 | 
			
		||||
 | 
			
		||||
      <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">
 | 
			
		||||
      <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>
 | 
			
		||||
 | 
			
		||||
          <!-- 操作符选择 -->
 | 
			
		||||
      <!-- 全局触发模式选择 -->
 | 
			
		||||
      <div class="flex flex-row justify-between my-4 mx-2">
 | 
			
		||||
        <div class="flex flex-row gap-4">
 | 
			
		||||
          <label class="label">
 | 
			
		||||
            <span class="label-text text-sm">全局触发逻辑</span>
 | 
			
		||||
          </label>
 | 
			
		||||
          <select
 | 
			
		||||
            v-model="signal.operator"
 | 
			
		||||
            class="select select-sm select-bordered w-32"
 | 
			
		||||
          >
 | 
			
		||||
            <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"
 | 
			
		||||
            v-model="currentGlobalMode"
 | 
			
		||||
            @change="setGlobalMode(currentGlobalMode)"
 | 
			
		||||
            class="select select-sm select-bordered w-full"
 | 
			
		||||
          >
 | 
			
		||||
            <option
 | 
			
		||||
              v-for="val in signalValues"
 | 
			
		||||
              :key="val.value"
 | 
			
		||||
              :value="val.value"
 | 
			
		||||
              v-for="mode in globalModes"
 | 
			
		||||
              :key="mode.value"
 | 
			
		||||
              :value="mode.value"
 | 
			
		||||
            >
 | 
			
		||||
              {{ val.label }}
 | 
			
		||||
              {{ mode.label }} - {{ mode.description }}
 | 
			
		||||
            </option>
 | 
			
		||||
          </select>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
          <!-- 启用/禁用开关 -->
 | 
			
		||||
          <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 class="flex flex-row gap-4">
 | 
			
		||||
          <button @click="toggleAllChannels" class="btn btn-primary btn-sm">
 | 
			
		||||
            {{ enabledChannelCount > 0 ? "全部禁用" : "全部启用" }}
 | 
			
		||||
          </button>
 | 
			
		||||
          <button
 | 
			
		||||
            @click="applyConfiguration"
 | 
			
		||||
            :disabled="isApplying"
 | 
			
		||||
            class="btn btn-primary btn-sm"
 | 
			
		||||
          >
 | 
			
		||||
            <span
 | 
			
		||||
              v-if="isApplying"
 | 
			
		||||
              class="loading loading-spinner loading-sm"
 | 
			
		||||
            ></span>
 | 
			
		||||
            应用配置
 | 
			
		||||
          </button>
 | 
			
		||||
 | 
			
		||||
          <button @click="resetConfiguration" class="btn btn-outline btn-sm">
 | 
			
		||||
            重置
 | 
			
		||||
          </button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <!-- 通道列表 -->
 | 
			
		||||
      <div class="space-y-2">
 | 
			
		||||
        <!-- 表头 - 小屏幕单列时显示 -->
 | 
			
		||||
        <div
 | 
			
		||||
          class="flex items-center gap-2 p-2 bg-base-300 rounded-lg text-sm font-medium lg:hidden"
 | 
			
		||||
        >
 | 
			
		||||
          <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 class="flex gap-2 pt-4">
 | 
			
		||||
      <button
 | 
			
		||||
        @click="applyConfiguration"
 | 
			
		||||
        :disabled="isApplying"
 | 
			
		||||
        class="btn btn-primary btn-sm"
 | 
			
		||||
      >
 | 
			
		||||
        <span
 | 
			
		||||
          v-if="isApplying"
 | 
			
		||||
          class="loading loading-spinner loading-sm"
 | 
			
		||||
        ></span>
 | 
			
		||||
        应用配置
 | 
			
		||||
      </button>
 | 
			
		||||
 | 
			
		||||
      <button @click="resetConfiguration" class="btn btn-outline btn-sm">
 | 
			
		||||
        重置
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- 状态指示 -->
 | 
			
		||||
    <div
 | 
			
		||||
      v-if="lastApplyResult"
 | 
			
		||||
      class="alert alert-sm"
 | 
			
		||||
      :class="lastApplyResult.success ? 'alert-success' : 'alert-error'"
 | 
			
		||||
    >
 | 
			
		||||
      <span>{{ lastApplyResult.message }}</span>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref, reactive, computed } from "vue";
 | 
			
		||||
import { useEquipments } from "@/stores/equipments";
 | 
			
		||||
import {
 | 
			
		||||
  CaptureConfig,
 | 
			
		||||
  LogicAnalyzerClient,
 | 
			
		||||
  GlobalCaptureMode,
 | 
			
		||||
  SignalOperator,
 | 
			
		||||
  SignalValue,
 | 
			
		||||
  type SignalTriggerConfig,
 | 
			
		||||
} from "@/APIClient";
 | 
			
		||||
import { AuthManager } from "@/utils/AuthManager";
 | 
			
		||||
import { useRequiredInjection } from "@/utils/Common";
 | 
			
		||||
import { useLogicAnalyzerState } from "./LogicAnalyzerManager";
 | 
			
		||||
 | 
			
		||||
// 使用设备配置
 | 
			
		||||
const equipments = useEquipments();
 | 
			
		||||
const {
 | 
			
		||||
  currentGlobalMode,
 | 
			
		||||
  isApplying,
 | 
			
		||||
  channels,
 | 
			
		||||
  signalConfigs,
 | 
			
		||||
  enabledChannelCount,
 | 
			
		||||
  globalModes,
 | 
			
		||||
  operators,
 | 
			
		||||
  signalValues,
 | 
			
		||||
  enableAllChannels,
 | 
			
		||||
  disableAllChannels,
 | 
			
		||||
  setGlobalMode,
 | 
			
		||||
  applyConfiguration,
 | 
			
		||||
  resetConfiguration,
 | 
			
		||||
} = useRequiredInjection(useLogicAnalyzerState);
 | 
			
		||||
 | 
			
		||||
// 当前全局模式
 | 
			
		||||
const currentGlobalMode = ref<GlobalCaptureMode>(GlobalCaptureMode.AND);
 | 
			
		||||
 | 
			
		||||
// 加载状态
 | 
			
		||||
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 {
 | 
			
		||||
      throw new Error("设置失败");
 | 
			
		||||
    }
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error("设置全局触发模式失败:", error);
 | 
			
		||||
    lastApplyResult.value = {
 | 
			
		||||
      success: false,
 | 
			
		||||
      message: "设置全局触发模式失败",
 | 
			
		||||
    };
 | 
			
		||||
const toggleAllChannels = () => {
 | 
			
		||||
  if (enabledChannelCount.value > 0) {
 | 
			
		||||
    disableAllChannels();
 | 
			
		||||
  } else {
 | 
			
		||||
    enableAllChannels();
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 应用完整配置
 | 
			
		||||
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>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,78 +1,5 @@
 | 
			
		||||
import LogicalWaveFormDisplay from "./LogicalWaveFormDisplay.vue";
 | 
			
		||||
 | 
			
		||||
type LogicDataType = {
 | 
			
		||||
  x: number[];
 | 
			
		||||
  y: number[][]; // 8 channels of digital data (0 or 1)
 | 
			
		||||
  xUnit: "s" | "ms" | "us" | "ns";
 | 
			
		||||
  channelNames: string[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Test data generator for 8-channel digital signals
 | 
			
		||||
function generateTestLogicData(): LogicDataType {
 | 
			
		||||
  const sampleRate = 10000; // 10kHz sampling
 | 
			
		||||
  const duration = 1;
 | 
			
		||||
  const points = Math.floor(sampleRate * duration);
 | 
			
		||||
 | 
			
		||||
  const x = Array.from({ length: points }, (_, i) => (i / sampleRate) * 1000); // time in ms
 | 
			
		||||
 | 
			
		||||
  // Generate 8 channels with different digital patterns
 | 
			
		||||
  const y = [
 | 
			
		||||
    // Channel 0: Clock signal 100Hz
 | 
			
		||||
    Array.from(
 | 
			
		||||
      { length: points },
 | 
			
		||||
      (_, i) => Math.floor((100 * i) / sampleRate) % 2,
 | 
			
		||||
    ),
 | 
			
		||||
    // Channel 1: Clock/2 signal 50Hz
 | 
			
		||||
    Array.from(
 | 
			
		||||
      { length: points },
 | 
			
		||||
      (_, i) => Math.floor((50 * i) / sampleRate) % 2,
 | 
			
		||||
    ),
 | 
			
		||||
    // Channel 2: Clock/4 signal 25Hz
 | 
			
		||||
    Array.from(
 | 
			
		||||
      { length: points },
 | 
			
		||||
      (_, i) => Math.floor((25 * i) / sampleRate) % 2,
 | 
			
		||||
    ),
 | 
			
		||||
    // Channel 3: Clock/8 signal 12.5Hz
 | 
			
		||||
    Array.from(
 | 
			
		||||
      { length: points },
 | 
			
		||||
      (_, i) => Math.floor((12.5 * i) / sampleRate) % 2,
 | 
			
		||||
    ),
 | 
			
		||||
    // Channel 4: Data signal (pseudo-random pattern)
 | 
			
		||||
    Array.from(
 | 
			
		||||
      { length: points },
 | 
			
		||||
      (_, i) => Math.abs( Math.floor(Math.sin(i * 0.01) * 10) % 2 ),
 | 
			
		||||
    ),
 | 
			
		||||
    // Channel 5: Enable signal (periodic pulse)
 | 
			
		||||
    Array.from(
 | 
			
		||||
      { length: points },
 | 
			
		||||
      (_, i) => (Math.floor(i / 50) % 10) < 3 ? 1 : 0,
 | 
			
		||||
    ),
 | 
			
		||||
    // Channel 6: Reset signal (occasional pulse)
 | 
			
		||||
    Array.from(
 | 
			
		||||
      { length: points },
 | 
			
		||||
      (_, i) => (Math.floor(i / 200) % 20) === 0 ? 1 : 0,
 | 
			
		||||
    ),
 | 
			
		||||
    // Channel 7: Status signal (slow changing)
 | 
			
		||||
    Array.from(
 | 
			
		||||
      { length: points },
 | 
			
		||||
      (_, i) => Math.floor(i / 1000) % 2,
 | 
			
		||||
    ),
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  const channelNames = [
 | 
			
		||||
    "CLK",
 | 
			
		||||
    "CLK/2", 
 | 
			
		||||
    "CLK/4",
 | 
			
		||||
    "CLK/8",
 | 
			
		||||
    "PWM",
 | 
			
		||||
    "ENABLE",
 | 
			
		||||
    "RESET",
 | 
			
		||||
    "STATUS"
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  return { x, y, xUnit: "ms", channelNames };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export { LogicalWaveFormDisplay, generateTestLogicData, type LogicDataType };
 | 
			
		||||
export { LogicalWaveFormDisplay };
 | 
			
		||||
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>
 | 
			
		||||
  <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-body">
 | 
			
		||||
        <h2 class="card-title">
 | 
			
		||||
          <Zap class="w-5 h-5" />
 | 
			
		||||
          逻辑信号分析
 | 
			
		||||
        <h2 class="card-title flex justify-between items-center">
 | 
			
		||||
          <div class="flex items-center gap-2">
 | 
			
		||||
            <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>
 | 
			
		||||
        <LogicalWaveFormDisplay :data="generateTestLogicData()" />
 | 
			
		||||
        <LogicalWaveFormDisplay />
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- 触发设置 -->
 | 
			
		||||
    <div class="card bg-base-200 shadow-xl mt-4">
 | 
			
		||||
    <div class="card bg-base-200 shadow-xl">
 | 
			
		||||
      <div class="card-body">
 | 
			
		||||
        <h2 class="card-title">
 | 
			
		||||
          <Settings class="w-5 h-5" />
 | 
			
		||||
@@ -21,29 +28,24 @@
 | 
			
		||||
        <TriggerSettings />
 | 
			
		||||
      </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>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { Zap, Settings, Layers } from "lucide-vue-next";
 | 
			
		||||
import { useEquipments } from "@/stores/equipments";
 | 
			
		||||
import { 
 | 
			
		||||
  LogicalWaveFormDisplay, 
 | 
			
		||||
import {
 | 
			
		||||
  LogicalWaveFormDisplay,
 | 
			
		||||
  generateTestLogicData,
 | 
			
		||||
  TriggerSettings,
 | 
			
		||||
  ChannelConfig 
 | 
			
		||||
} from "@/components/LogicAnalyzer";
 | 
			
		||||
import { useProvideLogicAnalyzer } from "@/components/LogicAnalyzer";
 | 
			
		||||
 | 
			
		||||
const analyzer = useProvideLogicAnalyzer();
 | 
			
		||||
 | 
			
		||||
function handleDeleteData() {
 | 
			
		||||
  analyzer.logicData.value = undefined;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 使用全局设备配置
 | 
			
		||||
const equipments = useEquipments();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user