feat: frontend add set jtag frequency
This commit is contained in:
parent
a6ac728cf1
commit
d754a881d7
|
@ -367,7 +367,6 @@ public class JtagController : ControllerBase
|
||||||
[HttpPost("BoundaryScanLogicalPorts")]
|
[HttpPost("BoundaryScanLogicalPorts")]
|
||||||
[EnableCors("Users")]
|
[EnableCors("Users")]
|
||||||
[ProducesResponseType(typeof(Dictionary<string, bool>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(Dictionary<string, bool>), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)]
|
|
||||||
[ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
|
[ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
|
||||||
public async ValueTask<IResult> BoundaryScanLogicalPorts(string address, int port)
|
public async ValueTask<IResult> BoundaryScanLogicalPorts(string address, int port)
|
||||||
{
|
{
|
||||||
|
@ -382,6 +381,31 @@ public class JtagController : ControllerBase
|
||||||
|
|
||||||
return TypedResults.Ok(ret.Value);
|
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>
|
/// <summary>
|
||||||
|
|
|
@ -28,6 +28,10 @@ public static class JtagAddr
|
||||||
/// Jtag Write Command
|
/// Jtag Write Command
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const UInt32 WRITE_CMD = 0x10_00_00_03;
|
public const UInt32 WRITE_CMD = 0x10_00_00_03;
|
||||||
|
/// <summary>
|
||||||
|
/// Jtag Speed Control
|
||||||
|
/// </summary>
|
||||||
|
public const UInt32 SPEED_CTRL = 0x10_00_00_04;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -833,10 +837,26 @@ public class Jtag
|
||||||
if (cellList.IsNull) return new(new Exception("Get boundary logical ports failed"));
|
if (cellList.IsNull) return new(new Exception("Get boundary logical ports failed"));
|
||||||
|
|
||||||
var portStatus = new Dictionary<string, bool>();
|
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]);
|
portStatus.Add(cell.PortID ?? "UnknownPortID", bitArray.Value[cell.CellNumber]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return portStatus;
|
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);
|
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 {
|
export class RemoteUpdateClient {
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<Teleport to="#ComponentCapabilities" v-if="selectecComponentID === props.componentId">
|
<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>
|
</Teleport>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -35,6 +36,11 @@ const emit = defineEmits<{
|
||||||
const props = withDefaults(defineProps<MotherBoardProps>(), getDefaultProps());
|
const props = withDefaults(defineProps<MotherBoardProps>(), getDefaultProps());
|
||||||
const selectecComponentID = inject(CanvasCurrentSelectedComponentID, ref(null));
|
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 width = computed(() => 800 * props.size);
|
||||||
const height = computed(() => 600 * props.size);
|
const height = computed(() => 600 * props.size);
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
<p class="grow">Jtag Addr: {{ eqps.boardAddr }}</p>
|
<p class="grow">Jtag Addr: {{ eqps.boardAddr }}</p>
|
||||||
<p class="grow">Jtag Port: {{ eqps.boardPort.toString() }}</p>
|
<p class="grow">Jtag Port: {{ eqps.boardPort.toString() }}</p>
|
||||||
<div class="flex justify-between grow">
|
<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">
|
<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"
|
<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">
|
xmlns="http://www.w3.org/2000/svg" p-id="4865" width="200" height="200">
|
||||||
|
@ -22,16 +24,26 @@
|
||||||
@update:bitstream-file="handleBitstreamChange">
|
@update:bitstream-file="handleBitstreamChange">
|
||||||
</UploadCard>
|
</UploadCard>
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<fieldset class="fieldset w-full">
|
<div class="w-full">
|
||||||
<legend class="fieldset-legend text-sm">边界扫描刷新率 / Hz</legend>
|
<legend class="fieldset-legend text-sm mb-0.3">Jtag运行频率</legend>
|
||||||
<input type="number" class="input validator w-full" required placeholder="Type a number between 1 to 1000" min="1"
|
<select class="select w-full" @change="handleSelectJtagSpeed" :value="props.jtagFreq">
|
||||||
max="1000" v-model="jtagBoundaryScanFreq" title="Type a number between 1 to 1000" />
|
<option v-for="option in selectJtagSpeedOptions" :value="option.id">
|
||||||
<p class="validator-hint">输入一个1 ~ 1000的数</p>
|
{{ option.text }}
|
||||||
</fieldset>
|
</option>
|
||||||
<button class="btn w-full btn-primary" :class="eqps.enableJtagBoundaryScan ? '' : 'btn-soft'"
|
</select>
|
||||||
:onclick="toggleJtagBoundaryScan">
|
</div>
|
||||||
{{ eqps.enableJtagBoundaryScan ? "关闭边界扫描" : "启动边界扫描" }}
|
<div class="flex flex-row items-center">
|
||||||
</button>
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -45,10 +57,24 @@ import { computed, ref, watchEffect } from "vue";
|
||||||
interface CapsProps {
|
interface CapsProps {
|
||||||
jtagAddr?: string;
|
jtagAddr?: string;
|
||||||
jtagPort?: number;
|
jtagPort?: number;
|
||||||
|
jtagFreq?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const emits = defineEmits<{
|
||||||
|
changeJtagFreq: [text: string];
|
||||||
|
}>();
|
||||||
const props = withDefaults(defineProps<CapsProps>(), {});
|
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
|
// Global Stores
|
||||||
const dialog = useDialogStore();
|
const dialog = useDialogStore();
|
||||||
const eqps = useEquipments();
|
const eqps = useEquipments();
|
||||||
|
@ -68,6 +94,12 @@ function handleBitstreamChange(file: File | undefined) {
|
||||||
eqps.jtagBitstream = file;
|
eqps.jtagBitstream = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSelectJtagSpeed(event: Event) {
|
||||||
|
const target = event.target as HTMLSelectElement;
|
||||||
|
eqps.jtagSetSpeed(target.selectedIndex);
|
||||||
|
emits("changeJtagFreq", target.value);
|
||||||
|
}
|
||||||
|
|
||||||
async function toggleJtagBoundaryScan() {
|
async function toggleJtagBoundaryScan() {
|
||||||
if (eqps.jtagClientMutex.isLocked()) {
|
if (eqps.jtagClientMutex.isLocked()) {
|
||||||
dialog.warn("Jtag正在被占用");
|
dialog.warn("Jtag正在被占用");
|
||||||
|
|
|
@ -17,8 +17,8 @@ export const useEquipments = defineStore('equipments', () => {
|
||||||
const boardAddr = ref("127.0.0.1");
|
const boardAddr = ref("127.0.0.1");
|
||||||
const boardPort = ref(1234);
|
const boardPort = ref(1234);
|
||||||
const jtagBitstream = ref<File>();
|
const jtagBitstream = ref<File>();
|
||||||
const jtagBoundaryScanFreq = ref(10);
|
const jtagBoundaryScanFreq = ref(100);
|
||||||
const jtagClientMutex = withTimeout(new Mutex(), 2000, new Error("JtagClient Mutex Timeout!"))
|
const jtagClientMutex = withTimeout(new Mutex(), 1000, new Error("JtagClient Mutex Timeout!"))
|
||||||
const jtagClient = new JtagClient();
|
const jtagClient = new JtagClient();
|
||||||
|
|
||||||
const enableJtagBoundaryScan = ref(false);
|
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 {
|
return {
|
||||||
boardAddr,
|
boardAddr,
|
||||||
|
@ -134,6 +150,7 @@ export const useEquipments = defineStore('equipments', () => {
|
||||||
jtagUploadBitstream,
|
jtagUploadBitstream,
|
||||||
jtagDownloadBitstream,
|
jtagDownloadBitstream,
|
||||||
jtagGetIDCode,
|
jtagGetIDCode,
|
||||||
|
jtagSetSpeed,
|
||||||
enableJtagBoundaryScan,
|
enableJtagBoundaryScan,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue