feat: 添加示波器前后端
This commit is contained in:
parent
ba79a2093b
commit
e4a1c34a6c
|
@ -28,6 +28,7 @@ declare module 'vue' {
|
||||||
MotherBoard: typeof import('./src/components/equipments/MotherBoard.vue')['default']
|
MotherBoard: typeof import('./src/components/equipments/MotherBoard.vue')['default']
|
||||||
MotherBoardCaps: typeof import('./src/components/equipments/MotherBoardCaps.vue')['default']
|
MotherBoardCaps: typeof import('./src/components/equipments/MotherBoardCaps.vue')['default']
|
||||||
Navbar: typeof import('./src/components/Navbar.vue')['default']
|
Navbar: typeof import('./src/components/Navbar.vue')['default']
|
||||||
|
OscilloscopeWaveformDisplay: typeof import('./src/components/Oscilloscope/OscilloscopeWaveformDisplay.vue')['default']
|
||||||
PG2L100H_FBG676: typeof import('./src/components/equipments/PG2L100H_FBG676.vue')['default']
|
PG2L100H_FBG676: typeof import('./src/components/equipments/PG2L100H_FBG676.vue')['default']
|
||||||
Pin: typeof import('./src/components/equipments/Pin.vue')['default']
|
Pin: typeof import('./src/components/equipments/Pin.vue')['default']
|
||||||
PopButton: typeof import('./src/components/PopButton.vue')['default']
|
PopButton: typeof import('./src/components/PopButton.vue')['default']
|
||||||
|
@ -48,7 +49,7 @@ declare module 'vue' {
|
||||||
TriggerSettings: typeof import('./src/components/LogicAnalyzer/TriggerSettings.vue')['default']
|
TriggerSettings: typeof import('./src/components/LogicAnalyzer/TriggerSettings.vue')['default']
|
||||||
TutorialCarousel: typeof import('./src/components/TutorialCarousel.vue')['default']
|
TutorialCarousel: typeof import('./src/components/TutorialCarousel.vue')['default']
|
||||||
UploadCard: typeof import('./src/components/UploadCard.vue')['default']
|
UploadCard: typeof import('./src/components/UploadCard.vue')['default']
|
||||||
WaveformDisplay: typeof import('./src/components/Oscilloscope/WaveformDisplay.vue')['default']
|
WaveformDisplay: typeof import('./src/components/WaveformDisplay/WaveformDisplay.vue')['default']
|
||||||
Wire: typeof import('./src/components/equipments/Wire.vue')['default']
|
Wire: typeof import('./src/components/equipments/Wire.vue')['default']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,494 @@
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Cors;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Peripherals.OscilloscopeClient;
|
||||||
|
|
||||||
|
namespace server.Controllers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 示波器API控制器 - 普通用户权限
|
||||||
|
/// </summary>
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[Authorize(Roles = "User")]
|
||||||
|
public class OscilloscopeApiController : ControllerBase
|
||||||
|
{
|
||||||
|
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 示波器完整配置
|
||||||
|
/// </summary>
|
||||||
|
public class OscilloscopeFullConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 是否启动捕获
|
||||||
|
/// </summary>
|
||||||
|
public bool CaptureEnabled { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 触发电平(0-255)
|
||||||
|
/// </summary>
|
||||||
|
public byte TriggerLevel { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 触发边沿(true为上升沿,false为下降沿)
|
||||||
|
/// </summary>
|
||||||
|
public bool TriggerRisingEdge { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 水平偏移量(0-1023)
|
||||||
|
/// </summary>
|
||||||
|
public ushort HorizontalShift { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 抽样率(0-1023)
|
||||||
|
/// </summary>
|
||||||
|
public ushort DecimationRate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否自动刷新RAM
|
||||||
|
/// </summary>
|
||||||
|
public bool AutoRefreshRAM { get; set; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 示波器状态和数据
|
||||||
|
/// </summary>
|
||||||
|
public class OscilloscopeDataResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// AD采样频率
|
||||||
|
/// </summary>
|
||||||
|
public uint ADFrequency { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// AD采样幅度
|
||||||
|
/// </summary>
|
||||||
|
public byte ADVpp { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// AD采样最大值
|
||||||
|
/// </summary>
|
||||||
|
public byte ADMax { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// AD采样最小值
|
||||||
|
/// </summary>
|
||||||
|
public byte ADMin { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 波形数据(Base64编码)
|
||||||
|
/// </summary>
|
||||||
|
public string WaveformData { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取示波器实例
|
||||||
|
/// </summary>
|
||||||
|
private Oscilloscope? GetOscilloscope()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var userName = User.Identity?.Name;
|
||||||
|
if (string.IsNullOrEmpty(userName))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
using var db = new Database.AppDataConnection();
|
||||||
|
var userRet = db.GetUserByName(userName);
|
||||||
|
if (!userRet.IsSuccessful || !userRet.Value.HasValue)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var user = userRet.Value.Value;
|
||||||
|
if (user.BoardID == Guid.Empty)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var boardRet = db.GetBoardByID(user.BoardID);
|
||||||
|
if (!boardRet.IsSuccessful || !boardRet.Value.HasValue)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var board = boardRet.Value.Value;
|
||||||
|
return new Oscilloscope(board.IpAddr, board.Port);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Error(ex, "获取示波器实例时发生异常");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化示波器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">示波器配置</param>
|
||||||
|
/// <returns>操作结果</returns>
|
||||||
|
[HttpPost("Initialize")]
|
||||||
|
[EnableCors("Users")]
|
||||||
|
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
|
public async Task<IActionResult> Initialize([FromBody] OscilloscopeFullConfig config)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (config == null)
|
||||||
|
return BadRequest("配置参数不能为空");
|
||||||
|
|
||||||
|
if (config.HorizontalShift > 1023)
|
||||||
|
return BadRequest("水平偏移量必须在0-1023之间");
|
||||||
|
|
||||||
|
if (config.DecimationRate > 1023)
|
||||||
|
return BadRequest("抽样率必须在0-1023之间");
|
||||||
|
|
||||||
|
var oscilloscope = GetOscilloscope();
|
||||||
|
if (oscilloscope == null)
|
||||||
|
return BadRequest("用户未绑定有效的实验板");
|
||||||
|
|
||||||
|
// 首先关闭捕获
|
||||||
|
var stopResult = await oscilloscope.SetCaptureEnable(false);
|
||||||
|
if (!stopResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"关闭捕获失败: {stopResult.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "关闭捕获失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置触发电平
|
||||||
|
var levelResult = await oscilloscope.SetTriggerLevel(config.TriggerLevel);
|
||||||
|
if (!levelResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"设置触发电平失败: {levelResult.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "设置触发电平失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置触发边沿
|
||||||
|
var edgeResult = await oscilloscope.SetTriggerEdge(config.TriggerRisingEdge);
|
||||||
|
if (!edgeResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"设置触发边沿失败: {edgeResult.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "设置触发边沿失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置水平偏移量
|
||||||
|
var shiftResult = await oscilloscope.SetHorizontalShift(config.HorizontalShift);
|
||||||
|
if (!shiftResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"设置水平偏移量失败: {shiftResult.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "设置水平偏移量失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置抽样率
|
||||||
|
var rateResult = await oscilloscope.SetDecimationRate(config.DecimationRate);
|
||||||
|
if (!rateResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"设置抽样率失败: {rateResult.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "设置抽样率失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刷新RAM
|
||||||
|
if (config.AutoRefreshRAM)
|
||||||
|
{
|
||||||
|
var refreshResult = await oscilloscope.RefreshRAM();
|
||||||
|
if (!refreshResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"刷新RAM失败: {refreshResult.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "刷新RAM失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置捕获开关
|
||||||
|
var captureResult = await oscilloscope.SetCaptureEnable(config.CaptureEnabled);
|
||||||
|
if (!captureResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"设置捕获开关失败: {captureResult.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "设置捕获开关失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Error(ex, "初始化示波器时发生异常");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "操作失败,请稍后重试");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动捕获
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>操作结果</returns>
|
||||||
|
[HttpPost("StartCapture")]
|
||||||
|
[EnableCors("Users")]
|
||||||
|
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
|
public async Task<IActionResult> StartCapture()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var oscilloscope = GetOscilloscope();
|
||||||
|
if (oscilloscope == null)
|
||||||
|
return BadRequest("用户未绑定有效的实验板");
|
||||||
|
|
||||||
|
var result = await oscilloscope.SetCaptureEnable(true);
|
||||||
|
if (!result.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"启动捕获失败: {result.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "启动捕获失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(result.Value);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Error(ex, "启动捕获时发生异常");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "操作失败,请稍后重试");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 停止捕获
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>操作结果</returns>
|
||||||
|
[HttpPost("StopCapture")]
|
||||||
|
[EnableCors("Users")]
|
||||||
|
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
|
public async Task<IActionResult> StopCapture()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var oscilloscope = GetOscilloscope();
|
||||||
|
if (oscilloscope == null)
|
||||||
|
return BadRequest("用户未绑定有效的实验板");
|
||||||
|
|
||||||
|
var result = await oscilloscope.SetCaptureEnable(false);
|
||||||
|
if (!result.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"停止捕获失败: {result.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "停止捕获失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(result.Value);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Error(ex, "停止捕获时发生异常");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "操作失败,请稍后重试");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取示波器数据和状态
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>示波器数据和状态信息</returns>
|
||||||
|
[HttpGet("GetData")]
|
||||||
|
[EnableCors("Users")]
|
||||||
|
[ProducesResponseType(typeof(OscilloscopeDataResponse), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
|
public async Task<IActionResult> GetData()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var oscilloscope = GetOscilloscope();
|
||||||
|
if (oscilloscope == null)
|
||||||
|
return BadRequest("用户未绑定有效的实验板");
|
||||||
|
|
||||||
|
// 并行获取所有数据
|
||||||
|
var freqTask = oscilloscope.GetADFrequency();
|
||||||
|
var vppTask = oscilloscope.GetADVpp();
|
||||||
|
var maxTask = oscilloscope.GetADMax();
|
||||||
|
var minTask = oscilloscope.GetADMin();
|
||||||
|
var waveformTask = oscilloscope.GetWaveformData();
|
||||||
|
|
||||||
|
await Task.WhenAll(freqTask.AsTask(), vppTask.AsTask(), maxTask.AsTask(),
|
||||||
|
minTask.AsTask(), waveformTask.AsTask());
|
||||||
|
|
||||||
|
var freqResult = await freqTask;
|
||||||
|
var vppResult = await vppTask;
|
||||||
|
var maxResult = await maxTask;
|
||||||
|
var minResult = await minTask;
|
||||||
|
var waveformResult = await waveformTask;
|
||||||
|
|
||||||
|
if (!freqResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"获取AD采样频率失败: {freqResult.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "获取AD采样频率失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vppResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"获取AD采样幅度失败: {vppResult.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "获取AD采样幅度失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!maxResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"获取AD采样最大值失败: {maxResult.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "获取AD采样最大值失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!minResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"获取AD采样最小值失败: {minResult.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "获取AD采样最小值失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!waveformResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"获取波形数据失败: {waveformResult.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "获取波形数据失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = new OscilloscopeDataResponse
|
||||||
|
{
|
||||||
|
ADFrequency = freqResult.Value,
|
||||||
|
ADVpp = vppResult.Value,
|
||||||
|
ADMax = maxResult.Value,
|
||||||
|
ADMin = minResult.Value,
|
||||||
|
WaveformData = Convert.ToBase64String(waveformResult.Value)
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(response);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Error(ex, "获取示波器数据时发生异常");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "操作失败,请稍后重试");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新触发参数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="level">触发电平(0-255)</param>
|
||||||
|
/// <param name="risingEdge">触发边沿(true为上升沿,false为下降沿)</param>
|
||||||
|
/// <returns>操作结果</returns>
|
||||||
|
[HttpPost("UpdateTrigger")]
|
||||||
|
[EnableCors("Users")]
|
||||||
|
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
|
public async Task<IActionResult> UpdateTrigger(byte level, bool risingEdge)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var oscilloscope = GetOscilloscope();
|
||||||
|
if (oscilloscope == null)
|
||||||
|
return BadRequest("用户未绑定有效的实验板");
|
||||||
|
|
||||||
|
// 设置触发电平
|
||||||
|
var levelResult = await oscilloscope.SetTriggerLevel(level);
|
||||||
|
if (!levelResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"设置触发电平失败: {levelResult.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "设置触发电平失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置触发边沿
|
||||||
|
var edgeResult = await oscilloscope.SetTriggerEdge(risingEdge);
|
||||||
|
if (!edgeResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"设置触发边沿失败: {edgeResult.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "设置触发边沿失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Error(ex, "更新触发参数时发生异常");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "操作失败,请稍后重试");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新采样参数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="horizontalShift">水平偏移量(0-1023)</param>
|
||||||
|
/// <param name="decimationRate">抽样率(0-1023)</param>
|
||||||
|
/// <returns>操作结果</returns>
|
||||||
|
[HttpPost("UpdateSampling")]
|
||||||
|
[EnableCors("Users")]
|
||||||
|
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
|
public async Task<IActionResult> UpdateSampling(ushort horizontalShift, ushort decimationRate)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (horizontalShift > 1023)
|
||||||
|
return BadRequest("水平偏移量必须在0-1023之间");
|
||||||
|
|
||||||
|
if (decimationRate > 1023)
|
||||||
|
return BadRequest("抽样率必须在0-1023之间");
|
||||||
|
|
||||||
|
var oscilloscope = GetOscilloscope();
|
||||||
|
if (oscilloscope == null)
|
||||||
|
return BadRequest("用户未绑定有效的实验板");
|
||||||
|
|
||||||
|
// 设置水平偏移量
|
||||||
|
var shiftResult = await oscilloscope.SetHorizontalShift(horizontalShift);
|
||||||
|
if (!shiftResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"设置水平偏移量失败: {shiftResult.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "设置水平偏移量失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置抽样率
|
||||||
|
var rateResult = await oscilloscope.SetDecimationRate(decimationRate);
|
||||||
|
if (!rateResult.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"设置抽样率失败: {rateResult.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "设置抽样率失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Error(ex, "更新采样参数时发生异常");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "操作失败,请稍后重试");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 手动刷新RAM
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>操作结果</returns>
|
||||||
|
[HttpPost("RefreshRAM")]
|
||||||
|
[EnableCors("Users")]
|
||||||
|
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
|
public async Task<IActionResult> RefreshRAM()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var oscilloscope = GetOscilloscope();
|
||||||
|
if (oscilloscope == null)
|
||||||
|
return BadRequest("用户未绑定有效的实验板");
|
||||||
|
|
||||||
|
var result = await oscilloscope.RefreshRAM();
|
||||||
|
if (!result.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"刷新RAM失败: {result.Error}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "刷新RAM失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(result.Value);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Error(ex, "刷新RAM时发生异常");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError, "操作失败,请稍后重试");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,68 @@
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using Common;
|
||||||
using DotNext;
|
using DotNext;
|
||||||
|
|
||||||
namespace Peripherals.OscilloscopeClient;
|
namespace Peripherals.OscilloscopeClient;
|
||||||
|
|
||||||
static class OscilloscopeAddr
|
static class OscilloscopeAddr
|
||||||
{
|
{
|
||||||
public const UInt32 Base = 0x0000_0000;
|
const UInt32 BASE = 0x8000_0000;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 0x0000_0000:R/W[0] wave_run 启动捕获/关闭
|
||||||
|
/// </summary>
|
||||||
|
public const UInt32 START_CAPTURE = BASE + 0x0000_0000;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 0x0000_0001: R/W[7:0] trig_level 触发电平
|
||||||
|
/// </summary>
|
||||||
|
public const UInt32 TRIG_LEVEL = BASE + 0x0000_0001;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 0x0000_0002:R/W[0] trig_edge 触发边沿,0-下降沿,1-上升沿
|
||||||
|
/// </summary>
|
||||||
|
public const UInt32 TRIG_EDGE = BASE + 0x0000_0002;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 0x0000_0003: R/W[9:0] h shift 水平偏移量
|
||||||
|
/// </summary>
|
||||||
|
public const UInt32 H_SHIFT = BASE + 0x0000_0003;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 0x0000_0004: R/W[9:0] deci rate 抽样率,0—1023
|
||||||
|
/// </summary>
|
||||||
|
public const UInt32 DECI_RATE = BASE + 0x0000_0004;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 0x0000_0005:R/W[0] ram refresh RAM刷新
|
||||||
|
/// </summary>
|
||||||
|
public const UInt32 RAM_FRESH = BASE + 0x0000_0005;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 0x0000 0006:R[19: 0] ad_freq AD采样频率
|
||||||
|
/// </summary>
|
||||||
|
public const UInt32 AD_FREQ = BASE + 0x0000_0006;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ox0000_0007: R[7:0] ad_vpp AD采样幅度
|
||||||
|
/// </summary>
|
||||||
|
public const UInt32 AD_VPP = BASE + 0x0000_0007;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 0x0000_0008: R[7:0] ad max AD采样最大值
|
||||||
|
/// </summary>
|
||||||
|
public const UInt32 AD_MAX = BASE + 0x0000_0008;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 0x0000_0009: R[7:0] ad_min AD采样最小值
|
||||||
|
/// </summary>
|
||||||
|
public const UInt32 AD_MIN = BASE + 0x0000_0009;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 0x0000_1000-0x0000_13FF:R[7:0] wave_rd_data 共1024个字节
|
||||||
|
/// </summary>
|
||||||
|
public const UInt32 RD_DATA_ADDR = BASE + 0x0000_1000;
|
||||||
|
public const UInt32 RD_DATA_LENGTH = 0x0000_0400;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Oscilloscope
|
class Oscilloscope
|
||||||
|
@ -13,6 +70,7 @@ class Oscilloscope
|
||||||
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
readonly int timeout = 2000;
|
readonly int timeout = 2000;
|
||||||
|
readonly int taskID = 1;
|
||||||
|
|
||||||
readonly int port;
|
readonly int port;
|
||||||
readonly string address;
|
readonly string address;
|
||||||
|
@ -33,4 +91,258 @@ class Oscilloscope
|
||||||
this.ep = new IPEndPoint(IPAddress.Parse(address), port);
|
this.ep = new IPEndPoint(IPAddress.Parse(address), port);
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 控制示波器的捕获开关
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enable">是否启动捕获</param>
|
||||||
|
/// <returns>操作结果,成功返回true,否则返回异常信息</returns>
|
||||||
|
public async ValueTask<Result<bool>> SetCaptureEnable(bool enable)
|
||||||
|
{
|
||||||
|
UInt32 value = enable ? 1u : 0u;
|
||||||
|
var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, OscilloscopeAddr.START_CAPTURE, value, this.timeout);
|
||||||
|
if (!ret.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"Failed to set capture enable: {ret.Error}");
|
||||||
|
return new(ret.Error);
|
||||||
|
}
|
||||||
|
if (!ret.Value)
|
||||||
|
{
|
||||||
|
logger.Error("WriteAddr to START_CAPTURE returned false");
|
||||||
|
return new(new Exception("Failed to set capture enable"));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置触发电平
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="level">触发电平值(0-255)</param>
|
||||||
|
/// <returns>操作结果,成功返回true,否则返回异常信息</returns>
|
||||||
|
public async ValueTask<Result<bool>> SetTriggerLevel(byte level)
|
||||||
|
{
|
||||||
|
var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, OscilloscopeAddr.TRIG_LEVEL, level, this.timeout);
|
||||||
|
if (!ret.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"Failed to set trigger level: {ret.Error}");
|
||||||
|
return new(ret.Error);
|
||||||
|
}
|
||||||
|
if (!ret.Value)
|
||||||
|
{
|
||||||
|
logger.Error("WriteAddr to TRIG_LEVEL returned false");
|
||||||
|
return new(new Exception("Failed to set trigger level"));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置触发边沿
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="risingEdge">true为上升沿,false为下降沿</param>
|
||||||
|
/// <returns>操作结果,成功返回true,否则返回异常信息</returns>
|
||||||
|
public async ValueTask<Result<bool>> SetTriggerEdge(bool risingEdge)
|
||||||
|
{
|
||||||
|
UInt32 value = risingEdge ? 1u : 0u;
|
||||||
|
var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, OscilloscopeAddr.TRIG_EDGE, value, this.timeout);
|
||||||
|
if (!ret.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"Failed to set trigger edge: {ret.Error}");
|
||||||
|
return new(ret.Error);
|
||||||
|
}
|
||||||
|
if (!ret.Value)
|
||||||
|
{
|
||||||
|
logger.Error("WriteAddr to TRIG_EDGE returned false");
|
||||||
|
return new(new Exception("Failed to set trigger edge"));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置水平偏移量
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="shift">水平偏移量值(0-1023)</param>
|
||||||
|
/// <returns>操作结果,成功返回true,否则返回异常信息</returns>
|
||||||
|
public async ValueTask<Result<bool>> SetHorizontalShift(UInt16 shift)
|
||||||
|
{
|
||||||
|
if (shift > 1023)
|
||||||
|
return new(new ArgumentException("Horizontal shift must be 0-1023", nameof(shift)));
|
||||||
|
|
||||||
|
var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, OscilloscopeAddr.H_SHIFT, shift, this.timeout);
|
||||||
|
if (!ret.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"Failed to set horizontal shift: {ret.Error}");
|
||||||
|
return new(ret.Error);
|
||||||
|
}
|
||||||
|
if (!ret.Value)
|
||||||
|
{
|
||||||
|
logger.Error("WriteAddr to H_SHIFT returned false");
|
||||||
|
return new(new Exception("Failed to set horizontal shift"));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置抽样率
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rate">抽样率值(0-1023)</param>
|
||||||
|
/// <returns>操作结果,成功返回true,否则返回异常信息</returns>
|
||||||
|
public async ValueTask<Result<bool>> SetDecimationRate(UInt16 rate)
|
||||||
|
{
|
||||||
|
if (rate > 1023)
|
||||||
|
return new(new ArgumentException("Decimation rate must be 0-1023", nameof(rate)));
|
||||||
|
|
||||||
|
var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, OscilloscopeAddr.DECI_RATE, rate, this.timeout);
|
||||||
|
if (!ret.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"Failed to set decimation rate: {ret.Error}");
|
||||||
|
return new(ret.Error);
|
||||||
|
}
|
||||||
|
if (!ret.Value)
|
||||||
|
{
|
||||||
|
logger.Error("WriteAddr to DECI_RATE returned false");
|
||||||
|
return new(new Exception("Failed to set decimation rate"));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 刷新RAM
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>操作结果,成功返回true,否则返回异常信息</returns>
|
||||||
|
public async ValueTask<Result<bool>> RefreshRAM()
|
||||||
|
{
|
||||||
|
var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, OscilloscopeAddr.RAM_FRESH, 1u, this.timeout);
|
||||||
|
if (!ret.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"Failed to refresh RAM: {ret.Error}");
|
||||||
|
return new(ret.Error);
|
||||||
|
}
|
||||||
|
if (!ret.Value)
|
||||||
|
{
|
||||||
|
logger.Error("WriteAddr to RAM_FRESH returned false");
|
||||||
|
return new(new Exception("Failed to refresh RAM"));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取AD采样频率
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>操作结果,成功返回采样频率值,否则返回异常信息</returns>
|
||||||
|
public async ValueTask<Result<UInt32>> GetADFrequency()
|
||||||
|
{
|
||||||
|
var ret = await UDPClientPool.ReadAddr(this.ep, this.taskID, OscilloscopeAddr.AD_FREQ, this.timeout);
|
||||||
|
if (!ret.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"Failed to read AD frequency: {ret.Error}");
|
||||||
|
return new(ret.Error);
|
||||||
|
}
|
||||||
|
if (ret.Value.Options.Data == null || ret.Value.Options.Data.Length < 4)
|
||||||
|
{
|
||||||
|
logger.Error("ReadAddr returned invalid data for AD frequency");
|
||||||
|
return new(new Exception("Failed to read AD frequency"));
|
||||||
|
}
|
||||||
|
UInt32 freq = Number.BytesToUInt32(ret.Value.Options.Data).Value;
|
||||||
|
// 取低20位 [19:0]
|
||||||
|
freq &= 0xFFFFF;
|
||||||
|
return freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取AD采样幅度
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>操作结果,成功返回采样幅度值,否则返回异常信息</returns>
|
||||||
|
public async ValueTask<Result<byte>> GetADVpp()
|
||||||
|
{
|
||||||
|
var ret = await UDPClientPool.ReadAddr(this.ep, this.taskID, OscilloscopeAddr.AD_VPP, this.timeout);
|
||||||
|
if (!ret.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"Failed to read AD VPP: {ret.Error}");
|
||||||
|
return new(ret.Error);
|
||||||
|
}
|
||||||
|
if (ret.Value.Options.Data == null || ret.Value.Options.Data.Length < 1)
|
||||||
|
{
|
||||||
|
logger.Error("ReadAddr returned invalid data for AD VPP");
|
||||||
|
return new(new Exception("Failed to read AD VPP"));
|
||||||
|
}
|
||||||
|
return ret.Value.Options.Data[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取AD采样最大值
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>操作结果,成功返回采样最大值,否则返回异常信息</returns>
|
||||||
|
public async ValueTask<Result<byte>> GetADMax()
|
||||||
|
{
|
||||||
|
var ret = await UDPClientPool.ReadAddr(this.ep, this.taskID, OscilloscopeAddr.AD_MAX, this.timeout);
|
||||||
|
if (!ret.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"Failed to read AD max: {ret.Error}");
|
||||||
|
return new(ret.Error);
|
||||||
|
}
|
||||||
|
if (ret.Value.Options.Data == null || ret.Value.Options.Data.Length < 1)
|
||||||
|
{
|
||||||
|
logger.Error("ReadAddr returned invalid data for AD max");
|
||||||
|
return new(new Exception("Failed to read AD max"));
|
||||||
|
}
|
||||||
|
return ret.Value.Options.Data[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取AD采样最小值
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>操作结果,成功返回采样最小值,否则返回异常信息</returns>
|
||||||
|
public async ValueTask<Result<byte>> GetADMin()
|
||||||
|
{
|
||||||
|
var ret = await UDPClientPool.ReadAddr(this.ep, this.taskID, OscilloscopeAddr.AD_MIN, this.timeout);
|
||||||
|
if (!ret.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"Failed to read AD min: {ret.Error}");
|
||||||
|
return new(ret.Error);
|
||||||
|
}
|
||||||
|
if (ret.Value.Options.Data == null || ret.Value.Options.Data.Length < 1)
|
||||||
|
{
|
||||||
|
logger.Error("ReadAddr returned invalid data for AD min");
|
||||||
|
return new(new Exception("Failed to read AD min"));
|
||||||
|
}
|
||||||
|
return ret.Value.Options.Data[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取波形采样数据
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>操作结果,成功返回采样数据数组,否则返回异常信息</returns>
|
||||||
|
public async ValueTask<Result<byte[]>> GetWaveformData()
|
||||||
|
{
|
||||||
|
var ret = await UDPClientPool.ReadAddr4BytesAsync(
|
||||||
|
this.ep,
|
||||||
|
this.taskID,
|
||||||
|
OscilloscopeAddr.RD_DATA_ADDR,
|
||||||
|
(int)OscilloscopeAddr.RD_DATA_LENGTH / 32,
|
||||||
|
this.timeout
|
||||||
|
);
|
||||||
|
if (!ret.IsSuccessful)
|
||||||
|
{
|
||||||
|
logger.Error($"Failed to read waveform data: {ret.Error}");
|
||||||
|
return new(ret.Error);
|
||||||
|
}
|
||||||
|
var data = ret.Value;
|
||||||
|
if (data == null || data.Length != OscilloscopeAddr.RD_DATA_LENGTH)
|
||||||
|
{
|
||||||
|
logger.Error($"Waveform data length mismatch: {data?.Length}");
|
||||||
|
return new(new Exception("Waveform data length mismatch"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理波形数据:从每4个字节中提取第4个字节(索引3)作为有效数据
|
||||||
|
// 数据格式:低八位有效,即[4*i + 3]才是有效数据
|
||||||
|
int sampleCount = data.Length / 4;
|
||||||
|
byte[] waveformData = new byte[sampleCount];
|
||||||
|
|
||||||
|
for (int i = 0; i < sampleCount; i++)
|
||||||
|
{
|
||||||
|
waveformData[i] = data[4 * i + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
return waveformData;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
631
src/APIClient.ts
631
src/APIClient.ts
|
@ -3170,6 +3170,61 @@ export class NetConfigClient {
|
||||||
return Promise.resolve<boolean>(null as any);
|
return Promise.resolve<boolean>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置板卡MAC地址
|
||||||
|
* @param boardMac (optional) 板卡MAC地址(格式:AA:BB:CC:DD:EE:FF)
|
||||||
|
* @return 操作结果
|
||||||
|
*/
|
||||||
|
setBoardMAC(boardMac: string | undefined): Promise<boolean> {
|
||||||
|
let url_ = this.baseUrl + "/api/NetConfig/SetBoardMAC?";
|
||||||
|
if (boardMac === null)
|
||||||
|
throw new Error("The parameter 'boardMac' cannot be null.");
|
||||||
|
else if (boardMac !== undefined)
|
||||||
|
url_ += "boardMac=" + encodeURIComponent("" + boardMac) + "&";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processSetBoardMAC(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processSetBoardMAC(response: Response): Promise<boolean> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result200 = resultData200 !== undefined ? resultData200 : <any>null;
|
||||||
|
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status === 400) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result400: any = null;
|
||||||
|
let resultData400 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result400 = ProblemDetails.fromJS(resultData400);
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers, result400);
|
||||||
|
});
|
||||||
|
} else if (status === 500) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<boolean>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置主机MAC地址
|
* 设置主机MAC地址
|
||||||
* @param hostMac (optional) 主机MAC地址(格式:AA:BB:CC:DD:EE:FF)
|
* @param hostMac (optional) 主机MAC地址(格式:AA:BB:CC:DD:EE:FF)
|
||||||
|
@ -3319,31 +3374,81 @@ export class NetConfigClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置板卡MAC地址
|
* 获取本机网络信息
|
||||||
* @param boardMac (optional) 板卡MAC地址(格式:AA:BB:CC:DD:EE:FF)
|
* @return 本机网络信息
|
||||||
* @return 操作结果
|
|
||||||
*/
|
*/
|
||||||
setBoardMAC(boardMac: string | undefined): Promise<boolean> {
|
getLocalNetworkInfo(): Promise<any> {
|
||||||
let url_ = this.baseUrl + "/api/NetConfig/SetBoardMAC?";
|
let url_ = this.baseUrl + "/api/NetConfig/GetLocalNetworkInfo";
|
||||||
if (boardMac === null)
|
|
||||||
throw new Error("The parameter 'boardMac' cannot be null.");
|
|
||||||
else if (boardMac !== undefined)
|
|
||||||
url_ += "boardMac=" + encodeURIComponent("" + boardMac) + "&";
|
|
||||||
url_ = url_.replace(/[?&]$/, "");
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
let options_: RequestInit = {
|
let options_: RequestInit = {
|
||||||
method: "POST",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Accept": "application/json"
|
"Accept": "application/json"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.http.fetch(url_, options_).then((_response: Response) => {
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
return this.processSetBoardMAC(_response);
|
return this.processGetLocalNetworkInfo(_response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected processSetBoardMAC(response: Response): Promise<boolean> {
|
protected processGetLocalNetworkInfo(response: Response): Promise<any> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result200 = resultData200 !== undefined ? resultData200 : <any>null;
|
||||||
|
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<any>(null as any);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class OscilloscopeApiClient {
|
||||||
|
private http: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> };
|
||||||
|
private baseUrl: string;
|
||||||
|
protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined;
|
||||||
|
|
||||||
|
constructor(baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
|
||||||
|
this.http = http ? http : window as any;
|
||||||
|
this.baseUrl = baseUrl ?? "http://localhost:5000";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化示波器
|
||||||
|
* @param config 示波器配置
|
||||||
|
* @return 操作结果
|
||||||
|
*/
|
||||||
|
initialize(config: OscilloscopeFullConfig): Promise<boolean> {
|
||||||
|
let url_ = this.baseUrl + "/api/OscilloscopeApi/Initialize";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
const content_ = JSON.stringify(config);
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
body: content_,
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processInitialize(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processInitialize(response: Response): Promise<boolean> {
|
||||||
const status = response.status;
|
const status = response.status;
|
||||||
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
if (status === 200) {
|
if (status === 200) {
|
||||||
|
@ -3365,6 +3470,374 @@ export class NetConfigClient {
|
||||||
return response.text().then((_responseText) => {
|
return response.text().then((_responseText) => {
|
||||||
return throwException("A server side error occurred.", status, _responseText, _headers);
|
return throwException("A server side error occurred.", status, _responseText, _headers);
|
||||||
});
|
});
|
||||||
|
} else if (status === 401) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result401: any = null;
|
||||||
|
let resultData401 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result401 = ProblemDetails.fromJS(resultData401);
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers, result401);
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<boolean>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动捕获
|
||||||
|
* @return 操作结果
|
||||||
|
*/
|
||||||
|
startCapture(): Promise<boolean> {
|
||||||
|
let url_ = this.baseUrl + "/api/OscilloscopeApi/StartCapture";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processStartCapture(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processStartCapture(response: Response): Promise<boolean> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result200 = resultData200 !== undefined ? resultData200 : <any>null;
|
||||||
|
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status === 400) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result400: any = null;
|
||||||
|
let resultData400 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result400 = ProblemDetails.fromJS(resultData400);
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers, result400);
|
||||||
|
});
|
||||||
|
} else if (status === 500) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
} else if (status === 401) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result401: any = null;
|
||||||
|
let resultData401 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result401 = ProblemDetails.fromJS(resultData401);
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers, result401);
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<boolean>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止捕获
|
||||||
|
* @return 操作结果
|
||||||
|
*/
|
||||||
|
stopCapture(): Promise<boolean> {
|
||||||
|
let url_ = this.baseUrl + "/api/OscilloscopeApi/StopCapture";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processStopCapture(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processStopCapture(response: Response): Promise<boolean> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result200 = resultData200 !== undefined ? resultData200 : <any>null;
|
||||||
|
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status === 400) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result400: any = null;
|
||||||
|
let resultData400 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result400 = ProblemDetails.fromJS(resultData400);
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers, result400);
|
||||||
|
});
|
||||||
|
} else if (status === 500) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
} else if (status === 401) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result401: any = null;
|
||||||
|
let resultData401 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result401 = ProblemDetails.fromJS(resultData401);
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers, result401);
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<boolean>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取示波器数据和状态
|
||||||
|
* @return 示波器数据和状态信息
|
||||||
|
*/
|
||||||
|
getData(): Promise<OscilloscopeDataResponse> {
|
||||||
|
let url_ = this.baseUrl + "/api/OscilloscopeApi/GetData";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processGetData(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processGetData(response: Response): Promise<OscilloscopeDataResponse> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result200 = OscilloscopeDataResponse.fromJS(resultData200);
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status === 400) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result400: any = null;
|
||||||
|
let resultData400 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result400 = ProblemDetails.fromJS(resultData400);
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers, result400);
|
||||||
|
});
|
||||||
|
} else if (status === 500) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
} else if (status === 401) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result401: any = null;
|
||||||
|
let resultData401 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result401 = ProblemDetails.fromJS(resultData401);
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers, result401);
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<OscilloscopeDataResponse>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新触发参数
|
||||||
|
* @param level (optional) 触发电平(0-255)
|
||||||
|
* @param risingEdge (optional) 触发边沿(true为上升沿,false为下降沿)
|
||||||
|
* @return 操作结果
|
||||||
|
*/
|
||||||
|
updateTrigger(level: number | undefined, risingEdge: boolean | undefined): Promise<boolean> {
|
||||||
|
let url_ = this.baseUrl + "/api/OscilloscopeApi/UpdateTrigger?";
|
||||||
|
if (level === null)
|
||||||
|
throw new Error("The parameter 'level' cannot be null.");
|
||||||
|
else if (level !== undefined)
|
||||||
|
url_ += "level=" + encodeURIComponent("" + level) + "&";
|
||||||
|
if (risingEdge === null)
|
||||||
|
throw new Error("The parameter 'risingEdge' cannot be null.");
|
||||||
|
else if (risingEdge !== undefined)
|
||||||
|
url_ += "risingEdge=" + encodeURIComponent("" + risingEdge) + "&";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processUpdateTrigger(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processUpdateTrigger(response: Response): Promise<boolean> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result200 = resultData200 !== undefined ? resultData200 : <any>null;
|
||||||
|
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status === 400) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result400: any = null;
|
||||||
|
let resultData400 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result400 = ProblemDetails.fromJS(resultData400);
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers, result400);
|
||||||
|
});
|
||||||
|
} else if (status === 500) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
} else if (status === 401) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result401: any = null;
|
||||||
|
let resultData401 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result401 = ProblemDetails.fromJS(resultData401);
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers, result401);
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<boolean>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新采样参数
|
||||||
|
* @param horizontalShift (optional) 水平偏移量(0-1023)
|
||||||
|
* @param decimationRate (optional) 抽样率(0-1023)
|
||||||
|
* @return 操作结果
|
||||||
|
*/
|
||||||
|
updateSampling(horizontalShift: number | undefined, decimationRate: number | undefined): Promise<boolean> {
|
||||||
|
let url_ = this.baseUrl + "/api/OscilloscopeApi/UpdateSampling?";
|
||||||
|
if (horizontalShift === null)
|
||||||
|
throw new Error("The parameter 'horizontalShift' cannot be null.");
|
||||||
|
else if (horizontalShift !== undefined)
|
||||||
|
url_ += "horizontalShift=" + encodeURIComponent("" + horizontalShift) + "&";
|
||||||
|
if (decimationRate === null)
|
||||||
|
throw new Error("The parameter 'decimationRate' cannot be null.");
|
||||||
|
else if (decimationRate !== undefined)
|
||||||
|
url_ += "decimationRate=" + encodeURIComponent("" + decimationRate) + "&";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processUpdateSampling(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processUpdateSampling(response: Response): Promise<boolean> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result200 = resultData200 !== undefined ? resultData200 : <any>null;
|
||||||
|
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status === 400) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result400: any = null;
|
||||||
|
let resultData400 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result400 = ProblemDetails.fromJS(resultData400);
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers, result400);
|
||||||
|
});
|
||||||
|
} else if (status === 500) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
} else if (status === 401) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result401: any = null;
|
||||||
|
let resultData401 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result401 = ProblemDetails.fromJS(resultData401);
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers, result401);
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<boolean>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动刷新RAM
|
||||||
|
* @return 操作结果
|
||||||
|
*/
|
||||||
|
refreshRAM(): Promise<boolean> {
|
||||||
|
let url_ = this.baseUrl + "/api/OscilloscopeApi/RefreshRAM";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processRefreshRAM(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processRefreshRAM(response: Response): Promise<boolean> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result200 = resultData200 !== undefined ? resultData200 : <any>null;
|
||||||
|
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status === 400) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result400: any = null;
|
||||||
|
let resultData400 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result400 = ProblemDetails.fromJS(resultData400);
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers, result400);
|
||||||
|
});
|
||||||
|
} else if (status === 500) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
} else if (status === 401) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result401: any = null;
|
||||||
|
let resultData401 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||||
|
result401 = ProblemDetails.fromJS(resultData401);
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers, result401);
|
||||||
|
});
|
||||||
} else if (status !== 200 && status !== 204) {
|
} else if (status !== 200 && status !== 204) {
|
||||||
return response.text().then((_responseText) => {
|
return response.text().then((_responseText) => {
|
||||||
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
@ -4885,6 +5358,140 @@ export interface INetworkInterfaceDto {
|
||||||
macAddress: string;
|
macAddress: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 示波器完整配置 */
|
||||||
|
export class OscilloscopeFullConfig implements IOscilloscopeFullConfig {
|
||||||
|
/** 是否启动捕获 */
|
||||||
|
captureEnabled!: boolean;
|
||||||
|
/** 触发电平(0-255) */
|
||||||
|
triggerLevel!: number;
|
||||||
|
/** 触发边沿(true为上升沿,false为下降沿) */
|
||||||
|
triggerRisingEdge!: boolean;
|
||||||
|
/** 水平偏移量(0-1023) */
|
||||||
|
horizontalShift!: number;
|
||||||
|
/** 抽样率(0-1023) */
|
||||||
|
decimationRate!: number;
|
||||||
|
/** 是否自动刷新RAM */
|
||||||
|
autoRefreshRAM!: boolean;
|
||||||
|
|
||||||
|
constructor(data?: IOscilloscopeFullConfig) {
|
||||||
|
if (data) {
|
||||||
|
for (var property in data) {
|
||||||
|
if (data.hasOwnProperty(property))
|
||||||
|
(<any>this)[property] = (<any>data)[property];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(_data?: any) {
|
||||||
|
if (_data) {
|
||||||
|
this.captureEnabled = _data["captureEnabled"];
|
||||||
|
this.triggerLevel = _data["triggerLevel"];
|
||||||
|
this.triggerRisingEdge = _data["triggerRisingEdge"];
|
||||||
|
this.horizontalShift = _data["horizontalShift"];
|
||||||
|
this.decimationRate = _data["decimationRate"];
|
||||||
|
this.autoRefreshRAM = _data["autoRefreshRAM"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJS(data: any): OscilloscopeFullConfig {
|
||||||
|
data = typeof data === 'object' ? data : {};
|
||||||
|
let result = new OscilloscopeFullConfig();
|
||||||
|
result.init(data);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON(data?: any) {
|
||||||
|
data = typeof data === 'object' ? data : {};
|
||||||
|
data["captureEnabled"] = this.captureEnabled;
|
||||||
|
data["triggerLevel"] = this.triggerLevel;
|
||||||
|
data["triggerRisingEdge"] = this.triggerRisingEdge;
|
||||||
|
data["horizontalShift"] = this.horizontalShift;
|
||||||
|
data["decimationRate"] = this.decimationRate;
|
||||||
|
data["autoRefreshRAM"] = this.autoRefreshRAM;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 示波器完整配置 */
|
||||||
|
export interface IOscilloscopeFullConfig {
|
||||||
|
/** 是否启动捕获 */
|
||||||
|
captureEnabled: boolean;
|
||||||
|
/** 触发电平(0-255) */
|
||||||
|
triggerLevel: number;
|
||||||
|
/** 触发边沿(true为上升沿,false为下降沿) */
|
||||||
|
triggerRisingEdge: boolean;
|
||||||
|
/** 水平偏移量(0-1023) */
|
||||||
|
horizontalShift: number;
|
||||||
|
/** 抽样率(0-1023) */
|
||||||
|
decimationRate: number;
|
||||||
|
/** 是否自动刷新RAM */
|
||||||
|
autoRefreshRAM: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 示波器状态和数据 */
|
||||||
|
export class OscilloscopeDataResponse implements IOscilloscopeDataResponse {
|
||||||
|
/** AD采样频率 */
|
||||||
|
adFrequency!: number;
|
||||||
|
/** AD采样幅度 */
|
||||||
|
adVpp!: number;
|
||||||
|
/** AD采样最大值 */
|
||||||
|
adMax!: number;
|
||||||
|
/** AD采样最小值 */
|
||||||
|
adMin!: number;
|
||||||
|
/** 波形数据(Base64编码) */
|
||||||
|
waveformData!: string;
|
||||||
|
|
||||||
|
constructor(data?: IOscilloscopeDataResponse) {
|
||||||
|
if (data) {
|
||||||
|
for (var property in data) {
|
||||||
|
if (data.hasOwnProperty(property))
|
||||||
|
(<any>this)[property] = (<any>data)[property];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(_data?: any) {
|
||||||
|
if (_data) {
|
||||||
|
this.adFrequency = _data["adFrequency"];
|
||||||
|
this.adVpp = _data["adVpp"];
|
||||||
|
this.adMax = _data["adMax"];
|
||||||
|
this.adMin = _data["adMin"];
|
||||||
|
this.waveformData = _data["waveformData"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJS(data: any): OscilloscopeDataResponse {
|
||||||
|
data = typeof data === 'object' ? data : {};
|
||||||
|
let result = new OscilloscopeDataResponse();
|
||||||
|
result.init(data);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON(data?: any) {
|
||||||
|
data = typeof data === 'object' ? data : {};
|
||||||
|
data["adFrequency"] = this.adFrequency;
|
||||||
|
data["adVpp"] = this.adVpp;
|
||||||
|
data["adMax"] = this.adMax;
|
||||||
|
data["adMin"] = this.adMin;
|
||||||
|
data["waveformData"] = this.waveformData;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 示波器状态和数据 */
|
||||||
|
export interface IOscilloscopeDataResponse {
|
||||||
|
/** AD采样频率 */
|
||||||
|
adFrequency: number;
|
||||||
|
/** AD采样幅度 */
|
||||||
|
adVpp: number;
|
||||||
|
/** AD采样最大值 */
|
||||||
|
adMax: number;
|
||||||
|
/** AD采样最小值 */
|
||||||
|
adMin: number;
|
||||||
|
/** 波形数据(Base64编码) */
|
||||||
|
waveformData: string;
|
||||||
|
}
|
||||||
|
|
||||||
/** Package options which to send address to read or write */
|
/** Package options which to send address to read or write */
|
||||||
export class SendAddrPackOptions implements ISendAddrPackOptions {
|
export class SendAddrPackOptions implements ISendAddrPackOptions {
|
||||||
/** 突发类型 */
|
/** 突发类型 */
|
||||||
|
|
|
@ -0,0 +1,264 @@
|
||||||
|
import { createInjectionState } from "@vueuse/core";
|
||||||
|
import { shallowRef, reactive, ref, computed } from "vue";
|
||||||
|
import { Mutex } from "async-mutex";
|
||||||
|
import {
|
||||||
|
OscilloscopeFullConfig,
|
||||||
|
OscilloscopeDataResponse,
|
||||||
|
} from "@/APIClient";
|
||||||
|
import { AuthManager } from "@/utils/AuthManager";
|
||||||
|
import { useAlertStore } from "@/components/Alert";
|
||||||
|
import { useRequiredInjection } from "@/utils/Common";
|
||||||
|
|
||||||
|
export type OscilloscopeDataType = {
|
||||||
|
x: number[];
|
||||||
|
y: number[] | number[][];
|
||||||
|
xUnit: "s" | "ms" | "us" | "ns";
|
||||||
|
yUnit: "V" | "mV" | "uV";
|
||||||
|
adFrequency: number;
|
||||||
|
adVpp: number;
|
||||||
|
adMax: number;
|
||||||
|
adMin: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 默认配置
|
||||||
|
const DEFAULT_CONFIG: OscilloscopeFullConfig = new OscilloscopeFullConfig({
|
||||||
|
captureEnabled: false,
|
||||||
|
triggerLevel: 128,
|
||||||
|
triggerRisingEdge: true,
|
||||||
|
horizontalShift: 0,
|
||||||
|
decimationRate: 0,
|
||||||
|
autoRefreshRAM: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 采样频率常量(后端返回)
|
||||||
|
const [useProvideOscilloscope, useOscilloscopeState] = createInjectionState(() => {
|
||||||
|
const oscData = shallowRef<OscilloscopeDataType>();
|
||||||
|
const alert = useRequiredInjection(useAlertStore);
|
||||||
|
|
||||||
|
// 互斥锁
|
||||||
|
const operationMutex = new Mutex();
|
||||||
|
|
||||||
|
// 状态
|
||||||
|
const isApplying = ref(false);
|
||||||
|
const isCapturing = ref(false);
|
||||||
|
|
||||||
|
// 配置
|
||||||
|
const config = reactive<OscilloscopeFullConfig>(new OscilloscopeFullConfig({ ...DEFAULT_CONFIG }));
|
||||||
|
|
||||||
|
// 采样点数(由后端数据决定)
|
||||||
|
const sampleCount = ref(0);
|
||||||
|
|
||||||
|
// 采样周期(ns),由adFrequency计算
|
||||||
|
const samplePeriodNs = computed(() =>
|
||||||
|
oscData.value?.adFrequency ? 1_000_000_000 / oscData.value.adFrequency : 200
|
||||||
|
);
|
||||||
|
|
||||||
|
// 应用配置
|
||||||
|
const applyConfiguration = async () => {
|
||||||
|
if (operationMutex.isLocked()) {
|
||||||
|
alert.warn("有其他操作正在进行中,请稍后再试", 3000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const release = await operationMutex.acquire();
|
||||||
|
isApplying.value = true;
|
||||||
|
try {
|
||||||
|
const client = AuthManager.createAuthenticatedOscilloscopeApiClient();
|
||||||
|
const success = await client.initialize({ ...config });
|
||||||
|
if (success) {
|
||||||
|
alert.success("示波器配置已应用", 2000);
|
||||||
|
} else {
|
||||||
|
throw new Error("应用失败");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert.error("应用配置失败", 3000);
|
||||||
|
} finally {
|
||||||
|
isApplying.value = false;
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 重置配置
|
||||||
|
const resetConfiguration = () => {
|
||||||
|
Object.assign(config, { ...DEFAULT_CONFIG });
|
||||||
|
alert.info("配置已重置", 2000);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取数据
|
||||||
|
const getOscilloscopeData = async () => {
|
||||||
|
try {
|
||||||
|
const client = AuthManager.createAuthenticatedOscilloscopeApiClient();
|
||||||
|
const resp: OscilloscopeDataResponse = await client.getData();
|
||||||
|
|
||||||
|
// 解析波形数据
|
||||||
|
const binaryString = atob(resp.waveformData);
|
||||||
|
const bytes = new Uint8Array(binaryString.length);
|
||||||
|
for (let i = 0; i < binaryString.length; i++) {
|
||||||
|
bytes[i] = binaryString.charCodeAt(i);
|
||||||
|
}
|
||||||
|
sampleCount.value = bytes.length;
|
||||||
|
|
||||||
|
// 构建时间轴
|
||||||
|
const x = Array.from(
|
||||||
|
{ length: bytes.length },
|
||||||
|
(_, i) => (i * samplePeriodNs.value) / 1000 // us
|
||||||
|
);
|
||||||
|
const y = Array.from(bytes);
|
||||||
|
|
||||||
|
oscData.value = {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
xUnit: "us",
|
||||||
|
yUnit: "V",
|
||||||
|
adFrequency: resp.adFrequency,
|
||||||
|
adVpp: resp.adVpp,
|
||||||
|
adMax: resp.adMax,
|
||||||
|
adMin: resp.adMin,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
alert.error("获取示波器数据失败", 3000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 启动捕获
|
||||||
|
const startCapture = async () => {
|
||||||
|
if (operationMutex.isLocked()) {
|
||||||
|
alert.warn("有其他操作正在进行中,请稍后再试", 3000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isCapturing.value = true;
|
||||||
|
const release = await operationMutex.acquire();
|
||||||
|
try {
|
||||||
|
const client = AuthManager.createAuthenticatedOscilloscopeApiClient();
|
||||||
|
const started = await client.startCapture();
|
||||||
|
if (!started) throw new Error("无法启动捕获");
|
||||||
|
alert.info("开始捕获...", 2000);
|
||||||
|
|
||||||
|
// 简单轮询,直到捕获完成(可根据后端实际情况优化)
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
await getOscilloscopeData();
|
||||||
|
alert.success("捕获完成", 2000);
|
||||||
|
} catch (error) {
|
||||||
|
alert.error("捕获失败", 3000);
|
||||||
|
} finally {
|
||||||
|
isCapturing.value = false;
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 停止捕获
|
||||||
|
const stopCapture = async () => {
|
||||||
|
if (!isCapturing.value) {
|
||||||
|
alert.warn("当前没有正在进行的捕获操作", 2000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isCapturing.value = false;
|
||||||
|
const release = await operationMutex.acquire();
|
||||||
|
try {
|
||||||
|
const client = AuthManager.createAuthenticatedOscilloscopeApiClient();
|
||||||
|
const stopped = await client.stopCapture();
|
||||||
|
if (!stopped) throw new Error("无法停止捕获");
|
||||||
|
alert.info("捕获已停止", 2000);
|
||||||
|
} catch (error) {
|
||||||
|
alert.error("停止捕获失败", 3000);
|
||||||
|
} finally {
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 更新触发参数
|
||||||
|
const updateTrigger = async (level: number, risingEdge: boolean) => {
|
||||||
|
const client = AuthManager.createAuthenticatedOscilloscopeApiClient();
|
||||||
|
try {
|
||||||
|
const ok = await client.updateTrigger(level, risingEdge);
|
||||||
|
if (ok) {
|
||||||
|
config.triggerLevel = level;
|
||||||
|
config.triggerRisingEdge = risingEdge;
|
||||||
|
alert.success("触发参数已更新", 2000);
|
||||||
|
} else {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
alert.error("更新触发参数失败", 2000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 更新采样参数
|
||||||
|
const updateSampling = async (horizontalShift: number, decimationRate: number) => {
|
||||||
|
const client = AuthManager.createAuthenticatedOscilloscopeApiClient();
|
||||||
|
try {
|
||||||
|
const ok = await client.updateSampling(horizontalShift, decimationRate);
|
||||||
|
if (ok) {
|
||||||
|
config.horizontalShift = horizontalShift;
|
||||||
|
config.decimationRate = decimationRate;
|
||||||
|
alert.success("采样参数已更新", 2000);
|
||||||
|
} else {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
alert.error("更新采样参数失败", 2000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 手动刷新RAM
|
||||||
|
const refreshRAM = async () => {
|
||||||
|
const client = AuthManager.createAuthenticatedOscilloscopeApiClient();
|
||||||
|
try {
|
||||||
|
const ok = await client.refreshRAM();
|
||||||
|
if (ok) {
|
||||||
|
alert.success("RAM已刷新", 2000);
|
||||||
|
} else {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
alert.error("刷新RAM失败", 2000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 生成测试数据
|
||||||
|
const generateTestData = () => {
|
||||||
|
const freq = 5_000_000;
|
||||||
|
const duration = 0.001; // 1ms
|
||||||
|
const points = Math.floor(freq * duration);
|
||||||
|
const x = Array.from({ length: points }, (_, i) => (i * 1_000_000_000 / freq) / 1000);
|
||||||
|
const y = Array.from({ length: points }, (_, i) =>
|
||||||
|
Math.floor(Math.sin(i * 0.01) * 127 + 128)
|
||||||
|
);
|
||||||
|
oscData.value = {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
xUnit: "us",
|
||||||
|
yUnit: "V",
|
||||||
|
adFrequency: freq,
|
||||||
|
adVpp: 2.0,
|
||||||
|
adMax: 255,
|
||||||
|
adMin: 0,
|
||||||
|
};
|
||||||
|
alert.success("测试数据生成成功", 2000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isOperationInProgress = computed(
|
||||||
|
() => isApplying.value || isCapturing.value || operationMutex.isLocked()
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
oscData,
|
||||||
|
config,
|
||||||
|
isApplying,
|
||||||
|
isCapturing,
|
||||||
|
isOperationInProgress,
|
||||||
|
sampleCount,
|
||||||
|
samplePeriodNs,
|
||||||
|
|
||||||
|
applyConfiguration,
|
||||||
|
resetConfiguration,
|
||||||
|
getOscilloscopeData,
|
||||||
|
startCapture,
|
||||||
|
stopCapture,
|
||||||
|
updateTrigger,
|
||||||
|
updateSampling,
|
||||||
|
refreshRAM,
|
||||||
|
generateTestData,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export { useProvideOscilloscope, useOscilloscopeState, DEFAULT_CONFIG };
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="w-full h-100">
|
<div class="w-full h-100">
|
||||||
<v-chart v-if="true" class="w-full h-full" :option="option" autoresize />
|
<v-chart v-if="hasData" class="w-full h-full" :option="option" autoresize />
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
class="w-full h-full flex items-center justify-center text-gray-500"
|
class="w-full h-full flex items-center justify-center text-gray-500"
|
||||||
|
@ -11,16 +11,15 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, withDefaults } from "vue";
|
import { computed } from "vue";
|
||||||
import { forEach } from "lodash";
|
import { forEach } from "lodash";
|
||||||
import VChart from "vue-echarts";
|
import VChart from "vue-echarts";
|
||||||
import { type WaveformDataType } from "./index";
|
import { useOscilloscopeState } from "./OscilloscopeManager";
|
||||||
|
|
||||||
// Echarts
|
// Echarts
|
||||||
import { use } from "echarts/core";
|
import { use } from "echarts/core";
|
||||||
import { LineChart } from "echarts/charts";
|
import { LineChart } from "echarts/charts";
|
||||||
import {
|
import {
|
||||||
TitleComponent,
|
|
||||||
TooltipComponent,
|
TooltipComponent,
|
||||||
LegendComponent,
|
LegendComponent,
|
||||||
ToolboxComponent,
|
ToolboxComponent,
|
||||||
|
@ -37,6 +36,7 @@ import type {
|
||||||
DataZoomComponentOption,
|
DataZoomComponentOption,
|
||||||
GridComponentOption,
|
GridComponentOption,
|
||||||
} from "echarts/components";
|
} from "echarts/components";
|
||||||
|
import { useRequiredInjection } from "@/utils/Common";
|
||||||
|
|
||||||
use([
|
use([
|
||||||
TooltipComponent,
|
TooltipComponent,
|
||||||
|
@ -57,44 +57,47 @@ type EChartsOption = ComposeOption<
|
||||||
| LineSeriesOption
|
| LineSeriesOption
|
||||||
>;
|
>;
|
||||||
|
|
||||||
const props = withDefaults(
|
// 使用 manager 获取 oscilloscope 数据
|
||||||
defineProps<{
|
const { oscData } = useRequiredInjection(useOscilloscopeState);
|
||||||
data?: WaveformDataType;
|
|
||||||
}>(),
|
|
||||||
{
|
|
||||||
data: () => ({
|
|
||||||
x: [],
|
|
||||||
y: [],
|
|
||||||
xUnit: "s",
|
|
||||||
yUnit: "V",
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const hasData = computed(() => {
|
const hasData = computed(() => {
|
||||||
return (
|
return (
|
||||||
props.data &&
|
oscData.value &&
|
||||||
props.data.x &&
|
oscData.value.x &&
|
||||||
props.data.y &&
|
oscData.value.y &&
|
||||||
props.data.x.length > 0 &&
|
oscData.value.x.length > 0 &&
|
||||||
props.data.y.length > 0 &&
|
(
|
||||||
props.data.y.some((channel) => channel.length > 0)
|
Array.isArray(oscData.value.y[0])
|
||||||
|
? oscData.value.y.some((channel: any) => channel.length > 0)
|
||||||
|
: oscData.value.y.length > 0
|
||||||
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const option = computed((): EChartsOption => {
|
const option = computed((): EChartsOption => {
|
||||||
|
if (!oscData.value || !oscData.value.x || !oscData.value.y) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
const series: LineSeriesOption[] = [];
|
const series: LineSeriesOption[] = [];
|
||||||
|
|
||||||
forEach(props.data.y, (yData, index) => {
|
// 兼容单通道和多通道,确保 yChannels 为 number[][]
|
||||||
// 将 x 和 y 数据组合成 [x, y] 格式
|
const yChannels: number[][] = Array.isArray(oscData.value.y[0])
|
||||||
const seriesData = props.data.x.map((xValue, i) => [xValue, yData[i] || 0]);
|
? (oscData.value.y as number[][])
|
||||||
|
: [oscData.value.y as number[]];
|
||||||
|
|
||||||
|
forEach(yChannels, (yData, index) => {
|
||||||
|
if (!oscData.value || !yData) return;
|
||||||
|
const seriesData = oscData.value.x.map((xValue, i) => [
|
||||||
|
xValue,
|
||||||
|
yData && yData[i] !== undefined ? yData[i] : 0,
|
||||||
|
]);
|
||||||
series.push({
|
series.push({
|
||||||
type: "line",
|
type: "line",
|
||||||
name: `通道 ${index + 1}`,
|
name: `通道 ${index + 1}`,
|
||||||
data: seriesData,
|
data: seriesData,
|
||||||
smooth: false, // 示波器通常显示原始波形
|
smooth: false,
|
||||||
symbol: "none", // 不显示数据点标记
|
symbol: "none",
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
width: 2,
|
width: 2,
|
||||||
},
|
},
|
||||||
|
@ -111,9 +114,10 @@ const option = computed((): EChartsOption => {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: "axis",
|
trigger: "axis",
|
||||||
formatter: (params: any) => {
|
formatter: (params: any) => {
|
||||||
let result = `时间: ${params[0].data[0].toFixed(2)} ${props.data.xUnit}<br/>`;
|
if (!oscData.value) return "";
|
||||||
|
let result = `时间: ${params[0].data[0].toFixed(2)} ${oscData.value.xUnit}<br/>`;
|
||||||
params.forEach((param: any) => {
|
params.forEach((param: any) => {
|
||||||
result += `${param.seriesName}: ${param.data[1].toFixed(3)} ${props.data.yUnit}<br/>`;
|
result += `${param.seriesName}: ${param.data[1].toFixed(3)} ${oscData.value?.yUnit ?? ""}<br/>`;
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
@ -141,7 +145,7 @@ const option = computed((): EChartsOption => {
|
||||||
],
|
],
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: "value",
|
type: "value",
|
||||||
name: `时间 (${props.data.xUnit})`,
|
name: oscData.value ? `时间 (${oscData.value.xUnit})` : "时间",
|
||||||
nameLocation: "middle",
|
nameLocation: "middle",
|
||||||
nameGap: 30,
|
nameGap: 30,
|
||||||
axisLine: {
|
axisLine: {
|
||||||
|
@ -156,7 +160,7 @@ const option = computed((): EChartsOption => {
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
type: "value",
|
type: "value",
|
||||||
name: `电压 (${props.data.yUnit})`,
|
name: oscData.value ? `电压 (${oscData.value.yUnit})` : "电压",
|
||||||
nameLocation: "middle",
|
nameLocation: "middle",
|
||||||
nameGap: 40,
|
nameGap: 40,
|
||||||
axisLine: {
|
axisLine: {
|
|
@ -1,42 +1,3 @@
|
||||||
import WaveformDisplay from "./WaveformDisplay.vue";
|
import OscilloscopeWaveformDisplay from "./OscilloscopeWaveformDisplay.vue";
|
||||||
|
|
||||||
type WaveformDataType = {
|
export { OscilloscopeWaveformDisplay };
|
||||||
x: number[];
|
|
||||||
y: number[][];
|
|
||||||
xUnit: "s" | "ms" | "us";
|
|
||||||
yUnit: "V" | "mV" | "uV";
|
|
||||||
};
|
|
||||||
|
|
||||||
// Test data generator
|
|
||||||
function generateTestData(): WaveformDataType {
|
|
||||||
const sampleRate = 1000; // 1kHz
|
|
||||||
const duration = 0.1; // 10ms
|
|
||||||
const points = Math.floor(sampleRate * duration);
|
|
||||||
|
|
||||||
const x = Array.from({ length: points }, (_, i) => (i / sampleRate) * 1000); // time in ms
|
|
||||||
|
|
||||||
// Generate multiple channels with different waveforms
|
|
||||||
const y = [
|
|
||||||
// Channel 1: Sine wave 50Hz
|
|
||||||
Array.from(
|
|
||||||
{ length: points },
|
|
||||||
(_, i) => Math.sin((2 * Math.PI * 50 * i) / sampleRate) * 3.3,
|
|
||||||
),
|
|
||||||
// Channel 2: Square wave 25Hz
|
|
||||||
Array.from(
|
|
||||||
{ length: points },
|
|
||||||
(_, i) => Math.sign(Math.sin((2 * Math.PI * 25 * i) / sampleRate)) * 5,
|
|
||||||
),
|
|
||||||
// Channel 3: Sawtooth wave 33Hz
|
|
||||||
Array.from(
|
|
||||||
{ length: points },
|
|
||||||
(_, i) => (2 * (((33 * i) / sampleRate) % 1) - 1) * 2.5,
|
|
||||||
),
|
|
||||||
// Channel 4: Noise + DC offset
|
|
||||||
Array.from({ length: points }, () => Math.random() * 0.5 + 1.5),
|
|
||||||
];
|
|
||||||
|
|
||||||
return { x, y, xUnit: "ms", yUnit: "V" };
|
|
||||||
}
|
|
||||||
|
|
||||||
export { WaveformDisplay, generateTestData , type WaveformDataType };
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
UDPClient,
|
UDPClient,
|
||||||
LogicAnalyzerClient,
|
LogicAnalyzerClient,
|
||||||
NetConfigClient,
|
NetConfigClient,
|
||||||
|
OscilloscopeApiClient,
|
||||||
} from "@/APIClient";
|
} from "@/APIClient";
|
||||||
|
|
||||||
// 支持的客户端类型联合类型
|
// 支持的客户端类型联合类型
|
||||||
|
@ -26,7 +27,8 @@ type SupportedClient =
|
||||||
| TutorialClient
|
| TutorialClient
|
||||||
| LogicAnalyzerClient
|
| LogicAnalyzerClient
|
||||||
| UDPClient
|
| UDPClient
|
||||||
| NetConfigClient;
|
| NetConfigClient
|
||||||
|
| OscilloscopeApiClient;
|
||||||
|
|
||||||
export class AuthManager {
|
export class AuthManager {
|
||||||
// 存储token到localStorage
|
// 存储token到localStorage
|
||||||
|
@ -158,10 +160,14 @@ export class AuthManager {
|
||||||
public static createAuthenticatedLogicAnalyzerClient(): LogicAnalyzerClient {
|
public static createAuthenticatedLogicAnalyzerClient(): LogicAnalyzerClient {
|
||||||
return AuthManager.createAuthenticatedClient(LogicAnalyzerClient);
|
return AuthManager.createAuthenticatedClient(LogicAnalyzerClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static createAuthenticatedNetConfigClient(): NetConfigClient {
|
public static createAuthenticatedNetConfigClient(): NetConfigClient {
|
||||||
return AuthManager.createAuthenticatedClient(NetConfigClient);
|
return AuthManager.createAuthenticatedClient(NetConfigClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static createAuthenticatedOscilloscopeApiClient(): OscilloscopeApiClient {
|
||||||
|
return AuthManager.createAuthenticatedClient(OscilloscopeApiClient);
|
||||||
|
}
|
||||||
|
|
||||||
// 登录函数
|
// 登录函数
|
||||||
public static async login(
|
public static async login(
|
||||||
|
|
|
@ -104,9 +104,12 @@ import { onMounted, ref, watch } from "vue";
|
||||||
import Debugger from "./Debugger.vue";
|
import Debugger from "./Debugger.vue";
|
||||||
import { useProvideLogicAnalyzer } from "@/components/LogicAnalyzer";
|
import { useProvideLogicAnalyzer } from "@/components/LogicAnalyzer";
|
||||||
import { useProvideWaveformManager } from "@/components/WaveformDisplay/WaveformManager";
|
import { useProvideWaveformManager } from "@/components/WaveformDisplay/WaveformManager";
|
||||||
|
import { useProvideOscilloscope } from "@/components/Oscilloscope/OscilloscopeManager";
|
||||||
|
|
||||||
const analyzer = useProvideLogicAnalyzer();
|
const analyzer = useProvideLogicAnalyzer();
|
||||||
const waveformManager = useProvideWaveformManager();
|
const waveformManager = useProvideWaveformManager();
|
||||||
|
const oscilloscopeManager = useProvideOscilloscope();
|
||||||
|
|
||||||
waveformManager.logicData.value = waveformManager.generateTestData();
|
waveformManager.logicData.value = waveformManager.generateTestData();
|
||||||
|
|
||||||
const checkID = useLocalStorage("checkID", 1);
|
const checkID = useLocalStorage("checkID", 1);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<Activity class="w-5 h-5" />
|
<Activity class="w-5 h-5" />
|
||||||
波形显示
|
波形显示
|
||||||
</h2>
|
</h2>
|
||||||
<WaveformDisplay :data="generateTestData()" />
|
<OscilloscopeWaveformDisplay />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Activity } from "lucide-vue-next";
|
import { Activity } from "lucide-vue-next";
|
||||||
import { WaveformDisplay, generateTestData } from "@/components/Oscilloscope";
|
import { OscilloscopeWaveformDisplay } from "@/components/Oscilloscope";
|
||||||
import { useEquipments } from "@/stores/equipments";
|
import { useEquipments } from "@/stores/equipments";
|
||||||
|
|
||||||
// 使用全局设备配置
|
// 使用全局设备配置
|
||||||
|
|
Loading…
Reference in New Issue