diff --git a/server/src/Controllers/LogicAnalyzerController.cs b/server/src/Controllers/LogicAnalyzerController.cs
index f3c7343..f54eeeb 100644
--- a/server/src/Controllers/LogicAnalyzerController.cs
+++ b/server/src/Controllers/LogicAnalyzerController.cs
@@ -58,6 +58,10 @@ public class LogicAnalyzerController : ControllerBase
///
public AnalyzerChannelDiv ChannelDiv { get; set; } = AnalyzerChannelDiv.EIGHT;
///
+ /// 时钟分频系数
+ ///
+ public AnalyzerClockDiv ClockDiv { get; set; } = AnalyzerClockDiv.DIV1;
+ ///
/// 信号触发配置列表
///
public SignalTriggerConfig[] SignalConfigs { get; set; } = Array.Empty();
@@ -248,6 +252,7 @@ public class LogicAnalyzerController : ControllerBase
/// 深度
/// 预采样深度
/// 有效通道(0-[1],1-[2],2-[4],3-[8],4-[16],5-[32])
+ /// 采样时钟分频系数
/// 操作结果
[HttpPost("SetCaptureParams")]
[EnableCors("Users")]
@@ -255,7 +260,7 @@ public class LogicAnalyzerController : ControllerBase
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
- public async Task SetCaptureParams(int capture_length, int pre_capture_length, AnalyzerChannelDiv channel_div)
+ public async Task SetCaptureParams(int capture_length, int pre_capture_length, AnalyzerChannelDiv channel_div, AnalyzerClockDiv clock_div)
{
try
{
@@ -269,18 +274,18 @@ public class LogicAnalyzerController : ControllerBase
if (analyzer == null)
return BadRequest("用户未绑定有效的实验板");
- var result = await analyzer.SetCaptureParams(capture_length, pre_capture_length, channel_div);
+ var result = await analyzer.SetCaptureParams(capture_length, pre_capture_length, channel_div, clock_div);
if (!result.IsSuccessful)
{
- logger.Error($"设置深度、预采样深度、有效通道失败: {result.Error}");
- return StatusCode(StatusCodes.Status500InternalServerError, "设置深度、预采样深度、有效通道失败");
+ logger.Error($"设置深度、预采样深度、有效通道、时钟分频失败: {result.Error}");
+ return StatusCode(StatusCodes.Status500InternalServerError, "设置深度、预采样深度、有效通道、时钟分频失败");
}
return Ok(result.Value);
}
catch (Exception ex)
{
- logger.Error(ex, "设置深度、预采样深度、有效通道失败时发生异常");
+ logger.Error(ex, "设置深度、预采样深度、有效通道、时钟分频失败时发生异常");
return StatusCode(StatusCodes.Status500InternalServerError, "操作失败,请稍后重试");
}
}
@@ -332,7 +337,7 @@ public class LogicAnalyzerController : ControllerBase
}
// 设置深度、预采样深度、有效通道
var paramsResult = await analyzer.SetCaptureParams(
- config.CaptureLength, config.PreCaptureLength, config.ChannelDiv);
+ config.CaptureLength, config.PreCaptureLength, config.ChannelDiv, config.ClockDiv);
if (!paramsResult.IsSuccessful)
{
logger.Error($"设置深度、预采样深度、有效通道失败: {paramsResult.Error}");
diff --git a/server/src/Peripherals/LogicAnalyzerClient.cs b/server/src/Peripherals/LogicAnalyzerClient.cs
index 799a57b..342ff5d 100644
--- a/server/src/Peripherals/LogicAnalyzerClient.cs
+++ b/server/src/Peripherals/LogicAnalyzerClient.cs
@@ -67,6 +67,7 @@ static class AnalyzerAddr
public const UInt32 LOAD_NUM_ADDR = BASE + 0x0000_0002;
public const UInt32 PRE_LOAD_NUM_ADDR = BASE + 0x0000_0003;
public const UInt32 CAHNNEL_DIV_ADDR = BASE + 0x0000_0004;
+ public const UInt32 CLOCK_DIV_ADDR = BASE + 0x0000_0005;
public const UInt32 DMA1_START_WRITE_ADDR = DMA1_BASE + 0x0000_0012;
public const UInt32 DMA1_END_WRITE_ADDR = DMA1_BASE + 0x0000_0013;
public const UInt32 DMA1_CAPTURE_CTRL_ADDR = DMA1_BASE + 0x0000_0014;
@@ -138,6 +139,52 @@ public enum GlobalCaptureMode
NOR = 0b11
}
+///
+/// 逻辑分析仪采样时钟分频系数
+///
+public enum AnalyzerClockDiv
+{
+ ///
+ /// 1分频
+ ///
+ DIV1 = 0x0000_0000,
+
+ ///
+ /// 2分频
+ ///
+ DIV2 = 0x0000_0001,
+
+ ///
+ /// 4分频
+ ///
+ DIV4 = 0x0000_0002,
+
+ ///
+ /// 8分频
+ ///
+ DIV8 = 0x0000_0003,
+
+ ///
+ /// 16分频
+ ///
+ DIV16 = 0x0000_0004,
+
+ ///
+ /// 32分频
+ ///
+ DIV32 = 0x0000_0005,
+
+ ///
+ /// 64分频
+ ///
+ DIV64 = 0x0000_0006,
+
+ ///
+ /// 128分频
+ ///
+ DIV128 = 0x0000_0007
+}
+
///
/// 信号M的操作符枚举
///
@@ -387,13 +434,14 @@ public class Analyzer
}
///
- /// 设置逻辑分析仪的深度、预采样深度、有效通道
+ /// 设置逻辑分析仪的深度、预采样深度、有效通道、分频系数
///
/// 深度
/// 预采样深度
/// 有效通道(0-[1],1-[2],2-[4],3-[8],4-[16],5-[32])
+ /// 采样时钟分频系数
/// 操作结果,成功返回true,否则返回异常信息
- public async ValueTask> SetCaptureParams(int capture_length, int pre_capture_length, AnalyzerChannelDiv channel_div)
+ public async ValueTask> SetCaptureParams(int capture_length, int pre_capture_length, AnalyzerChannelDiv channel_div, AnalyzerClockDiv clock_div)
{
if (capture_length == 0) capture_length = 1;
if (pre_capture_length == 0) pre_capture_length = 1;
@@ -462,6 +510,19 @@ public class Analyzer
return new(new Exception("Failed to set CAHNNEL_DIV_ADDR"));
}
}
+ {
+ var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, AnalyzerAddr.CLOCK_DIV_ADDR, (UInt32)clock_div, this.timeout);
+ if (!ret.IsSuccessful)
+ {
+ logger.Error($"Failed to set CLOCK_DIV_ADDR: {ret.Error}");
+ return new(ret.Error);
+ }
+ if (!ret.Value)
+ {
+ logger.Error("WriteAddr to CLOCK_DIV_ADDR returned false");
+ return new(new Exception("Failed to set CLOCK_DIV_ADDR"));
+ }
+ }
return true;
}
diff --git a/server/src/Services/HttpHdmiVideoStreamService.cs b/server/src/Services/HttpHdmiVideoStreamService.cs
index d1fbbdf..e00879a 100644
--- a/server/src/Services/HttpHdmiVideoStreamService.cs
+++ b/server/src/Services/HttpHdmiVideoStreamService.cs
@@ -16,7 +16,7 @@ public class HttpHdmiVideoStreamService : BackgroundService
{
private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private HttpListener? _httpListener;
- private readonly int _serverPort = 4322;
+ private readonly int _serverPort = 6666;
private readonly ConcurrentDictionary _hdmiInDict = new();
private bool _isEnabled = true;
diff --git a/src/APIClient.ts b/src/APIClient.ts
index 474a4b2..e48ad14 100644
--- a/src/APIClient.ts
+++ b/src/APIClient.ts
@@ -3948,9 +3948,10 @@ export class LogicAnalyzerClient {
* @param capture_length (optional) 深度
* @param pre_capture_length (optional) 预采样深度
* @param channel_div (optional) 有效通道(0-[1],1-[2],2-[4],3-[8],4-[16],5-[32])
+ * @param clock_div (optional) 采样时钟分频系数
* @return 操作结果
*/
- setCaptureParams(capture_length: number | undefined, pre_capture_length: number | undefined, channel_div: AnalyzerChannelDiv | undefined, cancelToken?: CancelToken): Promise {
+ setCaptureParams(capture_length: number | undefined, pre_capture_length: number | undefined, channel_div: AnalyzerChannelDiv | undefined, clock_div: AnalyzerClockDiv | undefined, cancelToken?: CancelToken): Promise {
let url_ = this.baseUrl + "/api/LogicAnalyzer/SetCaptureParams?";
if (capture_length === null)
throw new Error("The parameter 'capture_length' cannot be null.");
@@ -3964,6 +3965,10 @@ export class LogicAnalyzerClient {
throw new Error("The parameter 'channel_div' cannot be null.");
else if (channel_div !== undefined)
url_ += "channel_div=" + encodeURIComponent("" + channel_div) + "&";
+ if (clock_div === null)
+ throw new Error("The parameter 'clock_div' cannot be null.");
+ else if (clock_div !== undefined)
+ url_ += "clock_div=" + encodeURIComponent("" + clock_div) + "&";
url_ = url_.replace(/[?&]$/, "");
let options_: AxiosRequestConfig = {
@@ -8233,6 +8238,18 @@ export enum AnalyzerChannelDiv {
XXXII = 5,
}
+/** 逻辑分析仪采样时钟分频系数 */
+export enum AnalyzerClockDiv {
+ DIV1 = 0,
+ DIV2 = 1,
+ DIV4 = 2,
+ DIV8 = 3,
+ DIV16 = 4,
+ DIV32 = 5,
+ DIV64 = 6,
+ DIV128 = 7,
+}
+
/** 捕获配置 */
export class CaptureConfig implements ICaptureConfig {
/** 全局触发模式 */
@@ -8243,6 +8260,8 @@ export class CaptureConfig implements ICaptureConfig {
preCaptureLength!: number;
/** 有效通道 */
channelDiv!: AnalyzerChannelDiv;
+ /** 时钟分频系数 */
+ clockDiv!: AnalyzerClockDiv;
/** 信号触发配置列表 */
signalConfigs!: SignalTriggerConfig[];
@@ -8264,6 +8283,7 @@ export class CaptureConfig implements ICaptureConfig {
this.captureLength = _data["captureLength"];
this.preCaptureLength = _data["preCaptureLength"];
this.channelDiv = _data["channelDiv"];
+ this.clockDiv = _data["clockDiv"];
if (Array.isArray(_data["signalConfigs"])) {
this.signalConfigs = [] as any;
for (let item of _data["signalConfigs"])
@@ -8285,6 +8305,7 @@ export class CaptureConfig implements ICaptureConfig {
data["captureLength"] = this.captureLength;
data["preCaptureLength"] = this.preCaptureLength;
data["channelDiv"] = this.channelDiv;
+ data["clockDiv"] = this.clockDiv;
if (Array.isArray(this.signalConfigs)) {
data["signalConfigs"] = [];
for (let item of this.signalConfigs)
@@ -8304,6 +8325,8 @@ export interface ICaptureConfig {
preCaptureLength: number;
/** 有效通道 */
channelDiv: AnalyzerChannelDiv;
+ /** 时钟分频系数 */
+ clockDiv: AnalyzerClockDiv;
/** 信号触发配置列表 */
signalConfigs: SignalTriggerConfig[];
}
diff --git a/src/components/LogicAnalyzer/LogicAnalyzerManager.ts b/src/components/LogicAnalyzer/LogicAnalyzerManager.ts
index baec10d..c830a7a 100644
--- a/src/components/LogicAnalyzer/LogicAnalyzerManager.ts
+++ b/src/components/LogicAnalyzer/LogicAnalyzerManager.ts
@@ -10,6 +10,7 @@ import {
SignalTriggerConfig,
SignalValue,
AnalyzerChannelDiv,
+ AnalyzerClockDiv,
} from "@/APIClient";
import { AuthManager } from "@/utils/AuthManager";
import { useAlertStore } from "@/components/Alert";
@@ -30,16 +31,8 @@ export type Channel = {
// 全局模式选项
const globalModes = [
- {
- value: GlobalCaptureMode.AND,
- label: "AND",
- description: "所有条件都满足时触发",
- },
- {
- value: GlobalCaptureMode.OR,
- label: "OR",
- description: "任一条件满足时触发",
- },
+ {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的非" },
];
@@ -76,12 +69,23 @@ const channelDivOptions = [
{ 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 = 0; // 最小预捕获深度 0
+const PRE_CAPTURE_LENGTH_MIN = 2; // 最小预捕获深度 2
// 默认颜色数组
const defaultColors = [
@@ -95,9 +99,8 @@ const defaultColors = [
"#8C33FF",
];
-// 添加逻辑分析仪频率常量
-const LOGIC_ANALYZER_FREQUENCY = 125_000_000; // 125MHz
-const SAMPLE_PERIOD_NS = 1_000_000_000 / LOGIC_ANALYZER_FREQUENCY; // 采样周期,单位:纳秒
+// 添加逻辑分析仪基础频率常量
+const BASE_LOGIC_ANALYZER_FREQUENCY = 120_000_000; // 120MHz基础频率
const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
() => {
@@ -112,6 +115,7 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
const currentChannelDiv = ref(8); // 默认启用8个通道
const captureLength = ref(CAPTURE_LENGTH_MIN); // 捕获深度,默认为最小值
const preCaptureLength = ref(PRE_CAPTURE_LENGTH_MIN); // 预捕获深度,默认0
+ const currentclockDiv = ref(AnalyzerClockDiv.DIV1); // 默认时钟分频为1
const isApplying = ref(false);
const isCapturing = ref(false); // 添加捕获状态标识
@@ -152,6 +156,17 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
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) {
@@ -252,9 +267,16 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
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) => {
@@ -285,7 +307,7 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
// 根据当前通道数量解析数据
const channelCount = currentChannelDiv.value;
- const timeStepNs = SAMPLE_PERIOD_NS;
+ const timeStepNs = currentSamplePeriodNs.value;
let sampleCount: number;
let x: number[];
@@ -528,6 +550,7 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
channelDiv: getChannelDivEnum(currentChannelDiv.value),
captureLength: captureLength.value,
preCaptureLength: preCaptureLength.value,
+ clockDiv: currentclockDiv.value,
signalConfigs: allSignals,
});
@@ -666,13 +689,13 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
// 添加生成测试数据的方法
const generateTestData = () => {
- const sampleRate = LOGIC_ANALYZER_FREQUENCY; // 使用实际的逻辑分析仪频率
+ const sampleRate = currentSampleFrequency.value; // 使用当前设置的采样频率
const duration = 0.001; // 1ms的数据
const points = Math.floor(sampleRate * duration);
const x = Array.from(
{ length: points },
- (_, i) => (i * SAMPLE_PERIOD_NS) / 1000, // 时间轴,单位:微秒
+ (_, i) => (i * currentSamplePeriodNs.value) / 1000, // 时间轴,单位:微秒
);
// Generate 8 channels with different digital patterns
@@ -745,6 +768,7 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
currentChannelDiv, // 导出当前通道组状态
captureLength, // 导出捕获深度
preCaptureLength, // 导出预捕获深度
+ currentclockDiv, // 导出当前采样频率状态
isApplying,
isCapturing, // 导出捕获状态
isOperationInProgress, // 导出操作进行状态
@@ -753,12 +777,15 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
enabledChannelCount,
channelNames,
enabledChannels,
+ currentSampleFrequency, // 导出当前采样频率
+ currentSamplePeriodNs, // 导出当前采样周期
// 选项数据
globalModes,
operators,
signalValues,
channelDivOptions, // 导出通道组选项
+ ClockDivOptions, // 导出采样频率选项
// 捕获深度常量和验证
CAPTURE_LENGTH_MIN,
@@ -772,6 +799,7 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
// 触发设置方法
setChannelDiv, // 导出设置通道组方法
setGlobalMode,
+ setClockDiv, // 导出设置采样频率方法
resetConfiguration,
setLogicData,
startCapture,
diff --git a/src/components/LogicAnalyzer/TriggerSettings.vue b/src/components/LogicAnalyzer/TriggerSettings.vue
index 7f6b577..fc73036 100644
--- a/src/components/LogicAnalyzer/TriggerSettings.vue
+++ b/src/components/LogicAnalyzer/TriggerSettings.vue
@@ -81,6 +81,44 @@
{{ currentChannelDivDescription }}
+
+
+
+
+
+
+
+
+ {{ option.label }}
+
+
+
+
+ {{ currentClockDivDescription }}
+
+