From 1bdcb672ab7e302dc1ef35bf4ea96ab4ce8cdaa7 Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Tue, 20 May 2025 17:09:57 +0800 Subject: [PATCH] feat: frontend add virtual matrix key --- package-lock.json | 13 + package.json | 1 + public/EquipmentTemplates/MatrixKey.json | 298 ++++++++++++++++++ server/Program.cs | 1 + server/src/BsdlParser.cs | 5 +- server/src/Controllers/MatrixKeyController.cs | 6 +- src/APIClient.ts | 43 ++- src/components/ComponentSelector.vue | 10 + src/components/Dialog.vue | 1 + src/components/equipments/BaseBoard.vue | 42 +++ .../equipments/MechanicalButton.vue | 197 ++++++++---- src/components/equipments/MotherBoard.vue | 3 +- src/components/equipments/MotherBoardCaps.vue | 21 +- src/stores/dialog.ts | 45 ++- src/stores/equipments.ts | 109 ++++++- 15 files changed, 689 insertions(+), 106 deletions(-) create mode 100644 public/EquipmentTemplates/MatrixKey.json create mode 100644 src/components/equipments/BaseBoard.vue diff --git a/package-lock.json b/package-lock.json index 9dcaef7..75364d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "ts-results-es": "^5.0.1", "vue": "^3.5.13", "vue-router": "4", + "yocto-queue": "^1.2.1", "zod": "^3.24.2" }, "devDependencies": { @@ -4075,6 +4076,18 @@ "dev": true, "license": "ISC" }, + "node_modules/yocto-queue": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", + "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/yoctocolors": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.1.tgz", diff --git a/package.json b/package.json index ac7b8d0..1750b56 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "ts-results-es": "^5.0.1", "vue": "^3.5.13", "vue-router": "4", + "yocto-queue": "^1.2.1", "zod": "^3.24.2" }, "devDependencies": { diff --git a/public/EquipmentTemplates/MatrixKey.json b/public/EquipmentTemplates/MatrixKey.json new file mode 100644 index 0000000..7ec4cd4 --- /dev/null +++ b/public/EquipmentTemplates/MatrixKey.json @@ -0,0 +1,298 @@ +{ + "version": 1, + "author": "template", + "editor": "system", + "parts": [ + { + "id": "board", + "type": "BaseBoard", + "x": 0, + "y": 0, + "attrs": { + "size": 1.2, + "width": 400, + "height": 400, + "roundCorner": 20 + }, + "rotate": 0, + "group": "MatrixKeypad", + "positionlock": false, + "hidepins": false, + "isOn": true, + "index": 0 + }, + { + "id": "key_0_0", + "type": "MechanicalButton", + "x": 50, + "y": 50, + "attrs": { + "size": 0.5, + "bindKey": "1", + "pins": [] + }, + "rotate": 0, + "group": "MatrixKeypad", + "positionlock": false, + "hidepins": true, + "isOn": false, + "index": 0 + }, + { + "id": "key_0_1", + "type": "MechanicalButton", + "x": 150, + "y": 50, + "attrs": { + "size": 0.5, + "bindKey": "2", + "pins": [] + }, + "rotate": 0, + "group": "MatrixKeypad", + "positionlock": false, + "hidepins": true, + "isOn": false, + "index": 1 + }, + { + "id": "key_0_2", + "type": "MechanicalButton", + "x": 250, + "y": 50, + "attrs": { + "size": 0.5, + "bindKey": "3", + "pins": [] + }, + "rotate": 0, + "group": "MatrixKeypad", + "positionlock": false, + "hidepins": true, + "isOn": false, + "index": 2 + }, + { + "id": "key_0_3", + "type": "MechanicalButton", + "x": 350, + "y": 50, + "attrs": { + "size": 0.5, + "bindKey": "A", + "pins": [] + }, + "rotate": 0, + "group": "MatrixKeypad", + "positionlock": false, + "hidepins": true, + "isOn": false, + "index": 3 + }, + { + "id": "key_1_0", + "type": "MechanicalButton", + "x": 50, + "y": 150, + "attrs": { + "size": 0.5, + "bindKey": "4", + "pins": [] + }, + "rotate": 0, + "group": "MatrixKeypad", + "positionlock": false, + "hidepins": true, + "isOn": false, + "index": 4 + }, + { + "id": "key_1_1", + "type": "MechanicalButton", + "x": 150, + "y": 150, + "attrs": { + "size": 0.5, + "bindKey": "5", + "pins": [] + }, + "rotate": 0, + "group": "MatrixKeypad", + "positionlock": false, + "hidepins": true, + "isOn": false, + "index": 5 + }, + { + "id": "key_1_2", + "type": "MechanicalButton", + "x": 250, + "y": 150, + "attrs": { + "size": 0.5, + "bindKey": "6", + "pins": [] + }, + "rotate": 0, + "group": "MatrixKeypad", + "positionlock": false, + "hidepins": true, + "isOn": false, + "index": 6 + }, + { + "id": "key_1_3", + "type": "MechanicalButton", + "x": 350, + "y": 150, + "attrs": { + "size": 0.5, + "bindKey": "B", + "pins": [] + }, + "rotate": 0, + "group": "MatrixKeypad", + "positionlock": false, + "hidepins": true, + "isOn": false, + "index": 7 + }, + { + "id": "key_2_0", + "type": "MechanicalButton", + "x": 50, + "y": 250, + "attrs": { + "size": 0.5, + "bindKey": "7", + "pins": [] + }, + "rotate": 0, + "group": "MatrixKeypad", + "positionlock": false, + "hidepins": true, + "isOn": false, + "index": 8 + }, + { + "id": "key_2_1", + "type": "MechanicalButton", + "x": 150, + "y": 250, + "attrs": { + "size": 0.5, + "bindKey": "8", + "pins": [] + }, + "rotate": 0, + "group": "MatrixKeypad", + "positionlock": false, + "hidepins": true, + "isOn": false, + "index": 9 + }, + { + "id": "key_2_2", + "type": "MechanicalButton", + "x": 250, + "y": 250, + "attrs": { + "size": 0.5, + "bindKey": "9", + "pins": [] + }, + "rotate": 0, + "group": "MatrixKeypad", + "positionlock": false, + "hidepins": true, + "isOn": false, + "index": 10 + }, + { + "id": "key_2_3", + "type": "MechanicalButton", + "x": 350, + "y": 250, + "attrs": { + "size": 0.5, + "bindKey": "C", + "pins": [] + }, + "rotate": 0, + "group": "MatrixKeypad", + "positionlock": false, + "hidepins": true, + "isOn": false, + "index": 11 + }, + { + "id": "key_3_0", + "type": "MechanicalButton", + "x": 50, + "y": 350, + "attrs": { + "size": 0.5, + "bindKey": "*", + "pins": [] + }, + "rotate": 0, + "group": "MatrixKeypad", + "positionlock": false, + "hidepins": true, + "isOn": false, + "index": 12 + }, + { + "id": "key_3_1", + "type": "MechanicalButton", + "x": 150, + "y": 350, + "attrs": { + "size": 0.5, + "bindKey": "0", + "pins": [] + }, + "rotate": 0, + "group": "MatrixKeypad", + "positionlock": false, + "hidepins": true, + "isOn": false, + "index": 13 + }, + { + "id": "key_3_2", + "type": "MechanicalButton", + "x": 250, + "y": 350, + "attrs": { + "size": 0.5, + "bindKey": "#", + "pins": [] + }, + "rotate": 0, + "group": "MatrixKeypad", + "positionlock": false, + "hidepins": true, + "isOn": false, + "index": 14 + }, + { + "id": "key_3_3", + "type": "MechanicalButton", + "x": 350, + "y": 350, + "attrs": { + "size": 0.5, + "bindKey": "D", + "pins": [] + }, + "rotate": 0, + "group": "MatrixKeypad", + "positionlock": false, + "hidepins": true, + "isOn": false, + "index": 15 + } + ], + "connections": [] +} diff --git a/server/Program.cs b/server/Program.cs index e54b1cd..c40d13f 100644 --- a/server/Program.cs +++ b/server/Program.cs @@ -52,6 +52,7 @@ try { options.AddPolicy("Users", policy => policy .AllowAnyOrigin() + .AllowAnyHeader() ); }); diff --git a/server/src/BsdlParser.cs b/server/src/BsdlParser.cs index 70645f0..4f8ff35 100644 --- a/server/src/BsdlParser.cs +++ b/server/src/BsdlParser.cs @@ -26,7 +26,7 @@ public class BoundaryScanRegs /// [JsonProperty("cell_name")] [JsonRequired] - public string CellName { get; set; } + public string CellName { get; set; } = "UnknownCellName"; /// /// [TODO:description] @@ -146,7 +146,8 @@ public class Parser /// [TODO:return] public Optional> GetBoundaryLogicalPorts() { - var registers = this.BoundaryRegsDesp["registers"]?.ToList().Where((item)=>{ + var registers = this.BoundaryRegsDesp["registers"]?.ToList().Where((item) => + { return item["port_id"] is not null; }); if (registers is null) return new(); diff --git a/server/src/Controllers/MatrixKeyController.cs b/server/src/Controllers/MatrixKeyController.cs index 6f40cdb..dbb10f5 100644 --- a/server/src/Controllers/MatrixKeyController.cs +++ b/server/src/Controllers/MatrixKeyController.cs @@ -21,7 +21,7 @@ public class MatrixKeyController : ControllerBase /// 返回操作结果的状态码 [HttpPost("EnabelMatrixKey")] [EnableCors("Users")] - [ProducesResponseType(typeof(uint), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)] [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] public async ValueTask EnabelMatrixKey(string address, int port) { @@ -48,7 +48,7 @@ public class MatrixKeyController : ControllerBase /// 返回操作结果的状态码 [HttpPost("DisableMatrixKey")] [EnableCors("Users")] - [ProducesResponseType(typeof(uint), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)] [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] public async ValueTask DisableMatrixKey(string address, int port) { @@ -76,7 +76,7 @@ public class MatrixKeyController : ControllerBase /// 返回操作结果的状态码 [HttpPost("SetMatrixKeyStatus")] [EnableCors("Users")] - [ProducesResponseType(typeof(uint), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)] [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] public async ValueTask SetMatrixKeyStatus(string address, int port, [FromBody] bool[] keyStates) { diff --git a/src/APIClient.ts b/src/APIClient.ts index 0cbb72b..83383ad 100644 --- a/src/APIClient.ts +++ b/src/APIClient.ts @@ -955,7 +955,13 @@ export class MatrixKeyClient { this.baseUrl = baseUrl ?? "http://localhost:5000"; } - enabelMatrixKey(address: string | undefined, port: number | undefined): Promise { + /** + * 启用矩阵键控制。 + * @param address (optional) 设备的IP地址 + * @param port (optional) 设备的端口号 + * @return 返回操作结果的状态码 + */ + enabelMatrixKey(address: string | undefined, port: number | undefined): Promise { let url_ = this.baseUrl + "/api/MatrixKey/EnabelMatrixKey?"; if (address === null) throw new Error("The parameter 'address' cannot be null."); @@ -968,7 +974,7 @@ export class MatrixKeyClient { url_ = url_.replace(/[?&]$/, ""); let options_: RequestInit = { - method: "GET", + method: "POST", headers: { "Accept": "application/json" } @@ -979,7 +985,7 @@ export class MatrixKeyClient { }); } - protected processEnabelMatrixKey(response: Response): Promise { + protected processEnabelMatrixKey(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) { @@ -1002,10 +1008,16 @@ export class MatrixKeyClient { return throwException("An unexpected server error occurred.", status, _responseText, _headers); }); } - return Promise.resolve(null as any); + return Promise.resolve(null as any); } - disableMatrixKey(address: string | undefined, port: number | undefined): Promise { + /** + * 禁用矩阵键控制。 + * @param address (optional) 设备的IP地址 + * @param port (optional) 设备的端口号 + * @return 返回操作结果的状态码 + */ + disableMatrixKey(address: string | undefined, port: number | undefined): Promise { let url_ = this.baseUrl + "/api/MatrixKey/DisableMatrixKey?"; if (address === null) throw new Error("The parameter 'address' cannot be null."); @@ -1018,7 +1030,7 @@ export class MatrixKeyClient { url_ = url_.replace(/[?&]$/, ""); let options_: RequestInit = { - method: "GET", + method: "POST", headers: { "Accept": "application/json" } @@ -1029,7 +1041,7 @@ export class MatrixKeyClient { }); } - protected processDisableMatrixKey(response: Response): Promise { + protected processDisableMatrixKey(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) { @@ -1052,10 +1064,17 @@ export class MatrixKeyClient { return throwException("An unexpected server error occurred.", status, _responseText, _headers); }); } - return Promise.resolve(null as any); + return Promise.resolve(null as any); } - setMatrixKeyStatus(address: string | undefined, port: number | undefined, keyStates: boolean[]): Promise { + /** + * 设置矩阵键的状态。 + * @param address (optional) 设备的IP地址 + * @param port (optional) 设备的端口号 + * @param keyStates 矩阵键的状态数组,长度应为16 + * @return 返回操作结果的状态码 + */ + setMatrixKeyStatus(address: string | undefined, port: number | undefined, keyStates: boolean[]): Promise { let url_ = this.baseUrl + "/api/MatrixKey/SetMatrixKeyStatus?"; if (address === null) throw new Error("The parameter 'address' cannot be null."); @@ -1071,7 +1090,7 @@ export class MatrixKeyClient { let options_: RequestInit = { body: content_, - method: "GET", + method: "POST", headers: { "Content-Type": "application/json", "Accept": "application/json" @@ -1083,7 +1102,7 @@ export class MatrixKeyClient { }); } - protected processSetMatrixKeyStatus(response: Response): Promise { + protected processSetMatrixKeyStatus(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) { @@ -1106,7 +1125,7 @@ export class MatrixKeyClient { return throwException("An unexpected server error occurred.", status, _responseText, _headers); }); } - return Promise.resolve(null as any); + return Promise.resolve(null as any); } } diff --git a/src/components/ComponentSelector.vue b/src/components/ComponentSelector.vue index 8153330..b477ed9 100644 --- a/src/components/ComponentSelector.vue +++ b/src/components/ComponentSelector.vue @@ -182,6 +182,7 @@ diff --git a/src/components/equipments/MechanicalButton.vue b/src/components/equipments/MechanicalButton.vue index b167845..6c92e42 100644 --- a/src/components/equipments/MechanicalButton.vue +++ b/src/components/equipments/MechanicalButton.vue @@ -1,16 +1,28 @@ @@ -80,16 +131,16 @@ diff --git a/src/components/equipments/MotherBoard.vue b/src/components/equipments/MotherBoard.vue index ffbf60f..f95fcb9 100644 --- a/src/components/equipments/MotherBoard.vue +++ b/src/components/equipments/MotherBoard.vue @@ -23,7 +23,7 @@ import { toNumber } from "lodash"; // 主板特有属性 export interface MotherBoardProps { - size?: number; + size: number; boardAddr?: string; boardPort?: string; componentId?: string; @@ -63,7 +63,6 @@ export function getDefaultProps(): MotherBoardProps { size: 1, boardAddr: "127.0.0.1", boardPort: "1234", - componentId: "DefaultMotherBoardID", }; } diff --git a/src/components/equipments/MotherBoardCaps.vue b/src/components/equipments/MotherBoardCaps.vue index fd229c5..351422d 100644 --- a/src/components/equipments/MotherBoardCaps.vue +++ b/src/components/equipments/MotherBoardCaps.vue @@ -44,6 +44,12 @@ {{ eqps.enableJtagBoundaryScan ? "关闭边界扫描" : "启动边界扫描" }} +
+

外设

+
+ +

启用矩阵键盘

+
@@ -52,7 +58,7 @@ import z from "zod"; import UploadCard from "@/components/UploadCard.vue"; import { useDialogStore } from "@/stores/dialog"; import { useEquipments } from "@/stores/equipments"; -import { computed, ref, watchEffect } from "vue"; +import { computed, ref, watchEffect, watchPostEffect } from "vue"; interface CapsProps { jtagAddr?: string; @@ -100,6 +106,19 @@ function handleSelectJtagSpeed(event: Event) { emits("changeJtagFreq", target.value); } +async function handleMatrixkeyCheckboxChange(event: Event) { + const target = event.target as HTMLInputElement; + if (target.checked) { + const ret = await eqps.matrixKeypadEnable(true); + if (!ret) { + } + } else { + const ret = await eqps.matrixKeypadEnable(false); + if (!ret) { + } + } +} + async function toggleJtagBoundaryScan() { if (eqps.jtagClientMutex.isLocked()) { dialog.warn("Jtag正在被占用"); diff --git a/src/stores/dialog.ts b/src/stores/dialog.ts index 0e1589a..3fd6437 100644 --- a/src/stores/dialog.ts +++ b/src/stores/dialog.ts @@ -1,40 +1,61 @@ -import { ref, computed } from 'vue' +import { ref, reactive, watchPostEffect, computed } from 'vue' import { defineStore } from 'pinia' import { isUndefined } from 'lodash'; +import Queue from 'yocto-queue'; export const useDialogStore = defineStore('dialog', () => { type Title = "Error" | "Info" | "Warn"; + const enableDialog = ref(false); const isDialogOpen = ref(false); const dialogTitle = ref("Error"); const dialogContent = ref("这是一个错误"); + const contentQueue = new Queue<{ type: Title; content: string }>() - function openDialog(title: Title, content?: string) { - if (!isUndefined(content) && content.length != 0) - dialogContent.value = content; - dialogTitle.value = title; - isDialogOpen.value = true; + function openDialog(title?: Title, content?: string) { + if (isUndefined(title)) { + if (contentQueue.size != 0) { + const dialog = contentQueue.dequeue(); + if (isUndefined(dialog)) return; + openDialog(dialog.type, dialog.content); + } + } else { + if (!isUndefined(content) && content.length != 0) + dialogContent.value = content; + dialogTitle.value = title; + isDialogOpen.value = true; + } } function closeDialog() { isDialogOpen.value = false; + + openDialog(); } - function info(content?: string) { - openDialog("Info", content); + function info(content: string) { + contentQueue.enqueue({ type: "Info", content: content }); + openDialog(); + // openDialog("Info", content); } - function error(content?: string) { - openDialog("Error", content); + function error(content: string) { + contentQueue.enqueue({ type: "Error", content: content }); + openDialog(); + // openDialog("Error", content); } - function warn(content?: string) { - openDialog("Warn", content); + function warn(content: string) { + contentQueue.enqueue({ type: "Warn", content: content }); + openDialog(); + // openDialog("Warn", content); } return { + enableDialog, isDialogOpen, dialogTitle, dialogContent, + dialogQueue: contentQueue, openDialog, closeDialog, info, diff --git a/src/stores/equipments.ts b/src/stores/equipments.ts index 0233356..ae6b2f9 100644 --- a/src/stores/equipments.ts +++ b/src/stores/equipments.ts @@ -1,10 +1,10 @@ -import { ref, watchEffect } from 'vue' +import { ref, watchEffect, watchPostEffect } from 'vue' import { defineStore } from 'pinia' import { isString, toNumber, isUndefined } from 'lodash'; import { Common } from '@/Common'; import z from "zod" import { isNumber } from 'mathjs'; -import { JtagClient } from "@/APIClient"; +import { JtagClient, MatrixKeyClient } from "@/APIClient"; import { Mutex, withTimeout } from 'async-mutex'; import { useConstraintsStore } from "@/stores/constraints"; import { useDialogStore } from './dialog'; @@ -14,15 +14,41 @@ export const useEquipments = defineStore('equipments', () => { const constrainsts = useConstraintsStore(); const dialog = useDialogStore(); + // Basic Info const boardAddr = ref("127.0.0.1"); const boardPort = ref(1234); + + // Jtag const jtagBitstream = ref<File>(); const jtagBoundaryScanFreq = ref(100); const jtagClientMutex = withTimeout(new Mutex(), 1000, new Error("JtagClient Mutex Timeout!")) const jtagClient = new JtagClient(); - const enableJtagBoundaryScan = ref(false); + // Matrix Key + const matrixKeyStates = ref(new Array<boolean>(16).fill(false)) + const matrixKeypadClientMutex = withTimeout(new Mutex(), 1000, new Error("Matrixkeyclient Mutex Timeout!")); + const matrixKeypadClient = new MatrixKeyClient(); + // Enable Setting + const enableJtagBoundaryScan = ref(false); + const enableMatrixKey = ref(false); + + // Watch + watchPostEffect(async () => { + if (true === enableJtagBoundaryScan.value) jtagBoundaryScan(); + }); + + watchPostEffect(async () => { + if (true === enableMatrixKey.value) { + const ret = await matrixKeypadSetKeyStates(matrixKeyStates.value) + if (!ret) { + dialog.error("设置矩阵键盘失败") + enableMatrixKey.value = false; + } + } + }) + + // Parse and Set function setAddr(address: string | undefined): boolean { if (isString(address) && z.string().ip("4").safeParse(address).success) { boardAddr.value = address; @@ -49,9 +75,23 @@ export const useEquipments = defineStore('equipments', () => { return false; } - watchEffect(() => { - if (enableJtagBoundaryScan.value) jtagBoundaryScan(); - }); + function setMatrixKey(keyNum: number | string | undefined, keyValue: boolean): boolean { + + let _keyNum: number; + if (isString(keyNum)) { + _keyNum = toNumber(keyNum); + } else if (isNumber(keyNum)) { + _keyNum = keyNum; + } else { + return false; + } + + if (z.number().nonnegative().max(16).safeParse(_keyNum).success) { + matrixKeyStates.value[_keyNum] = keyValue; + return true; + } + return false; + } async function jtagBoundaryScan() { const release = await jtagClientMutex.acquire(); @@ -138,11 +178,59 @@ export const useEquipments = defineStore('equipments', () => { } } + async function matrixKeypadSetKeyStates(keyStates: boolean[]) { + const release = await matrixKeypadClientMutex.acquire(); + try { + const resp = await matrixKeypadClient.setMatrixKeyStatus( + boardAddr.value, + boardPort.value, + matrixKeyStates.value + ); + return resp; + } catch (e) { + dialog.error("设置矩阵键盘时,服务器发生错误"); + return false; + } finally { + release(); + } + } + + async function matrixKeypadEnable(enable: boolean) { + const release = await matrixKeypadClientMutex.acquire(); + try { + if (enable) { + const resp = await matrixKeypadClient.enabelMatrixKey( + boardAddr.value, + boardPort.value, + ); + enableMatrixKey.value = resp; + return resp; + } else { + const resp = await matrixKeypadClient.disableMatrixKey( + boardAddr.value, + boardPort.value, + ); + enableMatrixKey.value = !resp; + return resp; + } + } catch (e) { + enableMatrixKey.value = false; + dialog.error("设置矩阵键盘是否启用时,服务器发生错误"); + return false; + } finally { + release(); + } + } + return { boardAddr, boardPort, setAddr, setPort, + setMatrixKey, + + // Jtag + enableJtagBoundaryScan, jtagBitstream, jtagBoundaryScanFreq, jtagClientMutex, @@ -151,7 +239,14 @@ export const useEquipments = defineStore('equipments', () => { jtagDownloadBitstream, jtagGetIDCode, jtagSetSpeed, - enableJtagBoundaryScan, + + // Matrix Key + enableMatrixKey, + matrixKeyStates, + matrixKeypadClientMutex, + matrixKeypadClient, + matrixKeypadEnable, + matrixKeypadSetKeyStates, } })