feat: frontend add virtual matrix key

This commit is contained in:
2025-05-20 17:09:57 +08:00
parent b68d8eaf11
commit bea1c7e5ae
15 changed files with 689 additions and 106 deletions

View File

@@ -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<Title>("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,

View File

@@ -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,
}
})