fix: boundary scan could not save

This commit is contained in:
SikongJueluo 2025-05-19 18:47:15 +08:00
parent ba6ec73b84
commit a6ac728cf1
No known key found for this signature in database
7 changed files with 502 additions and 453 deletions

16
package-lock.json generated
View File

@ -10,6 +10,7 @@
"dependencies": {
"@svgdotjs/svg.js": "^3.2.4",
"@types/lodash": "^4.17.16",
"async-mutex": "^0.5.0",
"lodash": "^4.17.21",
"log-symbols": "^7.0.0",
"mathjs": "^14.4.0",
@ -2006,6 +2007,15 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/async-mutex": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz",
"integrity": "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==",
"license": "MIT",
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/autoprefixer": {
"version": "10.4.21",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz",
@ -3700,6 +3710,12 @@
"integrity": "sha512-HjX/7HxQe2bXkbp8pHTjy4Ir9eHIDnDDsLDphhGqy6I9iZ/vD4QXWEIlrVRZsEX+kS2jIiiF/mnl0nKnPTiYFw==",
"license": "MIT"
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/typed-function": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.2.1.tgz",

View File

@ -16,6 +16,7 @@
"dependencies": {
"@svgdotjs/svg.js": "^3.2.4",
"@types/lodash": "^4.17.16",
"async-mutex": "^0.5.0",
"lodash": "^4.17.21",
"log-symbols": "^7.0.0",
"mathjs": "^14.4.0",

File diff suppressed because it is too large Load Diff

View File

@ -99,7 +99,6 @@ async function handleClick(event: Event): Promise<void> {
isUploading.value = true;
try {
const ret = await props.uploadEvent(bitstream.value);
console.debug(`After upload bistream: ${bitstream.value}, result: ${ret}`);
if (isUndefined(props.downloadEvent)) {
if (ret) {
dialog.info("上传成功");

View File

@ -2,10 +2,10 @@
<div>
<h1 class="font-bold text-center text-2xl">Jtag</h1>
<div class="flex flex-col">
<p class="grow">Jtag Addr: {{ props.jtagAddr }}</p>
<p class="grow">Jtag Port: {{ props.jtagPort?.toString() }}</p>
<p class="grow">Jtag Addr: {{ eqps.boardAddr }}</p>
<p class="grow">Jtag Port: {{ eqps.boardPort.toString() }}</p>
<div class="flex justify-between grow">
<p>IDCode: 0x{{ jtagIDCode.toString(16).padStart(8, "0") }}</p>
<p>IDCode: 0x{{ jtagIDCode.toString(16).padStart(8, "0").toUpperCase() }}</p>
<button class="btn btn-circle w-6 h-6" :onclick="getIDCode">
<svg class="icon opacity-70 fill-primary" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="4865" width="200" height="200">
@ -17,27 +17,30 @@
</div>
</div>
<div class="divider"></div>
<UploadCard class="bg-base-200" :upload-event="uploadBitstream" :download-event="downloadBitstream"
:bitstream-file="eqps.jtagBitstream" @update:bitstream-file="handleBitstreamChange">
<UploadCard class="bg-base-200" :upload-event="eqps.jtagUploadBitstream"
:download-event="eqps.jtagDownloadBitstream" :bitstream-file="eqps.jtagBitstream"
@update:bitstream-file="handleBitstreamChange">
</UploadCard>
<div class="divider"></div>
<button class="btn w-full btn-primary" :class="isEnableJtagBoundaryScan ? '' : 'btn-soft'"
<fieldset class="fieldset w-full">
<legend class="fieldset-legend text-sm">边界扫描刷新率 / Hz</legend>
<input type="number" class="input validator w-full" required placeholder="Type a number between 1 to 1000" min="1"
max="1000" v-model="jtagBoundaryScanFreq" title="Type a number between 1 to 1000" />
<p class="validator-hint">输入一个1 ~ 1000的数</p>
</fieldset>
<button class="btn w-full btn-primary" :class="eqps.enableJtagBoundaryScan ? '' : 'btn-soft'"
:onclick="toggleJtagBoundaryScan">
{{ isEnableJtagBoundaryScan ? "关闭边界扫描" : "启动边界扫描" }}
{{ eqps.enableJtagBoundaryScan ? "关闭边界扫描" : "启动边界扫描" }}
</button>
</div>
</template>
<script lang="ts" setup>
import { JtagClient } from "@/APIClient";
import z from "zod";
import UploadCard from "@/components/UploadCard.vue";
import { useDialogStore } from "@/stores/dialog";
import { Common } from "@/Common";
import { useEquipments } from "@/stores/equipments";
import { useConstraintsStore } from "@/stores/constraints";
import { isUndefined } from "lodash";
import { ref, watchEffect } from "vue";
import { computed, ref, watchEffect } from "vue";
interface CapsProps {
jtagAddr?: string;
@ -48,107 +51,38 @@ const props = withDefaults(defineProps<CapsProps>(), {});
// Global Stores
const dialog = useDialogStore();
const constrainsts = useConstraintsStore();
const eqps = useEquipments();
const jtagController = new JtagClient();
const isEnableJtagBoundaryScan = ref(false);
const jtagBoundaryScanFreq = computed({
get: () => eqps.jtagBoundaryScanFreq,
set: (val) => {
if (z.number().positive().max(1000).safeParse(val).success)
eqps.jtagBoundaryScanFreq = val;
},
});
// 使
const jtagIDCode = ref(0);
const jtagIDCode = ref(0xffff_ffff);
function handleBitstreamChange(file: File | undefined) {
eqps.jtagBitstream = file;
}
async function toggleJtagBoundaryScan() {
isEnableJtagBoundaryScan.value = !isEnableJtagBoundaryScan.value;
if (isEnableJtagBoundaryScan.value) jtagBoundaryScan();
}
async function jtagBoundaryScan() {
try {
const portStates = await jtagController.boundaryScanLogicalPorts(
props.jtagAddr,
props.jtagPort,
);
constrainsts.batchSetConstraintStates(portStates);
} catch (error) {
dialog.error("边界扫描发生错误");
console.error(error);
isEnableJtagBoundaryScan.value = false;
} finally {
if (isEnableJtagBoundaryScan.value) setTimeout(jtagBoundaryScan, 50);
}
}
async function uploadBitstream(bitstream: File): Promise<boolean> {
if (isUndefined(props.jtagAddr) || isUndefined(props.jtagPort)) {
dialog.error("开发板地址或端口空缺");
return false;
}
try {
console.debug(`Before upload bistream: ${bitstream}`);
const resp = await jtagController.uploadBitstream(
props.jtagAddr,
Common.toFileParameterOrNull(bitstream),
);
return resp;
} catch (e) {
dialog.error("上传错误");
console.error(e);
return false;
}
}
async function downloadBitstream(): Promise<boolean> {
if (isUndefined(props.jtagAddr) || isUndefined(props.jtagPort)) {
dialog.error("开发板地址或端口空缺");
return false;
}
try {
const resp = await jtagController.downloadBitstream(
props.jtagAddr,
props.jtagPort,
);
return resp;
} catch (e) {
dialog.error("上传错误");
console.error(e);
return false;
}
}
async function getIDCode(isQuiet: boolean = false) {
if (isUndefined(props.jtagAddr) || isUndefined(props.jtagPort)) {
dialog.error("开发板地址或端口空缺");
if (eqps.jtagClientMutex.isLocked()) {
dialog.warn("Jtag正在被占用");
return;
}
try {
const resp = await jtagController.getDeviceIDCode(
props.jtagAddr,
props.jtagPort,
);
jtagIDCode.value = resp;
} catch (e) {
if (!isQuiet) dialog.error("获取IDCode错误");
}
eqps.enableJtagBoundaryScan = !eqps.enableJtagBoundaryScan;
}
watchEffect(() => {
eqps.setAddr(props.jtagAddr);
eqps.setPort(props.jtagPort);
});
async function getIDCode(isQuiet: boolean = false) {
jtagIDCode.value = await eqps.jtagGetIDCode(isQuiet);
}
watchEffect(() => {
if (
z.string().ip().safeParse(props.jtagAddr).success &&
z.number().positive().safeParse(props.jtagPort).success
)
watchEffect(async () => {
if (eqps.setAddr(props.jtagAddr) && eqps.setPort(props.jtagPort))
getIDCode(true);
});
</script>

View File

@ -1,40 +1,140 @@
import { ref, computed } from 'vue'
import { ref, watchEffect } from 'vue'
import { defineStore } from 'pinia'
import { isString, isUndefined, toNumber } from 'lodash';
import { isString, toNumber, isUndefined } from 'lodash';
import { Common } from '@/Common';
import z from "zod"
import { isNumber } from 'mathjs';
import { JtagClient } from "@/APIClient";
import { Mutex, withTimeout } from 'async-mutex';
import { useConstraintsStore } from "@/stores/constraints";
import { useDialogStore } from './dialog';
export const useEquipments = defineStore('equipments', () => {
const boardAddr = ref("127.0.0.1")
const boardPort = ref(1234)
const jtagBitstream = ref<File>()
// Global Stores
const constrainsts = useConstraintsStore();
const dialog = useDialogStore();
function setAddr(address: string | undefined) {
if (isUndefined(address)) return;
if (z.string().ip("4").safeParse(address).success)
const boardAddr = ref("127.0.0.1");
const boardPort = ref(1234);
const jtagBitstream = ref<File>();
const jtagBoundaryScanFreq = ref(10);
const jtagClientMutex = withTimeout(new Mutex(), 2000, new Error("JtagClient Mutex Timeout!"))
const jtagClient = new JtagClient();
const enableJtagBoundaryScan = ref(false);
function setAddr(address: string | undefined): boolean {
if (isString(address) && z.string().ip("4").safeParse(address).success) {
boardAddr.value = address;
return true;
}
return false;
}
function setPort(port: string | number | undefined) {
if (isUndefined(port)) return;
function setPort(port: string | number | undefined): boolean {
if (isString(port) && port.length != 0) {
const portNumber = toNumber(port);
if (z.number().nonnegative().max(65535).safeParse(portNumber).success)
if (z.number().nonnegative().max(65535).safeParse(portNumber).success) {
boardPort.value = portNumber;
return true;
}
}
else if (isNumber(port)) {
if (z.number().nonnegative().max(65535).safeParse(port).success)
if (z.number().nonnegative().max(65535).safeParse(port).success) {
boardPort.value = port;
return true;
}
}
return false;
}
watchEffect(() => {
if (enableJtagBoundaryScan.value) jtagBoundaryScan();
});
async function jtagBoundaryScan() {
const release = await jtagClientMutex.acquire();
try {
const portStates = await jtagClient.boundaryScanLogicalPorts(
boardAddr.value,
boardPort.value,
);
constrainsts.batchSetConstraintStates(portStates);
} catch (error) {
dialog.error("边界扫描发生错误");
console.error(error);
enableJtagBoundaryScan.value = false;
} finally {
release();
if (enableJtagBoundaryScan.value)
setTimeout(jtagBoundaryScan, 1000 / jtagBoundaryScanFreq.value);
}
}
async function jtagUploadBitstream(bitstream: File): Promise<boolean> {
try {
const resp = await jtagClient.uploadBitstream(
boardAddr.value,
Common.toFileParameterOrNull(bitstream),
);
return resp;
} catch (e) {
dialog.error("上传错误");
console.error(e);
return false;
}
}
async function jtagDownloadBitstream(): Promise<boolean> {
const release = await jtagClientMutex.acquire();
try {
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<number> {
const release = await jtagClientMutex.acquire();
try {
const resp = await jtagClient.getDeviceIDCode(
boardAddr.value,
boardPort.value
);
return resp;
} catch (e) {
if (!isQuiet) dialog.error("获取IDCode错误");
return 0xffff_ffff;
} finally {
release();
}
}
return {
boardAddr,
boardPort,
setAddr,
setPort,
jtagBitstream,
jtagBoundaryScanFreq,
jtagClientMutex,
jtagClient,
jtagUploadBitstream,
jtagDownloadBitstream,
jtagGetIDCode,
enableJtagBoundaryScan,
}
})

View File

@ -62,7 +62,6 @@ async function uploadBitstream(bitstream: File): Promise<boolean> {
}
try {
console.debug(`Before upload bistream: ${bitstream}`);
const resp = await jtagController.uploadBitstream(
boardAddress.value,
Common.toFileParameterOrNull(bitstream),