fix: boundary scan could not save
This commit is contained in:
		
							
								
								
									
										16
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										16
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -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",
 | 
			
		||||
 
 | 
			
		||||
@@ -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
											
										
									
								
							@@ -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("上传成功");
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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),
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user