feat: frontend add set jtag frequency
This commit is contained in:
		@@ -367,7 +367,6 @@ public class JtagController : ControllerBase
 | 
			
		||||
    [HttpPost("BoundaryScanLogicalPorts")]
 | 
			
		||||
    [EnableCors("Users")]
 | 
			
		||||
    [ProducesResponseType(typeof(Dictionary<string, bool>), StatusCodes.Status200OK)]
 | 
			
		||||
    [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)]
 | 
			
		||||
    [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
 | 
			
		||||
    public async ValueTask<IResult> BoundaryScanLogicalPorts(string address, int port)
 | 
			
		||||
    {
 | 
			
		||||
@@ -382,6 +381,31 @@ public class JtagController : ControllerBase
 | 
			
		||||
 | 
			
		||||
        return TypedResults.Ok(ret.Value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// [TODO:description]
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="address">[TODO:parameter]</param>
 | 
			
		||||
    /// <param name="port">[TODO:parameter]</param>
 | 
			
		||||
    /// <param name="speed">[TODO:parameter]</param>
 | 
			
		||||
    /// <returns>[TODO:return]</returns>
 | 
			
		||||
    [HttpPost("SetSpeed")]
 | 
			
		||||
    [EnableCors("Users")]
 | 
			
		||||
    [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
 | 
			
		||||
    [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
 | 
			
		||||
    public async ValueTask<IResult> SetSpeed(string address, int port, UInt32 speed)
 | 
			
		||||
    {
 | 
			
		||||
        var jtagCtrl = new JtagClient.Jtag(address, port);
 | 
			
		||||
        var ret = await jtagCtrl.SetSpeed(speed);
 | 
			
		||||
        if (!ret.IsSuccessful)
 | 
			
		||||
        {
 | 
			
		||||
            if (ret.Error is ArgumentException)
 | 
			
		||||
                return TypedResults.BadRequest(ret.Error);
 | 
			
		||||
            else return TypedResults.InternalServerError(ret.Error);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return TypedResults.Ok(ret.Value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,10 @@ public static class JtagAddr
 | 
			
		||||
    /// Jtag Write Command
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 WRITE_CMD = 0x10_00_00_03;
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Jtag Speed Control
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 SPEED_CTRL = 0x10_00_00_04;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
@@ -833,10 +837,26 @@ public class Jtag
 | 
			
		||||
        if (cellList.IsNull) return new(new Exception("Get boundary logical ports failed"));
 | 
			
		||||
 | 
			
		||||
        var portStatus = new Dictionary<string, bool>();
 | 
			
		||||
        foreach (var cell in cellList.Value) {
 | 
			
		||||
        foreach (var cell in cellList.Value)
 | 
			
		||||
        {
 | 
			
		||||
            portStatus.Add(cell.PortID ?? "UnknownPortID", bitArray.Value[cell.CellNumber]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return portStatus;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<Result<bool>> SetSpeed(UInt32 speed)
 | 
			
		||||
    {
 | 
			
		||||
        // Clear Data
 | 
			
		||||
        await MsgBus.UDPServer.ClearUDPData(this.address);
 | 
			
		||||
 | 
			
		||||
        logger.Trace($"Clear up udp server {this.address} receive data");
 | 
			
		||||
        
 | 
			
		||||
        var ret = await WriteFIFO(
 | 
			
		||||
            JtagAddr.SPEED_CTRL, (speed << 16) | speed,
 | 
			
		||||
            JtagState.CMD_EXEC_FINISH, JtagState.CMD_EXEC_FINISH);
 | 
			
		||||
        
 | 
			
		||||
        if (!ret.IsSuccessful) return new (ret.Error);
 | 
			
		||||
        return ret.Value;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -724,6 +724,75 @@ export class JtagClient {
 | 
			
		||||
        }
 | 
			
		||||
        return Promise.resolve<{ [key: string]: boolean; }>(null as any);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * [TODO:description]
 | 
			
		||||
     * @param address (optional) [TODO:parameter]
 | 
			
		||||
     * @param port (optional) [TODO:parameter]
 | 
			
		||||
     * @param speed (optional) [TODO:parameter]
 | 
			
		||||
     * @return [TODO:return]
 | 
			
		||||
     */
 | 
			
		||||
    setSpeed(address: string | undefined, port: number | undefined, speed: number | undefined): Promise<boolean> {
 | 
			
		||||
        let url_ = this.baseUrl + "/api/Jtag/SetSpeed?";
 | 
			
		||||
        if (address === null)
 | 
			
		||||
            throw new Error("The parameter 'address' cannot be null.");
 | 
			
		||||
        else if (address !== undefined)
 | 
			
		||||
            url_ += "address=" + encodeURIComponent("" + address) + "&";
 | 
			
		||||
        if (port === null)
 | 
			
		||||
            throw new Error("The parameter 'port' cannot be null.");
 | 
			
		||||
        else if (port !== undefined)
 | 
			
		||||
            url_ += "port=" + encodeURIComponent("" + port) + "&";
 | 
			
		||||
        if (speed === null)
 | 
			
		||||
            throw new Error("The parameter 'speed' cannot be null.");
 | 
			
		||||
        else if (speed !== undefined)
 | 
			
		||||
            url_ += "speed=" + encodeURIComponent("" + speed) + "&";
 | 
			
		||||
        url_ = url_.replace(/[?&]$/, "");
 | 
			
		||||
 | 
			
		||||
        let options_: RequestInit = {
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            headers: {
 | 
			
		||||
                "Accept": "application/json"
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return this.http.fetch(url_, options_).then((_response: Response) => {
 | 
			
		||||
            return this.processSetSpeed(_response);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected processSetSpeed(response: Response): Promise<boolean> {
 | 
			
		||||
        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) {
 | 
			
		||||
            return response.text().then((_responseText) => {
 | 
			
		||||
            let result200: any = null;
 | 
			
		||||
            let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
 | 
			
		||||
                result200 = resultData200 !== undefined ? resultData200 : <any>null;
 | 
			
		||||
    
 | 
			
		||||
            return result200;
 | 
			
		||||
            });
 | 
			
		||||
        } else if (status === 400) {
 | 
			
		||||
            return response.text().then((_responseText) => {
 | 
			
		||||
            let result400: any = null;
 | 
			
		||||
            let resultData400 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
 | 
			
		||||
                result400 = resultData400 !== undefined ? resultData400 : <any>null;
 | 
			
		||||
    
 | 
			
		||||
            return throwException("A server side error occurred.", status, _responseText, _headers, result400);
 | 
			
		||||
            });
 | 
			
		||||
        } else if (status === 500) {
 | 
			
		||||
            return response.text().then((_responseText) => {
 | 
			
		||||
            let result500: any = null;
 | 
			
		||||
            let resultData500 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
 | 
			
		||||
            result500 = Exception.fromJS(resultData500);
 | 
			
		||||
            return throwException("A server side error occurred.", status, _responseText, _headers, result500);
 | 
			
		||||
            });
 | 
			
		||||
        } else if (status !== 200 && status !== 204) {
 | 
			
		||||
            return response.text().then((_responseText) => {
 | 
			
		||||
            return throwException("An unexpected server error occurred.", status, _responseText, _headers);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        return Promise.resolve<boolean>(null as any);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class RemoteUpdateClient {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,8 @@
 | 
			
		||||
    </svg>
 | 
			
		||||
  </div>
 | 
			
		||||
  <Teleport to="#ComponentCapabilities" v-if="selectecComponentID === props.componentId">
 | 
			
		||||
    <MotherBoardCaps :jtagAddr="props.boardAddr" :jtagPort="toNumber(props.boardPort)" />
 | 
			
		||||
    <MotherBoardCaps :jtagAddr="props.boardAddr" :jtagPort="toNumber(props.boardPort)" :jtagFreq="jtagFreq"
 | 
			
		||||
      @change-jtag-freq="changeJtagFreq" />
 | 
			
		||||
  </Teleport>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
@@ -35,6 +36,11 @@ const emit = defineEmits<{
 | 
			
		||||
const props = withDefaults(defineProps<MotherBoardProps>(), getDefaultProps());
 | 
			
		||||
const selectecComponentID = inject(CanvasCurrentSelectedComponentID, ref(null));
 | 
			
		||||
 | 
			
		||||
const jtagFreq = ref("25 MHz");
 | 
			
		||||
function changeJtagFreq(text: string) {
 | 
			
		||||
  jtagFreq.value = text;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 计算实际宽高
 | 
			
		||||
const width = computed(() => 800 * props.size);
 | 
			
		||||
const height = computed(() => 600 * props.size);
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,9 @@
 | 
			
		||||
      <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").toUpperCase() }}</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">
 | 
			
		||||
@@ -22,16 +24,26 @@
 | 
			
		||||
      @update:bitstream-file="handleBitstreamChange">
 | 
			
		||||
    </UploadCard>
 | 
			
		||||
    <div class="divider"></div>
 | 
			
		||||
    <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">
 | 
			
		||||
      {{ eqps.enableJtagBoundaryScan ? "关闭边界扫描" : "启动边界扫描" }}
 | 
			
		||||
    </button>
 | 
			
		||||
    <div class="w-full">
 | 
			
		||||
      <legend class="fieldset-legend text-sm mb-0.3">Jtag运行频率</legend>
 | 
			
		||||
      <select class="select w-full" @change="handleSelectJtagSpeed" :value="props.jtagFreq">
 | 
			
		||||
        <option v-for="option in selectJtagSpeedOptions" :value="option.id">
 | 
			
		||||
          {{ option.text }}
 | 
			
		||||
        </option>
 | 
			
		||||
      </select>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="flex flex-row items-center">
 | 
			
		||||
      <fieldset class="fieldset w-70">
 | 
			
		||||
        <legend class="fieldset-legend text-sm">边界扫描刷新率 / Hz</legend>
 | 
			
		||||
        <input type="number" class="input validator" 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 btn-primary grow mx-4" :class="eqps.enableJtagBoundaryScan ? '' : 'btn-soft'"
 | 
			
		||||
        :onclick="toggleJtagBoundaryScan">
 | 
			
		||||
        {{ eqps.enableJtagBoundaryScan ? "关闭边界扫描" : "启动边界扫描" }}
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
@@ -45,10 +57,24 @@ import { computed, ref, watchEffect } from "vue";
 | 
			
		||||
interface CapsProps {
 | 
			
		||||
  jtagAddr?: string;
 | 
			
		||||
  jtagPort?: number;
 | 
			
		||||
  jtagFreq?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const emits = defineEmits<{
 | 
			
		||||
  changeJtagFreq: [text: string];
 | 
			
		||||
}>();
 | 
			
		||||
const props = withDefaults(defineProps<CapsProps>(), {});
 | 
			
		||||
 | 
			
		||||
const selectJtagSpeedOptions = ref([
 | 
			
		||||
  { text: "25 MHz", id: 1 },
 | 
			
		||||
  { text: "12.5 MHz", id: 2 },
 | 
			
		||||
  { text: "6.25 MHz", id: 3 },
 | 
			
		||||
  { text: "3.125 MHz", id: 4 },
 | 
			
		||||
  { text: "1562.5 KHz", id: 5 },
 | 
			
		||||
  { text: "781.25 KHz", id: 6 },
 | 
			
		||||
  { text: "390.625 KHz", id: 7 },
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
// Global Stores
 | 
			
		||||
const dialog = useDialogStore();
 | 
			
		||||
const eqps = useEquipments();
 | 
			
		||||
@@ -68,6 +94,12 @@ function handleBitstreamChange(file: File | undefined) {
 | 
			
		||||
  eqps.jtagBitstream = file;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleSelectJtagSpeed(event: Event) {
 | 
			
		||||
  const target = event.target as HTMLSelectElement;
 | 
			
		||||
  eqps.jtagSetSpeed(target.selectedIndex);
 | 
			
		||||
  emits("changeJtagFreq", target.value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function toggleJtagBoundaryScan() {
 | 
			
		||||
  if (eqps.jtagClientMutex.isLocked()) {
 | 
			
		||||
    dialog.warn("Jtag正在被占用");
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,8 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
  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 jtagBoundaryScanFreq = ref(100);
 | 
			
		||||
  const jtagClientMutex = withTimeout(new Mutex(), 1000, new Error("JtagClient Mutex Timeout!"))
 | 
			
		||||
  const jtagClient = new JtagClient();
 | 
			
		||||
 | 
			
		||||
  const enableJtagBoundaryScan = ref(false);
 | 
			
		||||
@@ -121,6 +121,22 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function jtagSetSpeed(speed: number): Promise<boolean> {
 | 
			
		||||
    const release = await jtagClientMutex.acquire();
 | 
			
		||||
    try {
 | 
			
		||||
      const resp = await jtagClient.setSpeed(
 | 
			
		||||
        boardAddr.value,
 | 
			
		||||
        boardPort.value,
 | 
			
		||||
        speed
 | 
			
		||||
      );
 | 
			
		||||
      return resp;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      dialog.error("设置Jtag速度失败");
 | 
			
		||||
      return false;
 | 
			
		||||
    } finally {
 | 
			
		||||
      release();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    boardAddr,
 | 
			
		||||
@@ -134,6 +150,7 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
    jtagUploadBitstream,
 | 
			
		||||
    jtagDownloadBitstream,
 | 
			
		||||
    jtagGetIDCode,
 | 
			
		||||
    jtagSetSpeed,
 | 
			
		||||
    enableJtagBoundaryScan,
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user