862 lines
27 KiB
TypeScript
862 lines
27 KiB
TypeScript
import { createInjectionState } from "@vueuse/core";
|
||
import { shallowRef, reactive, ref, computed } from "vue";
|
||
import { Mutex } from "async-mutex";
|
||
import {
|
||
CaptureConfig,
|
||
CaptureStatus,
|
||
LogicAnalyzerClient,
|
||
GlobalCaptureMode,
|
||
SignalOperator,
|
||
SignalTriggerConfig,
|
||
SignalValue,
|
||
AnalyzerChannelDiv,
|
||
AnalyzerClockDiv,
|
||
} from "@/APIClient";
|
||
import { AuthManager } from "@/utils/AuthManager";
|
||
import { useAlertStore } from "@/components/Alert";
|
||
import { useRequiredInjection } from "@/utils/Common";
|
||
|
||
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 channelDivOptions = [
|
||
{ value: 1, label: "1通道", description: "启用1个通道 (CH0)" },
|
||
{ value: 2, label: "2通道", description: "启用2个通道 (CH0-CH1)" },
|
||
{ value: 4, label: "4通道", description: "启用4个通道 (CH0-CH3)" },
|
||
{ value: 8, label: "8通道", description: "启用8个通道 (CH0-CH7)" },
|
||
{ value: 16, label: "16通道", description: "启用16个通道 (CH0-CH15)" },
|
||
{ value: 32, label: "32通道", description: "启用32个通道 (CH0-CH31)" },
|
||
];
|
||
|
||
const ClockDivOptions = [
|
||
{
|
||
value: AnalyzerClockDiv.DIV1,
|
||
label: "120MHz",
|
||
description: "采样频率120MHz",
|
||
},
|
||
{
|
||
value: AnalyzerClockDiv.DIV2,
|
||
label: "60MHz",
|
||
description: "采样频率60MHz",
|
||
},
|
||
{
|
||
value: AnalyzerClockDiv.DIV4,
|
||
label: "30MHz",
|
||
description: "采样频率30MHz",
|
||
},
|
||
{
|
||
value: AnalyzerClockDiv.DIV8,
|
||
label: "15MHz",
|
||
description: "采样频率15MHz",
|
||
},
|
||
{
|
||
value: AnalyzerClockDiv.DIV16,
|
||
label: "7.5MHz",
|
||
description: "采样频率7.5MHz",
|
||
},
|
||
{
|
||
value: AnalyzerClockDiv.DIV32,
|
||
label: "3.75MHz",
|
||
description: "采样频率3.75MHz",
|
||
},
|
||
{
|
||
value: AnalyzerClockDiv.DIV64,
|
||
label: "1.875MHz",
|
||
description: "采样频率1.875MHz",
|
||
},
|
||
{
|
||
value: AnalyzerClockDiv.DIV128,
|
||
label: "937.5KHz",
|
||
description: "采样频率937.5KHz",
|
||
},
|
||
];
|
||
|
||
// 捕获深度限制常量
|
||
const CAPTURE_LENGTH_MIN = 1024; // 最小捕获深度 1024
|
||
const CAPTURE_LENGTH_MAX = 0x10000000 - 0x01000000; // 最大捕获深度
|
||
|
||
// 预捕获深度限制常量
|
||
const PRE_CAPTURE_LENGTH_MIN = 2; // 最小预捕获深度 2
|
||
|
||
// 默认颜色数组
|
||
const defaultColors = [
|
||
"#FF5733",
|
||
"#33FF57",
|
||
"#3357FF",
|
||
"#FF33F5",
|
||
"#F5FF33",
|
||
"#33FFF5",
|
||
"#FF8C33",
|
||
"#8C33FF",
|
||
];
|
||
|
||
// 添加逻辑分析仪基础频率常量
|
||
const BASE_LOGIC_ANALYZER_FREQUENCY = 120_000_000; // 120MHz基础频率
|
||
|
||
const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
|
||
() => {
|
||
const logicData = shallowRef<LogicDataType>();
|
||
const alert = useRequiredInjection(useAlertStore);
|
||
|
||
// 添加互斥锁
|
||
const operationMutex = new Mutex();
|
||
|
||
// 触发设置相关状态
|
||
const currentGlobalMode = ref<GlobalCaptureMode>(GlobalCaptureMode.AND);
|
||
const currentChannelDiv = ref<number>(8); // 默认启用8个通道
|
||
const captureLength = ref<number>(CAPTURE_LENGTH_MIN); // 捕获深度,默认为最小值
|
||
const preCaptureLength = ref<number>(PRE_CAPTURE_LENGTH_MIN); // 预捕获深度,默认0
|
||
const currentclockDiv = ref<AnalyzerClockDiv>(AnalyzerClockDiv.DIV1); // 默认时钟分频为1
|
||
const isApplying = ref(false);
|
||
const isCapturing = ref(false); // 添加捕获状态标识
|
||
|
||
// 通道配置
|
||
const channels = reactive<Channel[]>(
|
||
Array.from({ length: 32 }, (_, index) => ({
|
||
enabled: index < 8, // 默认启用前8个通道
|
||
label: `CH${index}`,
|
||
color: defaultColors[index % defaultColors.length], // 使用模运算避免数组越界
|
||
})),
|
||
);
|
||
|
||
// 32个信号通道的配置
|
||
const signalConfigs = reactive<SignalTriggerConfig[]>(
|
||
Array.from(
|
||
{ length: 32 },
|
||
(_, index) =>
|
||
new SignalTriggerConfig({
|
||
signalIndex: index,
|
||
operator: SignalOperator.Equal,
|
||
value: SignalValue.NotCare,
|
||
}),
|
||
),
|
||
);
|
||
|
||
// 计算启用的通道数量
|
||
const enabledChannelCount = computed(
|
||
() => channels.filter((channel) => channel.enabled).length,
|
||
);
|
||
|
||
// 添加计算属性:获取通道名称数组
|
||
const channelNames = computed(() =>
|
||
channels.map((channel) => channel.label),
|
||
);
|
||
|
||
// 添加计算属性:获取启用通道的名称数组
|
||
const enabledChannels = computed(() =>
|
||
channels.filter((channel) => channel.enabled),
|
||
);
|
||
|
||
// 计算属性:根据当前时钟分频获取实际采样频率
|
||
const currentSampleFrequency = computed(() => {
|
||
const divValue = Math.pow(2, currentclockDiv.value);
|
||
return BASE_LOGIC_ANALYZER_FREQUENCY / divValue;
|
||
});
|
||
|
||
// 计算属性:获取当前采样周期(纳秒)
|
||
const currentSamplePeriodNs = computed(() => {
|
||
return 1_000_000_000 / currentSampleFrequency.value;
|
||
});
|
||
|
||
// 转换通道数字到枚举值
|
||
const getChannelDivEnum = (channelCount: number): AnalyzerChannelDiv => {
|
||
switch (channelCount) {
|
||
case 1:
|
||
return AnalyzerChannelDiv.ONE;
|
||
case 2:
|
||
return AnalyzerChannelDiv.TWO;
|
||
case 4:
|
||
return AnalyzerChannelDiv.FOUR;
|
||
case 8:
|
||
return AnalyzerChannelDiv.EIGHT;
|
||
case 16:
|
||
return AnalyzerChannelDiv.XVI;
|
||
case 32:
|
||
return AnalyzerChannelDiv.XXXII;
|
||
default:
|
||
return AnalyzerChannelDiv.EIGHT;
|
||
}
|
||
};
|
||
|
||
// 验证捕获深度
|
||
const validateCaptureLength = (
|
||
value: number,
|
||
): { valid: boolean; message?: string } => {
|
||
if (!Number.isInteger(value)) {
|
||
return { valid: false, message: "捕获深度必须是整数" };
|
||
}
|
||
if (value < CAPTURE_LENGTH_MIN) {
|
||
return {
|
||
valid: false,
|
||
message: `捕获深度不能小于 ${CAPTURE_LENGTH_MIN}`,
|
||
};
|
||
}
|
||
if (value > CAPTURE_LENGTH_MAX) {
|
||
return {
|
||
valid: false,
|
||
message: `捕获深度不能大于 ${CAPTURE_LENGTH_MAX.toLocaleString()}`,
|
||
};
|
||
}
|
||
return { valid: true };
|
||
};
|
||
|
||
// 验证预捕获深度
|
||
const validatePreCaptureLength = (
|
||
value: number,
|
||
currentCaptureLength: number,
|
||
): { valid: boolean; message?: string } => {
|
||
if (!Number.isInteger(value)) {
|
||
return { valid: false, message: "预捕获深度必须是整数" };
|
||
}
|
||
if (value < PRE_CAPTURE_LENGTH_MIN) {
|
||
return {
|
||
valid: false,
|
||
message: `预捕获深度不能小于 ${PRE_CAPTURE_LENGTH_MIN}`,
|
||
};
|
||
}
|
||
if (value >= currentCaptureLength) {
|
||
return {
|
||
valid: false,
|
||
message: `预捕获深度不能大于等于捕获深度 (${currentCaptureLength})`,
|
||
};
|
||
}
|
||
return { valid: true };
|
||
};
|
||
|
||
// 设置捕获深度
|
||
const setCaptureLength = (value: number) => {
|
||
const validation = validateCaptureLength(value);
|
||
if (!validation.valid) {
|
||
alert?.error(validation.message!, 3000);
|
||
return false;
|
||
}
|
||
|
||
// 检查预捕获深度是否仍然有效
|
||
if (preCaptureLength.value >= value) {
|
||
preCaptureLength.value = Math.max(0, value - 1);
|
||
alert?.warn(`预捕获深度已自动调整为 ${preCaptureLength.value}`, 3000);
|
||
}
|
||
|
||
captureLength.value = value;
|
||
return true;
|
||
};
|
||
|
||
// 设置预捕获深度
|
||
const setPreCaptureLength = (value: number) => {
|
||
const validation = validatePreCaptureLength(value, captureLength.value);
|
||
if (!validation.valid) {
|
||
alert?.error(validation.message!, 3000);
|
||
return false;
|
||
}
|
||
|
||
preCaptureLength.value = value;
|
||
return true;
|
||
};
|
||
|
||
// 设置通道组
|
||
const setChannelDiv = (channelCount: number) => {
|
||
// 验证通道数量是否有效
|
||
if (!channelDivOptions.find((option) => option.value === channelCount)) {
|
||
console.error(`无效的通道组设置: ${channelCount}`);
|
||
return;
|
||
}
|
||
currentChannelDiv.value = channelCount;
|
||
|
||
// 禁用所有通道
|
||
channels.forEach((channel) => {
|
||
channel.enabled = false;
|
||
});
|
||
|
||
// 启用指定数量的通道(从CH0开始)
|
||
for (let i = 0; i < channelCount && i < channels.length; i++) {
|
||
channels[i].enabled = true;
|
||
}
|
||
|
||
const option = channelDivOptions.find(
|
||
(opt) => opt.value === channelCount,
|
||
);
|
||
alert?.success(`已设置为${option?.label}`, 2000);
|
||
};
|
||
|
||
const setGlobalMode = (mode: GlobalCaptureMode) => {
|
||
currentGlobalMode.value = mode;
|
||
const modeOption = globalModes.find((m) => m.value === mode);
|
||
alert?.info(`全局触发模式已设置为 ${modeOption?.label}`, 2000);
|
||
};
|
||
|
||
const setClockDiv = (mode: AnalyzerClockDiv) => {
|
||
currentclockDiv.value = mode;
|
||
const modeOption = ClockDivOptions.find((m) => m.value === mode);
|
||
alert?.info(`时钟分频已设置为 ${modeOption?.label}`, 2000);
|
||
};
|
||
|
||
const resetConfiguration = () => {
|
||
currentGlobalMode.value = GlobalCaptureMode.AND;
|
||
currentChannelDiv.value = 8; // 重置为默认的8通道
|
||
currentclockDiv.value = AnalyzerClockDiv.DIV1; // 重置为默认采样频率
|
||
setChannelDiv(8); // 重置为默认的8通道
|
||
|
||
signalConfigs.forEach((signal) => {
|
||
signal.operator = SignalOperator.Equal;
|
||
signal.value = SignalValue.NotCare;
|
||
});
|
||
|
||
alert?.info("配置已重置", 2000);
|
||
};
|
||
|
||
// 添加设置逻辑数据的方法
|
||
const setLogicData = (data: LogicDataType) => {
|
||
logicData.value = data;
|
||
};
|
||
|
||
const getCaptureData = async () => {
|
||
try {
|
||
const client = AuthManager.createClient(LogicAnalyzerClient);
|
||
// 获取捕获数据,使用当前设置的捕获长度
|
||
const base64Data = await client.getCaptureData(captureLength.value);
|
||
|
||
// 将base64数据转换为bytes
|
||
const binaryString = atob(base64Data);
|
||
const bytes = new Uint8Array(binaryString.length);
|
||
for (let i = 0; i < binaryString.length; i++) {
|
||
bytes[i] = binaryString.charCodeAt(i);
|
||
}
|
||
|
||
// 根据当前通道数量解析数据
|
||
const channelCount = currentChannelDiv.value;
|
||
const timeStepNs = currentSamplePeriodNs.value;
|
||
|
||
let sampleCount: number;
|
||
let x: number[];
|
||
let y: number[][];
|
||
|
||
if (channelCount === 1) {
|
||
// 1通道:每个字节包含8个时间单位的数据
|
||
sampleCount = bytes.length * 8;
|
||
|
||
// 创建时间轴
|
||
x = Array.from(
|
||
{ length: sampleCount },
|
||
(_, i) => (i * timeStepNs) / 1000,
|
||
); // 转换为微秒
|
||
|
||
// 创建通道数据数组
|
||
y = Array.from({ length: 1 }, () => new Array(sampleCount));
|
||
|
||
// 解析数据:每个字节的8个位对应8个时间单位
|
||
for (let byteIndex = 0; byteIndex < bytes.length; byteIndex++) {
|
||
const byte = bytes[byteIndex];
|
||
for (let bitIndex = 0; bitIndex < 8; bitIndex++) {
|
||
const timeIndex = byteIndex * 8 + bitIndex;
|
||
y[0][timeIndex] = (byte >> bitIndex) & 1;
|
||
}
|
||
}
|
||
} else if (channelCount === 2) {
|
||
// 2通道:每个字节包含4个时间单位的数据
|
||
sampleCount = bytes.length * 4;
|
||
|
||
// 创建时间轴
|
||
x = Array.from(
|
||
{ length: sampleCount },
|
||
(_, i) => (i * timeStepNs) / 1000,
|
||
); // 转换为微秒
|
||
|
||
// 创建通道数据数组
|
||
y = Array.from({ length: 2 }, () => new Array(sampleCount));
|
||
|
||
// 解析数据:每个字节的8个位对应4个时间单位的2通道数据
|
||
// 位分布:[T3_CH1, T3_CH0, T2_CH1, T2_CH0, T1_CH1, T1_CH0, T0_CH1, T0_CH0]
|
||
for (let byteIndex = 0; byteIndex < bytes.length; byteIndex++) {
|
||
const byte = bytes[byteIndex];
|
||
for (let timeUnit = 0; timeUnit < 4; timeUnit++) {
|
||
const timeIndex = byteIndex * 4 + timeUnit;
|
||
const bitOffset = timeUnit * 2;
|
||
y[0][timeIndex] = (byte >> bitOffset) & 1; // CH0
|
||
y[1][timeIndex] = (byte >> (bitOffset + 1)) & 1; // CH1
|
||
}
|
||
}
|
||
} else if (channelCount === 4) {
|
||
// 4通道:每个字节包含2个时间单位的数据
|
||
sampleCount = bytes.length * 2;
|
||
|
||
// 创建时间轴
|
||
x = Array.from(
|
||
{ length: sampleCount },
|
||
(_, i) => (i * timeStepNs) / 1000,
|
||
); // 转换为微秒
|
||
|
||
// 创建通道数据数组
|
||
y = Array.from({ length: 4 }, () => new Array(sampleCount));
|
||
|
||
// 解析数据:每个字节的8个位对应2个时间单位的4通道数据
|
||
// 位分布:[T1_CH3, T1_CH2, T1_CH1, T1_CH0, T0_CH3, T0_CH2, T0_CH1, T0_CH0]
|
||
for (let byteIndex = 0; byteIndex < bytes.length; byteIndex++) {
|
||
const byte = bytes[byteIndex];
|
||
|
||
// 处理第一个时间单位(低4位)
|
||
const timeIndex1 = byteIndex * 2;
|
||
for (let channel = 0; channel < 4; channel++) {
|
||
y[channel][timeIndex1] = (byte >> channel) & 1;
|
||
}
|
||
|
||
// 处理第二个时间单位(高4位)
|
||
const timeIndex2 = byteIndex * 2 + 1;
|
||
for (let channel = 0; channel < 4; channel++) {
|
||
y[channel][timeIndex2] = (byte >> (channel + 4)) & 1;
|
||
}
|
||
}
|
||
} else if (channelCount === 8) {
|
||
// 8通道:每个字节包含1个时间单位的8个通道数据
|
||
sampleCount = bytes.length;
|
||
|
||
// 创建时间轴
|
||
x = Array.from(
|
||
{ length: sampleCount },
|
||
(_, i) => (i * timeStepNs) / 1000,
|
||
); // 转换为微秒
|
||
|
||
// 创建8个通道的数据
|
||
y = Array.from({ length: 8 }, () => new Array(sampleCount));
|
||
|
||
// 解析每个字节的8个位到对应通道
|
||
for (let i = 0; i < sampleCount; i++) {
|
||
const byte = bytes[i];
|
||
for (let channel = 0; channel < 8; channel++) {
|
||
// bit0对应ch0, bit1对应ch1, ..., bit7对应ch7
|
||
y[channel][i] = (byte >> channel) & 1;
|
||
}
|
||
}
|
||
} else if (channelCount === 16) {
|
||
// 16通道:每2个字节包含1个时间单位的16个通道数据
|
||
sampleCount = bytes.length / 2;
|
||
|
||
// 创建时间轴
|
||
x = Array.from(
|
||
{ length: sampleCount },
|
||
(_, i) => (i * timeStepNs) / 1000,
|
||
); // 转换为微秒
|
||
|
||
// 创建16个通道的数据
|
||
y = Array.from({ length: 16 }, () => new Array(sampleCount));
|
||
|
||
// 解析数据:每2个字节为一个时间单位
|
||
for (let timeIndex = 0; timeIndex < sampleCount; timeIndex++) {
|
||
const byteIndex = timeIndex * 2;
|
||
const byte1 = bytes[byteIndex]; // [7:0]
|
||
const byte2 = bytes[byteIndex + 1]; // [15:8]
|
||
|
||
// 处理低8位通道 [7:0]
|
||
for (let channel = 0; channel < 8; channel++) {
|
||
y[channel][timeIndex] = (byte1 >> channel) & 1;
|
||
}
|
||
|
||
// 处理高8位通道 [15:8]
|
||
for (let channel = 0; channel < 8; channel++) {
|
||
y[channel + 8][timeIndex] = (byte2 >> channel) & 1;
|
||
}
|
||
}
|
||
} else if (channelCount === 32) {
|
||
// 32通道:每4个字节包含1个时间单位的32个通道数据
|
||
sampleCount = bytes.length / 4;
|
||
|
||
// 创建时间轴
|
||
x = Array.from(
|
||
{ length: sampleCount },
|
||
(_, i) => (i * timeStepNs) / 1000,
|
||
); // 转换为微秒
|
||
|
||
// 创建32个通道的数据
|
||
y = Array.from({ length: 32 }, () => new Array(sampleCount));
|
||
|
||
// 解析数据:每4个字节为一个时间单位
|
||
for (let timeIndex = 0; timeIndex < sampleCount; timeIndex++) {
|
||
const byteIndex = timeIndex * 4;
|
||
const byte1 = bytes[byteIndex]; // [7:0]
|
||
const byte2 = bytes[byteIndex + 1]; // [15:8]
|
||
const byte3 = bytes[byteIndex + 2]; // [23:16]
|
||
const byte4 = bytes[byteIndex + 3]; // [31:24]
|
||
|
||
// 处理 [7:0]
|
||
for (let channel = 0; channel < 8; channel++) {
|
||
y[channel][timeIndex] = (byte1 >> channel) & 1;
|
||
}
|
||
|
||
// 处理 [15:8]
|
||
for (let channel = 0; channel < 8; channel++) {
|
||
y[channel + 8][timeIndex] = (byte2 >> channel) & 1;
|
||
}
|
||
|
||
// 处理 [23:16]
|
||
for (let channel = 0; channel < 8; channel++) {
|
||
y[channel + 16][timeIndex] = (byte3 >> channel) & 1;
|
||
}
|
||
|
||
// 处理 [31:24]
|
||
for (let channel = 0; channel < 8; channel++) {
|
||
y[channel + 24][timeIndex] = (byte4 >> channel) & 1;
|
||
}
|
||
}
|
||
} else {
|
||
throw new Error(`不支持的通道数量: ${channelCount}`);
|
||
}
|
||
|
||
// 设置逻辑数据
|
||
const logicData: LogicDataType = {
|
||
x,
|
||
y,
|
||
xUnit: "us", // 微秒单位
|
||
};
|
||
|
||
setLogicData(logicData);
|
||
} catch (error) {
|
||
console.error("获取捕获数据失败:", error);
|
||
alert?.error("获取捕获数据失败", 3000);
|
||
}
|
||
};
|
||
|
||
const startCapture = async () => {
|
||
// 检查是否有其他操作正在进行
|
||
if (operationMutex.isLocked()) {
|
||
alert.warn("有其他操作正在进行中,请稍后再试", 3000);
|
||
return;
|
||
}
|
||
|
||
isCapturing.value = true;
|
||
const release = await operationMutex.acquire();
|
||
try {
|
||
const client = AuthManager.createClient(LogicAnalyzerClient);
|
||
|
||
// 1. 先应用配置
|
||
alert?.info("正在应用配置...", 2000);
|
||
|
||
// 准备配置数据 - 包含所有32个通道,未启用的通道设置为默认值
|
||
const allSignals = signalConfigs.map((signal, index) => {
|
||
if (channels[index].enabled) {
|
||
// 启用的通道使用用户配置的触发条件
|
||
return signal;
|
||
} else {
|
||
// 未启用的通道设置为默认触发条件
|
||
return new SignalTriggerConfig({
|
||
signalIndex: index,
|
||
operator: SignalOperator.Equal,
|
||
value: SignalValue.NotCare,
|
||
});
|
||
}
|
||
});
|
||
|
||
const config = new CaptureConfig({
|
||
globalMode: currentGlobalMode.value,
|
||
channelDiv: getChannelDivEnum(currentChannelDiv.value),
|
||
captureLength: captureLength.value,
|
||
preCaptureLength: preCaptureLength.value,
|
||
clockDiv: currentclockDiv.value,
|
||
signalConfigs: allSignals,
|
||
});
|
||
|
||
// 发送配置
|
||
const configSuccess = await client.configureCapture(config);
|
||
if (!configSuccess) {
|
||
throw new Error("配置应用失败");
|
||
}
|
||
|
||
const enabledChannelCount = channels.filter((ch) => ch.enabled).length;
|
||
alert?.success(
|
||
`配置已应用,启用了 ${enabledChannelCount} 个通道,捕获深度: ${captureLength.value}`,
|
||
2000,
|
||
);
|
||
|
||
// 2. 设置捕获模式为开始捕获
|
||
const captureStarted = await client.setCaptureMode(true, false);
|
||
if (!captureStarted) {
|
||
throw new Error("无法启动捕获");
|
||
}
|
||
|
||
alert?.info("开始捕获信号...", 2000);
|
||
|
||
// 3. 轮询捕获状态
|
||
let captureCompleted = false;
|
||
while (isCapturing.value) {
|
||
const status = await client.getCaptureStatus();
|
||
|
||
// 检查是否捕获完成
|
||
if (status === CaptureStatus.CaptureDone) {
|
||
captureCompleted = true;
|
||
break;
|
||
}
|
||
|
||
// 检查是否仍在捕获中
|
||
if (
|
||
status === CaptureStatus.CaptureBusy ||
|
||
status === CaptureStatus.CaptureOn ||
|
||
status === CaptureStatus.CaptureForce
|
||
) {
|
||
// 等待500毫秒后继续轮询
|
||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||
continue;
|
||
}
|
||
|
||
// 其他状态视为错误
|
||
// throw new Error(`捕获状态异常: ${status}`);
|
||
}
|
||
|
||
// 如果捕获被停止,不继续处理数据
|
||
if (!captureCompleted) {
|
||
alert?.info("捕获已停止", 2000);
|
||
return;
|
||
}
|
||
|
||
await getCaptureData();
|
||
alert.success(`捕获完成!`, 3000);
|
||
} catch (error) {
|
||
console.error("捕获失败:", error);
|
||
alert?.error(
|
||
`捕获失败: ${error instanceof Error ? error.message : "未知错误"}`,
|
||
3000,
|
||
);
|
||
} finally {
|
||
isCapturing.value = false;
|
||
release();
|
||
}
|
||
};
|
||
|
||
const stopCapture = async () => {
|
||
// 检查是否正在捕获
|
||
if (!isCapturing.value) {
|
||
alert.warn("当前没有正在进行的捕获操作", 2000);
|
||
return;
|
||
}
|
||
|
||
// 设置捕获状态为false,这会使轮询停止
|
||
isCapturing.value = false;
|
||
|
||
const release = await operationMutex.acquire();
|
||
try {
|
||
const client = AuthManager.createClient(LogicAnalyzerClient);
|
||
|
||
// 执行强制捕获来停止当前捕获
|
||
const forceSuccess = await client.setCaptureMode(false, false);
|
||
if (!forceSuccess) {
|
||
throw new Error("无法停止捕获");
|
||
}
|
||
|
||
alert.info("已停止强制捕获...", 2000);
|
||
} catch (error) {
|
||
console.error("停止捕获失败:", error);
|
||
alert.error(
|
||
`停止捕获失败: ${error instanceof Error ? error.message : "未知错误"}`,
|
||
3000,
|
||
);
|
||
} finally {
|
||
release();
|
||
}
|
||
};
|
||
|
||
const forceCapture = async () => {
|
||
// 检查是否正在捕获
|
||
if (!isCapturing.value) {
|
||
alert.warn("当前没有正在进行的捕获操作", 2000);
|
||
return;
|
||
}
|
||
|
||
const release = await operationMutex.acquire();
|
||
try {
|
||
const client = AuthManager.createClient(LogicAnalyzerClient);
|
||
|
||
// 执行强制捕获来停止当前捕获
|
||
const forceSuccess = await client.setCaptureMode(true, true);
|
||
if (!forceSuccess) {
|
||
throw new Error("无法执行强制捕获");
|
||
}
|
||
|
||
await getCaptureData();
|
||
alert.success(`强制捕获完成!`, 3000);
|
||
} catch (error) {
|
||
console.error("强制捕获失败:", error);
|
||
alert.error(
|
||
`强制捕获失败: ${error instanceof Error ? error.message : "未知错误"}`,
|
||
3000,
|
||
);
|
||
} finally {
|
||
release();
|
||
}
|
||
};
|
||
|
||
// 添加检查操作状态的计算属性
|
||
const isOperationInProgress = computed(
|
||
() => isApplying.value || isCapturing.value || operationMutex.isLocked(),
|
||
);
|
||
|
||
// 添加生成测试数据的方法
|
||
const generateTestData = () => {
|
||
const sampleRate = currentSampleFrequency.value; // 使用当前设置的采样频率
|
||
const duration = 0.001; // 1ms的数据
|
||
const points = Math.floor(sampleRate * duration);
|
||
|
||
const x = Array.from(
|
||
{ length: points },
|
||
(_, i) => (i * currentSamplePeriodNs.value) / 1000, // 时间轴,单位:微秒
|
||
);
|
||
|
||
// Generate 8 channels with different digital patterns
|
||
const y = [
|
||
// Channel 0: Clock signal 1MHz
|
||
Array.from(
|
||
{ length: points },
|
||
(_, i) => Math.floor((1_000_000 * i) / sampleRate) % 2,
|
||
),
|
||
// Channel 1: Clock/2 signal 500kHz
|
||
Array.from(
|
||
{ length: points },
|
||
(_, i) => Math.floor((500_000 * i) / sampleRate) % 2,
|
||
),
|
||
// Channel 2: Clock/4 signal 250kHz
|
||
Array.from(
|
||
{ length: points },
|
||
(_, i) => Math.floor((250_000 * i) / sampleRate) % 2,
|
||
),
|
||
// Channel 3: Clock/8 signal 125kHz
|
||
Array.from(
|
||
{ length: points },
|
||
(_, i) => Math.floor((125_000 * i) / sampleRate) % 2,
|
||
),
|
||
// Channel 4: Data signal (pseudo-random pattern)
|
||
Array.from({ length: points }, (_, i) =>
|
||
Math.abs(Math.floor(Math.sin(i * 0.001) * 10) % 2),
|
||
),
|
||
// Channel 5: Enable signal (periodic pulse)
|
||
Array.from({ length: points }, (_, i) =>
|
||
Math.floor(i / 250) % 10 < 3 ? 1 : 0,
|
||
),
|
||
// Channel 6: Reset signal (occasional pulse)
|
||
Array.from({ length: points }, (_, i) =>
|
||
Math.floor(i / 1000) % 20 === 0 ? 1 : 0,
|
||
),
|
||
// Channel 7: Status signal (slow changing)
|
||
Array.from({ length: points }, (_, i) => Math.floor(i / 5000) % 2),
|
||
];
|
||
|
||
// 同时更新通道标签为更有意义的名称
|
||
const testChannelNames = [
|
||
"CLK",
|
||
"CLK/2",
|
||
"CLK/4",
|
||
"CLK/8",
|
||
"PWM",
|
||
"ENABLE",
|
||
"RESET",
|
||
"STATUS",
|
||
];
|
||
|
||
channels.forEach((channel, index) => {
|
||
channel.label = testChannelNames[index];
|
||
});
|
||
|
||
// 设置逻辑数据
|
||
setChannelDiv(8);
|
||
setLogicData({ x, y, xUnit: "us" }); // 改为微秒单位
|
||
|
||
alert?.success("测试数据生成成功", 2000);
|
||
};
|
||
|
||
return {
|
||
// 原有的逻辑数据
|
||
logicData,
|
||
|
||
// 触发设置状态
|
||
currentGlobalMode,
|
||
currentChannelDiv, // 导出当前通道组状态
|
||
captureLength, // 导出捕获深度
|
||
preCaptureLength, // 导出预捕获深度
|
||
currentclockDiv, // 导出当前采样频率状态
|
||
isApplying,
|
||
isCapturing, // 导出捕获状态
|
||
isOperationInProgress, // 导出操作进行状态
|
||
channels,
|
||
signalConfigs,
|
||
enabledChannelCount,
|
||
channelNames,
|
||
enabledChannels,
|
||
currentSampleFrequency, // 导出当前采样频率
|
||
currentSamplePeriodNs, // 导出当前采样周期
|
||
|
||
// 选项数据
|
||
globalModes,
|
||
operators,
|
||
signalValues,
|
||
channelDivOptions, // 导出通道组选项
|
||
ClockDivOptions, // 导出采样频率选项
|
||
|
||
// 捕获深度常量和验证
|
||
CAPTURE_LENGTH_MIN,
|
||
CAPTURE_LENGTH_MAX,
|
||
PRE_CAPTURE_LENGTH_MIN,
|
||
validateCaptureLength,
|
||
validatePreCaptureLength,
|
||
setCaptureLength,
|
||
setPreCaptureLength,
|
||
|
||
// 触发设置方法
|
||
setChannelDiv, // 导出设置通道组方法
|
||
setGlobalMode,
|
||
setClockDiv, // 导出设置采样频率方法
|
||
resetConfiguration,
|
||
setLogicData,
|
||
startCapture,
|
||
forceCapture,
|
||
stopCapture,
|
||
generateTestData,
|
||
};
|
||
},
|
||
);
|
||
|
||
export { useProvideLogicAnalyzer, useLogicAnalyzerState };
|