feat: 添加debugger后端api,并修改waveformdisplay使其更加通用
This commit is contained in:
parent
a4192659d1
commit
23d4459406
|
@ -0,0 +1,251 @@
|
|||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Peripherals.DebuggerClient;
|
||||
|
||||
namespace server.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// FPGA调试器控制器
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
public class DebuggerController : ControllerBase
|
||||
{
|
||||
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
|
||||
/// <summary>
|
||||
/// 获取调试器实例
|
||||
/// </summary>
|
||||
private DebuggerClient? GetDebugger()
|
||||
{
|
||||
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 DebuggerClient(board.IpAddr, board.Port, 1);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(ex, "获取调试器实例时发生异常");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置捕获模式
|
||||
/// </summary>
|
||||
[HttpPost("SetMode")]
|
||||
[EnableCors("Users")]
|
||||
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
public async Task<IActionResult> SetMode([FromBody] CaptureMode mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
var debugger = GetDebugger();
|
||||
if (debugger == null)
|
||||
return BadRequest("用户未绑定有效的实验板");
|
||||
|
||||
var result = await debugger.SetMode(mode);
|
||||
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>
|
||||
[HttpPost("StartTrigger")]
|
||||
[EnableCors("Users")]
|
||||
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
public async Task<IActionResult> StartTrigger()
|
||||
{
|
||||
try
|
||||
{
|
||||
var debugger = GetDebugger();
|
||||
if (debugger == null)
|
||||
return BadRequest("用户未绑定有效的实验板");
|
||||
|
||||
var result = await debugger.StartTrigger();
|
||||
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>
|
||||
[HttpGet("ReadFlag")]
|
||||
[EnableCors("Users")]
|
||||
[ProducesResponseType(typeof(byte), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
public async Task<IActionResult> ReadFlag()
|
||||
{
|
||||
try
|
||||
{
|
||||
var debugger = GetDebugger();
|
||||
if (debugger == null)
|
||||
return BadRequest("用户未绑定有效的实验板");
|
||||
|
||||
var result = await debugger.ReadFlag();
|
||||
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>
|
||||
[HttpPost("ClearFlag")]
|
||||
[EnableCors("Users")]
|
||||
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
public async Task<IActionResult> ClearFlag()
|
||||
{
|
||||
try
|
||||
{
|
||||
var debugger = GetDebugger();
|
||||
if (debugger == null)
|
||||
return BadRequest("用户未绑定有效的实验板");
|
||||
|
||||
var result = await debugger.ClearFlag();
|
||||
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>
|
||||
[HttpGet("ReadData")]
|
||||
[EnableCors("Users")]
|
||||
[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
public async Task<IActionResult> ReadData([FromQuery] ushort offset = 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
var debugger = GetDebugger();
|
||||
if (debugger == null)
|
||||
return BadRequest("用户未绑定有效的实验板");
|
||||
|
||||
var result = await debugger.ReadData(offset);
|
||||
if (!result.IsSuccessful)
|
||||
{
|
||||
logger.Error($"读取捕获数据失败: {result.Error}");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "读取捕获数据失败");
|
||||
}
|
||||
|
||||
// 返回Base64编码
|
||||
var base64Data = Convert.ToBase64String(result.Value);
|
||||
return Ok(base64Data);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(ex, "读取捕获数据时发生异常");
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, "操作失败,请稍后重试");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新调试器状态
|
||||
/// </summary>
|
||||
[HttpPost("Refresh")]
|
||||
[EnableCors("Users")]
|
||||
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
public async Task<IActionResult> Refresh()
|
||||
{
|
||||
try
|
||||
{
|
||||
var debugger = GetDebugger();
|
||||
if (debugger == null)
|
||||
return BadRequest("用户未绑定有效的实验板");
|
||||
|
||||
var result = await debugger.Refresh();
|
||||
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, "操作失败,请稍后重试");
|
||||
}
|
||||
}
|
||||
}
|
356
src/APIClient.ts
356
src/APIClient.ts
|
@ -1637,6 +1637,362 @@ export class DDSClient {
|
|||
}
|
||||
}
|
||||
|
||||
export class DebuggerClient {
|
||||
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://127.0.0.1:5000";
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置捕获模式
|
||||
*/
|
||||
setMode(mode: string): Promise<boolean> {
|
||||
let url_ = this.baseUrl + "/api/Debugger/SetMode";
|
||||
url_ = url_.replace(/[?&]$/, "");
|
||||
|
||||
const content_ = JSON.stringify(mode);
|
||||
|
||||
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.processSetMode(_response);
|
||||
});
|
||||
}
|
||||
|
||||
protected processSetMode(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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动触发器
|
||||
*/
|
||||
startTrigger(): Promise<boolean> {
|
||||
let url_ = this.baseUrl + "/api/Debugger/StartTrigger";
|
||||
url_ = url_.replace(/[?&]$/, "");
|
||||
|
||||
let options_: RequestInit = {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Accept": "application/json"
|
||||
}
|
||||
};
|
||||
|
||||
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||
return this.processStartTrigger(_response);
|
||||
});
|
||||
}
|
||||
|
||||
protected processStartTrigger(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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取触发器状态标志
|
||||
*/
|
||||
readFlag(): Promise<number> {
|
||||
let url_ = this.baseUrl + "/api/Debugger/ReadFlag";
|
||||
url_ = url_.replace(/[?&]$/, "");
|
||||
|
||||
let options_: RequestInit = {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Accept": "application/json"
|
||||
}
|
||||
};
|
||||
|
||||
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||
return this.processReadFlag(_response);
|
||||
});
|
||||
}
|
||||
|
||||
protected processReadFlag(response: Response): Promise<number> {
|
||||
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<number>(null as any);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除触发器状态标志
|
||||
*/
|
||||
clearFlag(): Promise<boolean> {
|
||||
let url_ = this.baseUrl + "/api/Debugger/ClearFlag";
|
||||
url_ = url_.replace(/[?&]$/, "");
|
||||
|
||||
let options_: RequestInit = {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Accept": "application/json"
|
||||
}
|
||||
};
|
||||
|
||||
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||
return this.processClearFlag(_response);
|
||||
});
|
||||
}
|
||||
|
||||
protected processClearFlag(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 offset (optional)
|
||||
*/
|
||||
readData(offset: number | undefined): Promise<string> {
|
||||
let url_ = this.baseUrl + "/api/Debugger/ReadData?";
|
||||
if (offset === null)
|
||||
throw new Error("The parameter 'offset' cannot be null.");
|
||||
else if (offset !== undefined)
|
||||
url_ += "offset=" + encodeURIComponent("" + offset) + "&";
|
||||
url_ = url_.replace(/[?&]$/, "");
|
||||
|
||||
let options_: RequestInit = {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Accept": "application/json"
|
||||
}
|
||||
};
|
||||
|
||||
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||
return this.processReadData(_response);
|
||||
});
|
||||
}
|
||||
|
||||
protected processReadData(response: Response): Promise<string> {
|
||||
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<string>(null as any);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新调试器状态
|
||||
*/
|
||||
refresh(): Promise<boolean> {
|
||||
let url_ = this.baseUrl + "/api/Debugger/Refresh";
|
||||
url_ = url_.replace(/[?&]$/, "");
|
||||
|
||||
let options_: RequestInit = {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Accept": "application/json"
|
||||
}
|
||||
};
|
||||
|
||||
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||
return this.processRefresh(_response);
|
||||
});
|
||||
}
|
||||
|
||||
protected processRefresh(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);
|
||||
}
|
||||
}
|
||||
|
||||
export class JtagClient {
|
||||
private http: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> };
|
||||
private baseUrl: string;
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
<div
|
||||
class="w-full"
|
||||
:class="{
|
||||
'h-48': !analyzer.logicData.value,
|
||||
'h-150': analyzer.logicData.value,
|
||||
'h-48': !props.data,
|
||||
'h-150': props.data,
|
||||
}"
|
||||
>
|
||||
<v-chart
|
||||
v-if="analyzer.logicData.value"
|
||||
v-if="props.data"
|
||||
class="w-full h-full"
|
||||
:option="option"
|
||||
autoresize
|
||||
|
@ -17,17 +17,20 @@
|
|||
v-else
|
||||
class="w-full h-full flex flex-col gap-6 items-center justify-center"
|
||||
>
|
||||
<div class="text-center">
|
||||
<h3 class="text-xl font-semibold text-slate-600 mb-2">
|
||||
暂无逻辑分析数据
|
||||
</h3>
|
||||
</div>
|
||||
<template v-if="hasSlot">
|
||||
<slot />
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="text-center">
|
||||
<h3 class="text-xl font-semibold text-slate-600 mb-2">暂无数据</h3>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, shallowRef } from "vue";
|
||||
import { computed, shallowRef, useSlots } from "vue";
|
||||
import VChart from "vue-echarts";
|
||||
|
||||
// Echarts
|
||||
|
@ -56,9 +59,8 @@ import type {
|
|||
XAXisOption,
|
||||
YAXisOption,
|
||||
} from "echarts/types/dist/shared";
|
||||
import { useRequiredInjection } from "@/utils/Common";
|
||||
import { isUndefined } from "lodash";
|
||||
import { useWaveformManager } from "./WaveformManager";
|
||||
import type { LogicDataType } from ".";
|
||||
|
||||
use([
|
||||
TooltipComponent,
|
||||
|
@ -81,7 +83,12 @@ type EChartsOption = ComposeOption<
|
|||
| MarkLineComponentOption
|
||||
>;
|
||||
|
||||
const analyzer = useRequiredInjection(useWaveformManager);
|
||||
const props = defineProps<{
|
||||
data?: LogicDataType;
|
||||
}>();
|
||||
|
||||
const slots = useSlots();
|
||||
const hasSlot = computed(() => !!slots.default && slots.default().length > 0);
|
||||
|
||||
// 添加更新选项来减少重绘
|
||||
const updateOptions = shallowRef({
|
||||
|
@ -91,13 +98,13 @@ const updateOptions = shallowRef({
|
|||
});
|
||||
|
||||
const option = computed((): EChartsOption => {
|
||||
if (isUndefined(analyzer.logicData.value)) return {};
|
||||
if (isUndefined(props.data)) return {};
|
||||
|
||||
// 只获取启用的通道,使用y数据结构
|
||||
const enabledChannels = analyzer.logicData.value.y.filter(
|
||||
const enabledChannels = props.data.y.filter(
|
||||
(channel) => channel.enabled,
|
||||
);
|
||||
const enabledChannelIndices = analyzer.logicData.value.y
|
||||
const enabledChannelIndices = props.data.y
|
||||
.map((channel, index) => (channel.enabled ? index : -1))
|
||||
.filter((index) => index !== -1);
|
||||
|
||||
|
@ -124,11 +131,11 @@ const option = computed((): EChartsOption => {
|
|||
{
|
||||
type: "category",
|
||||
boundaryGap: true,
|
||||
data: analyzer.logicData.value.x.map((x) => x.toFixed(3)),
|
||||
data: props.data.x.map((x) => x.toFixed(3)),
|
||||
axisLabel: {
|
||||
formatter: (value: string) =>
|
||||
analyzer.logicData.value
|
||||
? `${value}${analyzer.logicData.value.xUnit}`
|
||||
props.data
|
||||
? `${value}${props.data.xUnit}`
|
||||
: `${value}`,
|
||||
},
|
||||
},
|
||||
|
@ -157,7 +164,7 @@ const option = computed((): EChartsOption => {
|
|||
const series: LineSeriesOption[] = [];
|
||||
enabledChannelIndices.forEach(
|
||||
(originalIndex: number, displayIndex: number) => {
|
||||
const channel = analyzer.logicData.value!.y[originalIndex];
|
||||
const channel = props.data!.y[originalIndex];
|
||||
if (channel.type === "logic") {
|
||||
// logic类型,原样显示
|
||||
series.push({
|
||||
|
@ -182,7 +189,7 @@ const option = computed((): EChartsOption => {
|
|||
});
|
||||
} else if (channel.type === "number") {
|
||||
const values = channel.value;
|
||||
const xArr = analyzer.logicData.value!.x;
|
||||
const xArr = props.data!.x;
|
||||
// 构造带过渡的点序列
|
||||
function buildVcdLine(valArr: number[], high: number, low: number) {
|
||||
const points: { x: number; y: number }[] = [];
|
||||
|
@ -208,7 +215,8 @@ const option = computed((): EChartsOption => {
|
|||
let lastIdx = 0;
|
||||
// 格式化函数
|
||||
function formatValue(val: number) {
|
||||
if (channel.base === "hex") return "0x" + val.toString(16).toUpperCase();
|
||||
if (channel.base === "hex")
|
||||
return "0x" + val.toString(16).toUpperCase();
|
||||
if (channel.base === "bin") return "0b" + val.toString(2);
|
||||
return val.toString();
|
||||
}
|
||||
|
@ -314,12 +322,12 @@ const option = computed((): EChartsOption => {
|
|||
},
|
||||
formatter: (params: any) => {
|
||||
if (Array.isArray(params) && params.length > 0) {
|
||||
const timeValue = analyzer.logicData.value!.x[params[0].dataIndex];
|
||||
const timeValue = props.data!.x[params[0].dataIndex];
|
||||
const dataIndex = params[0].dataIndex;
|
||||
let tooltip = `Time: ${timeValue.toFixed(3)}${analyzer.logicData.value!.xUnit}<br/>`;
|
||||
let tooltip = `Time: ${timeValue.toFixed(3)}${props.data!.xUnit}<br/>`;
|
||||
enabledChannelIndices.forEach(
|
||||
(originalIndex: number, displayIndex: number) => {
|
||||
const channel = analyzer.logicData.value!.y[originalIndex];
|
||||
const channel = props.data!.y[originalIndex];
|
||||
if (channel.type === "logic") {
|
||||
const channelName = channel.name;
|
||||
const originalValue = channel.value[dataIndex];
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
import { createInjectionState } from "@vueuse/core";
|
||||
import { shallowRef } from "vue";
|
||||
|
||||
export type LogicDataType = {
|
||||
x: number[];
|
||||
y: {
|
||||
enabled: boolean;
|
||||
type: "logic" | "number";
|
||||
name: string;
|
||||
color: string;
|
||||
value: number[];
|
||||
base: "bin" | "dec" | "hex";
|
||||
}[];
|
||||
xUnit: "s" | "ms" | "us" | "ns";
|
||||
};
|
||||
|
||||
// 生成4路测试数据的函数
|
||||
export function generateTestData(): LogicDataType {
|
||||
// 生成时间轴数据 (0-100ns,每1ns一个采样点)
|
||||
const timePoints = Array.from({ length: 101 }, (_, i) => i);
|
||||
|
||||
return {
|
||||
x: timePoints,
|
||||
y: [
|
||||
{
|
||||
enabled: true,
|
||||
type: "logic",
|
||||
name: "CLK",
|
||||
color: "#ff0000",
|
||||
value: timePoints.map((t) => t % 2), // 时钟信号,每1ns翻转
|
||||
base: "bin",
|
||||
},
|
||||
{
|
||||
enabled: true,
|
||||
type: "logic",
|
||||
name: "RESET",
|
||||
color: "#00ff00",
|
||||
value: timePoints.map((t) => (t < 10 ? 1 : 0)), // 复位信号,前10ns为高电平
|
||||
base: "bin",
|
||||
},
|
||||
{
|
||||
enabled: true,
|
||||
type: "number",
|
||||
name: "DATA",
|
||||
color: "#0000ff",
|
||||
value: timePoints.map((t) => Math.floor(t / 4) % 16), // 计数器,每4ns递增
|
||||
base: "hex",
|
||||
},
|
||||
{
|
||||
enabled: true,
|
||||
type: "logic",
|
||||
name: "ENABLE",
|
||||
color: "#ff8800",
|
||||
value: timePoints.map((t) => (t >= 20 && t < 80 ? 1 : 0)), // 使能信号,20-80ns为高电平
|
||||
base: "bin",
|
||||
},
|
||||
],
|
||||
xUnit: "ns",
|
||||
};
|
||||
}
|
||||
|
||||
const [useProvideWaveformManager, useWaveformManager] = createInjectionState(
|
||||
() => {
|
||||
const logicData = shallowRef<LogicDataType>();
|
||||
|
||||
return {
|
||||
logicData,
|
||||
generateTestData,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export { useProvideWaveformManager, useWaveformManager };
|
|
@ -1,5 +1,61 @@
|
|||
import WaveformDisplay from "./WaveformDisplay.vue";
|
||||
|
||||
export {
|
||||
WaveformDisplay
|
||||
export type LogicDataType = {
|
||||
x: number[];
|
||||
y: {
|
||||
enabled: boolean;
|
||||
type: "logic" | "number";
|
||||
name: string;
|
||||
color: string;
|
||||
value: number[];
|
||||
base: "bin" | "dec" | "hex";
|
||||
}[];
|
||||
xUnit: "s" | "ms" | "us" | "ns";
|
||||
};
|
||||
|
||||
// 生成4路测试数据的函数
|
||||
export function generateTestData(): LogicDataType {
|
||||
// 生成时间轴数据 (0-100ns,每1ns一个采样点)
|
||||
const timePoints = Array.from({ length: 101 }, (_, i) => i);
|
||||
|
||||
return {
|
||||
x: timePoints,
|
||||
y: [
|
||||
{
|
||||
enabled: true,
|
||||
type: "logic",
|
||||
name: "CLK",
|
||||
color: "#ff0000",
|
||||
value: timePoints.map((t) => t % 2), // 时钟信号,每1ns翻转
|
||||
base: "bin",
|
||||
},
|
||||
{
|
||||
enabled: true,
|
||||
type: "logic",
|
||||
name: "RESET",
|
||||
color: "#00ff00",
|
||||
value: timePoints.map((t) => (t < 10 ? 1 : 0)), // 复位信号,前10ns为高电平
|
||||
base: "bin",
|
||||
},
|
||||
{
|
||||
enabled: true,
|
||||
type: "number",
|
||||
name: "DATA",
|
||||
color: "#0000ff",
|
||||
value: timePoints.map((t) => Math.floor(t / 4) % 16), // 计数器,每4ns递增
|
||||
base: "hex",
|
||||
},
|
||||
{
|
||||
enabled: true,
|
||||
type: "logic",
|
||||
name: "ENABLE",
|
||||
color: "#ff8800",
|
||||
value: timePoints.map((t) => (t >= 20 && t < 80 ? 1 : 0)), // 使能信号,20-80ns为高电平
|
||||
base: "bin",
|
||||
},
|
||||
],
|
||||
xUnit: "ns",
|
||||
};
|
||||
}
|
||||
|
||||
export { WaveformDisplay };
|
||||
|
|
|
@ -103,15 +103,11 @@ import { isNull, toNumber } from "lodash";
|
|||
import { onMounted, ref, watch } from "vue";
|
||||
import Debugger from "./Debugger.vue";
|
||||
import { useProvideLogicAnalyzer } from "@/components/LogicAnalyzer";
|
||||
import { useProvideWaveformManager } from "@/components/WaveformDisplay/WaveformManager";
|
||||
import { useProvideOscilloscope } from "@/components/Oscilloscope/OscilloscopeManager";
|
||||
|
||||
const analyzer = useProvideLogicAnalyzer();
|
||||
const waveformManager = useProvideWaveformManager();
|
||||
const oscilloscopeManager = useProvideOscilloscope();
|
||||
|
||||
waveformManager.logicData.value = waveformManager.generateTestData();
|
||||
|
||||
const checkID = useLocalStorage("checkID", 1);
|
||||
|
||||
// 定义事件
|
||||
|
|
Loading…
Reference in New Issue