import { ref, reactive, watchPostEffect, onMounted, onUnmounted } from "vue"; import { defineStore } from "pinia"; import { useLocalStorage } from "@vueuse/core"; import { isString, toNumber, type Dictionary } from "lodash"; import z from "zod"; import { isNumber } from "mathjs"; import { Mutex, withTimeout } from "async-mutex"; import { useConstraintsStore } from "@/stores/constraints"; import { useDialogStore } from "./dialog"; import { toFileParameterOrUndefined } from "@/utils/Common"; import { AuthManager } from "@/utils/AuthManager"; import { HubConnectionBuilder } from "@microsoft/signalr"; import { getHubProxyFactory, getReceiverRegister } from "@/TypedSignalR.Client"; export const useEquipments = defineStore("equipments", () => { // Global Stores const constrainsts = useConstraintsStore(); const dialog = useDialogStore(); const boardAddr = useLocalStorage("fpga-board-addr", "127.0.0.1"); const boardPort = useLocalStorage("fpga-board-port", 1234); // Jtag const jtagBitstream = ref(); const jtagBoundaryScanFreq = ref(100); const jtagClientMutex = withTimeout( new Mutex(), 1000, new Error("JtagClient Mutex Timeout!"), ); const jtagHubConnection = new HubConnectionBuilder() .withUrl("/hubs/JtagHub") .withAutomaticReconnect() .build(); const jtagHubProxy = getHubProxyFactory("IJtagHub").createHubProxy(jtagHubConnection); const jtagHubSubscription = getReceiverRegister("IJtagReceiver").register( jtagHubConnection, { onReceiveBoundaryScanData: async (msg) => { constrainsts.batchSetConstraintStates(msg); }, }, ); onMounted(() => { jtagHubConnection.start(); }); // Matrix Key const matrixKeyStates = reactive(new Array(16).fill(false)); const matrixKeypadClientMutex = withTimeout( new Mutex(), 1000, new Error("Matrixkeyclient Mutex Timeout!"), ); // Power const powerClientMutex = withTimeout( new Mutex(), 1000, new Error("Matrixkeyclient Mutex Timeout!"), ); // Enable Setting const enableJtagBoundaryScan = ref(false); const enableMatrixKey = ref(false); const enablePower = ref(false); 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[_keyNum] = keyValue; return true; } return false; } async function jtagBoundaryScanSetOnOff(enable: boolean) { enableJtagBoundaryScan.value = enable; if (enable) { jtagHubProxy.startBoundaryScan(jtagBoundaryScanFreq.value); } else { jtagHubProxy.stopBoundaryScan(); } } async function jtagUploadBitstream(bitstream: File): Promise { try { // 自动开启电源 await powerSetOnOff(true); const jtagClient = AuthManager.createAuthenticatedJtagClient(); const resp = await jtagClient.uploadBitstream( boardAddr.value, toFileParameterOrUndefined(bitstream), ); return resp; } catch (e) { dialog.error("上传错误"); console.error(e); return false; } } async function jtagDownloadBitstream(): Promise { const release = await jtagClientMutex.acquire(); try { // 自动开启电源 await powerSetOnOff(true); const jtagClient = AuthManager.createAuthenticatedJtagClient(); const resp = await jtagClient.downloadBitstream( boardAddr.value, boardPort.value, ); return resp; } catch (e) { dialog.error("上传错误"); console.error(e); return false; } finally { release(); } } async function jtagGetIDCode(isQuiet: boolean = false): Promise { const release = await jtagClientMutex.acquire(); try { // 自动开启电源 await powerSetOnOff(true); const jtagClient = AuthManager.createAuthenticatedJtagClient(); const resp = await jtagClient.getDeviceIDCode( boardAddr.value, boardPort.value, ); return resp; } catch (e) { if (!isQuiet) dialog.error("获取IDCode错误"); return 0xffff_ffff; } finally { release(); } } async function jtagSetSpeed(speed: number): Promise { const release = await jtagClientMutex.acquire(); try { // 自动开启电源 await powerSetOnOff(true); const jtagClient = AuthManager.createAuthenticatedJtagClient(); const resp = await jtagClient.setSpeed( boardAddr.value, boardPort.value, speed, ); return resp; } catch (e) { dialog.error("设置Jtag速度失败"); return false; } finally { release(); } } async function matrixKeypadSetKeyStates(keyStates: boolean[]) { const release = await matrixKeypadClientMutex.acquire(); console.log("set Key !!!!!!!!!!!!"); try { const matrixKeypadClient = AuthManager.createAuthenticatedMatrixKeyClient(); const resp = await matrixKeypadClient.setMatrixKeyStatus( boardAddr.value, boardPort.value, keyStates, ); return resp; } catch (e) { dialog.error("设置矩阵键盘时,服务器发生错误"); return false; } finally { release(); } } async function matrixKeypadEnable(enable: boolean) { const release = await matrixKeypadClientMutex.acquire(); try { if (enable) { const matrixKeypadClient = AuthManager.createAuthenticatedMatrixKeyClient(); const resp = await matrixKeypadClient.enabelMatrixKey( boardAddr.value, boardPort.value, ); enableMatrixKey.value = resp; return resp; } else { const matrixKeypadClient = AuthManager.createAuthenticatedMatrixKeyClient(); 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(); } } async function powerSetOnOff(enable: boolean) { const release = await powerClientMutex.acquire(); try { const powerClient = AuthManager.createAuthenticatedPowerClient(); const resp = await powerClient.setPowerOnOff( boardAddr.value, boardPort.value, enable, ); return resp; } catch (e) { dialog.error("无法开关电源"); console.error(e); return false; } finally { release(); } } return { boardAddr, boardPort, setMatrixKey, // Jtag enableJtagBoundaryScan, jtagBoundaryScanSetOnOff, jtagBitstream, jtagBoundaryScanFreq, jtagUploadBitstream, jtagDownloadBitstream, jtagGetIDCode, jtagSetSpeed, // Matrix Key enableMatrixKey, matrixKeyStates, matrixKeypadClientMutex, matrixKeypadEnable, matrixKeypadSetKeyStates, // Power enablePower, powerClientMutex, powerSetOnOff, }; });