From d754a881d7cd0cba51eec3287d667f270faad9e5 Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Mon, 19 May 2025 21:18:22 +0800 Subject: [PATCH] feat: frontend add set jtag frequency --- server/src/Controllers.cs | 26 ++++++- server/src/JtagClient.cs | 22 +++++- src/APIClient.ts | 69 +++++++++++++++++++ src/components/equipments/MotherBoard.vue | 8 ++- src/components/equipments/MotherBoardCaps.vue | 54 ++++++++++++--- src/stores/equipments.ts | 21 +++++- 6 files changed, 184 insertions(+), 16 deletions(-) diff --git a/server/src/Controllers.cs b/server/src/Controllers.cs index 89d31aa..8c976db 100644 --- a/server/src/Controllers.cs +++ b/server/src/Controllers.cs @@ -367,7 +367,6 @@ public class JtagController : ControllerBase [HttpPost("BoundaryScanLogicalPorts")] [EnableCors("Users")] [ProducesResponseType(typeof(Dictionary), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] public async ValueTask BoundaryScanLogicalPorts(string address, int port) { @@ -382,6 +381,31 @@ public class JtagController : ControllerBase return TypedResults.Ok(ret.Value); } + + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:return] + [HttpPost("SetSpeed")] + [EnableCors("Users")] + [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] + public async ValueTask SetSpeed(string address, int port, UInt32 speed) + { + var jtagCtrl = new JtagClient.Jtag(address, port); + var ret = await jtagCtrl.SetSpeed(speed); + if (!ret.IsSuccessful) + { + if (ret.Error is ArgumentException) + return TypedResults.BadRequest(ret.Error); + else return TypedResults.InternalServerError(ret.Error); + } + + return TypedResults.Ok(ret.Value); + } } /// diff --git a/server/src/JtagClient.cs b/server/src/JtagClient.cs index 27a8a17..e14fa6c 100644 --- a/server/src/JtagClient.cs +++ b/server/src/JtagClient.cs @@ -28,6 +28,10 @@ public static class JtagAddr /// Jtag Write Command /// public const UInt32 WRITE_CMD = 0x10_00_00_03; + /// + /// Jtag Speed Control + /// + public const UInt32 SPEED_CTRL = 0x10_00_00_04; } /// @@ -833,10 +837,26 @@ public class Jtag if (cellList.IsNull) return new(new Exception("Get boundary logical ports failed")); var portStatus = new Dictionary(); - foreach (var cell in cellList.Value) { + foreach (var cell in cellList.Value) + { portStatus.Add(cell.PortID ?? "UnknownPortID", bitArray.Value[cell.CellNumber]); } return portStatus; } + + public async ValueTask> SetSpeed(UInt32 speed) + { + // Clear Data + await MsgBus.UDPServer.ClearUDPData(this.address); + + logger.Trace($"Clear up udp server {this.address} receive data"); + + var ret = await WriteFIFO( + JtagAddr.SPEED_CTRL, (speed << 16) | speed, + JtagState.CMD_EXEC_FINISH, JtagState.CMD_EXEC_FINISH); + + if (!ret.IsSuccessful) return new (ret.Error); + return ret.Value; + } } diff --git a/src/APIClient.ts b/src/APIClient.ts index 42c25fd..1efd437 100644 --- a/src/APIClient.ts +++ b/src/APIClient.ts @@ -724,6 +724,75 @@ export class JtagClient { } return Promise.resolve<{ [key: string]: boolean; }>(null as any); } + + /** + * [TODO:description] + * @param address (optional) [TODO:parameter] + * @param port (optional) [TODO:parameter] + * @param speed (optional) [TODO:parameter] + * @return [TODO:return] + */ + setSpeed(address: string | undefined, port: number | undefined, speed: number | undefined): Promise { + let url_ = this.baseUrl + "/api/Jtag/SetSpeed?"; + if (address === null) + throw new Error("The parameter 'address' cannot be null."); + else if (address !== undefined) + url_ += "address=" + encodeURIComponent("" + address) + "&"; + if (port === null) + throw new Error("The parameter 'port' cannot be null."); + else if (port !== undefined) + url_ += "port=" + encodeURIComponent("" + port) + "&"; + if (speed === null) + throw new Error("The parameter 'speed' cannot be null."); + else if (speed !== undefined) + url_ += "speed=" + encodeURIComponent("" + speed) + "&"; + url_ = url_.replace(/[?&]$/, ""); + + let options_: RequestInit = { + method: "POST", + headers: { + "Accept": "application/json" + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processSetSpeed(_response); + }); + } + + protected processSetSpeed(response: Response): Promise { + 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 : 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 = resultData400 !== undefined ? resultData400 : null; + + return throwException("A server side error occurred.", status, _responseText, _headers, result400); + }); + } else if (status === 500) { + return response.text().then((_responseText) => { + let result500: any = null; + let resultData500 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); + result500 = Exception.fromJS(resultData500); + return throwException("A server side error occurred.", status, _responseText, _headers, result500); + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null as any); + } } export class RemoteUpdateClient { diff --git a/src/components/equipments/MotherBoard.vue b/src/components/equipments/MotherBoard.vue index 3003d0f..ffbf60f 100644 --- a/src/components/equipments/MotherBoard.vue +++ b/src/components/equipments/MotherBoard.vue @@ -10,7 +10,8 @@ - + @@ -35,6 +36,11 @@ const emit = defineEmits<{ const props = withDefaults(defineProps(), getDefaultProps()); const selectecComponentID = inject(CanvasCurrentSelectedComponentID, ref(null)); +const jtagFreq = ref("25 MHz"); +function changeJtagFreq(text: string) { + jtagFreq.value = text; +} + // 计算实际宽高 const width = computed(() => 800 * props.size); const height = computed(() => 600 * props.size); diff --git a/src/components/equipments/MotherBoardCaps.vue b/src/components/equipments/MotherBoardCaps.vue index c517d1f..fd229c5 100644 --- a/src/components/equipments/MotherBoardCaps.vue +++ b/src/components/equipments/MotherBoardCaps.vue @@ -5,7 +5,9 @@

Jtag Addr: {{ eqps.boardAddr }}

Jtag Port: {{ eqps.boardPort.toString() }}

-

IDCode: 0x{{ jtagIDCode.toString(16).padStart(8, "0").toUpperCase() }}

+

+ IDCode: 0x{{ jtagIDCode.toString(16).padStart(8, "0").toUpperCase() }} +

+
+ Jtag运行频率 + +
+
+
+ 边界扫描刷新率 / Hz + +

输入一个1 ~ 1000的数

+
+ +
@@ -45,10 +57,24 @@ import { computed, ref, watchEffect } from "vue"; interface CapsProps { jtagAddr?: string; jtagPort?: number; + jtagFreq?: string; } +const emits = defineEmits<{ + changeJtagFreq: [text: string]; +}>(); const props = withDefaults(defineProps(), {}); +const selectJtagSpeedOptions = ref([ + { text: "25 MHz", id: 1 }, + { text: "12.5 MHz", id: 2 }, + { text: "6.25 MHz", id: 3 }, + { text: "3.125 MHz", id: 4 }, + { text: "1562.5 KHz", id: 5 }, + { text: "781.25 KHz", id: 6 }, + { text: "390.625 KHz", id: 7 }, +]); + // Global Stores const dialog = useDialogStore(); const eqps = useEquipments(); @@ -68,6 +94,12 @@ function handleBitstreamChange(file: File | undefined) { eqps.jtagBitstream = file; } +function handleSelectJtagSpeed(event: Event) { + const target = event.target as HTMLSelectElement; + eqps.jtagSetSpeed(target.selectedIndex); + emits("changeJtagFreq", target.value); +} + async function toggleJtagBoundaryScan() { if (eqps.jtagClientMutex.isLocked()) { dialog.warn("Jtag正在被占用"); diff --git a/src/stores/equipments.ts b/src/stores/equipments.ts index a727f08..0233356 100644 --- a/src/stores/equipments.ts +++ b/src/stores/equipments.ts @@ -17,8 +17,8 @@ export const useEquipments = defineStore('equipments', () => { const boardAddr = ref("127.0.0.1"); const boardPort = ref(1234); const jtagBitstream = ref(); - const jtagBoundaryScanFreq = ref(10); - const jtagClientMutex = withTimeout(new Mutex(), 2000, new Error("JtagClient Mutex Timeout!")) + const jtagBoundaryScanFreq = ref(100); + const jtagClientMutex = withTimeout(new Mutex(), 1000, new Error("JtagClient Mutex Timeout!")) const jtagClient = new JtagClient(); const enableJtagBoundaryScan = ref(false); @@ -121,6 +121,22 @@ export const useEquipments = defineStore('equipments', () => { } } + async function jtagSetSpeed(speed: number): Promise { + const release = await jtagClientMutex.acquire(); + try { + const resp = await jtagClient.setSpeed( + boardAddr.value, + boardPort.value, + speed + ); + return resp; + } catch (e) { + dialog.error("设置Jtag速度失败"); + return false; + } finally { + release(); + } + } return { boardAddr, @@ -134,6 +150,7 @@ export const useEquipments = defineStore('equipments', () => { jtagUploadBitstream, jtagDownloadBitstream, jtagGetIDCode, + jtagSetSpeed, enableJtagBoundaryScan, } })