maybe fix bug: download bitstream failed

This commit is contained in:
SikongJueluo 2025-04-23 20:22:49 +08:00
parent 5ea541ef4b
commit 4e752d4c9e
No known key found for this signature in database
5 changed files with 229 additions and 54 deletions

View File

@ -3,20 +3,35 @@
pwd
echo
# 清空构建文件
clean:
rm -rf "server/bin"
rm -rf "server/obj"
rm -rf "server.test/bin"
rm -rf "server.test/obj"
rm -rf "dist"
# 生成Restful API到网页客户端
gen-api:
cd server && dotnet run &
npx nswag openapi2tsclient /input:http://localhost:5000/swagger/v1/swagger.json /output:src/APIClient.ts
pkill server
# 构建服务器包含win与linux平台
[working-directory: "server"]
publish: _show-dir
build-server: _show-dir
dotnet publish --self-contained false -t:PublishAllRids
# 运行服务器
[working-directory: "server"]
run-server: _show-dir
dotnet run
# 运行网页客户端
run-web:
npm run dev
# 运行测试用例测试服务器
[working-directory: "server.test"]
test-server: _show-dir
dotnet test --logger "console;verbosity=detailed"

View File

@ -251,7 +251,9 @@ public class JtagController : ControllerBase
{
// 读取文件
var filePath = Directory.GetFiles(fileDir)[0];
var fileStream = System.IO.File.Open(filePath, System.IO.FileMode.Open);
using (var fileStream = System.IO.File.Open(filePath, System.IO.FileMode.Open))
{
if (fileStream is null || fileStream.Length <= 0)
return TypedResults.BadRequest("Wrong bitstream, Please upload it again");
@ -287,10 +289,112 @@ public class JtagController : ControllerBase
return TypedResults.InternalServerError(ret.Error);
}
}
}
}
catch (Exception error)
{
return TypedResults.InternalServerError(error);
}
finally
{
}
}
}
[ApiController]
[Route("api/[controller]")]
public class Log : ControllerBase
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private readonly string _logFilePath = Directory.GetFiles(Directory.GetCurrentDirectory())[0];
[HttpGet]
public async Task<IActionResult> Index()
{
if (!System.IO.File.Exists(_logFilePath))
{
Problem("日志文件不存在");
}
// 请求头
Response.Headers.Add("Content-Type", "text/event-stream");
Response.Headers.Add("Cache-Control", "no-cache");
Response.Headers.Add("Connection", "keep-alive");
long position = 0;
while (!HttpContext.RequestAborted.IsCancellationRequested)
{
try
{
if (System.IO.File.Exists(_logFilePath))
{
using (var stream = new FileStream(_logFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
stream.Position = position;
using (var reader = new StreamReader(stream))
{
string? line;
while ((line = await reader.ReadLineAsync()) != null)
{
// await WriteEvent(line);
await Response.WriteAsync($"data: {line}\n\n");
await Response.Body.FlushAsync();
position = stream.Position;
}
if (line is null) break;
}
}
}
else
{
await WriteEvent("日志文件被删除");
break;
}
}
catch (Exception ex)
{
await WriteEvent($"错误: {ex.Message}");
}
await Task.Delay(1000, HttpContext.RequestAborted); // 每秒检查一次
}
// 结束
return new EmptyResult();
}
private async Task WriteEvent(string message)
{
await Response.WriteAsync($"data: {message}\n\n");
await Response.Body.FlushAsync();
}
[HttpGet("example")]
public async Task<IActionResult> SseExample()
{
// 请求头
Response.Headers.Add("Content-Type", "text/event-stream");
Response.Headers.Add("Cache-Control", "no-cache");
Response.Headers.Add("Connection", "keep-alive");
// 假设不断得到新数据
for (int i = 0; i < 10000; i++)
{
// 每个数据参照 SSE 返回数据格式进行组装
var content = "event: message\n"
+ "data: {\"color\":\"66ccff\"}\n\n";
// 立刻写入响应
await Response.WriteAsync(content);
await Response.Body.FlushAsync();
}
// 结束
return new EmptyResult();
}
}

View File

@ -220,6 +220,8 @@ public class Jtag
{
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private const int CLOCK_FREQ = 50; // MHz
readonly int timeout;
readonly int port;
@ -274,7 +276,7 @@ public class Jtag
return Convert.ToUInt32(Common.Number.BytesToNumber(retPackOpts.Data).Value);
}
public async ValueTask<Result<RecvDataPackage>> WriteFIFO(UInt32 devAddr, UInt32 data)
public async ValueTask<Result<RecvDataPackage>> WriteFIFO(UInt32 devAddr, UInt32 data, UInt32 delayMilliseconds = 0)
{
var ret = false;
var opts = new SendAddrPackOptions();
@ -303,6 +305,9 @@ public class Jtag
else if (!udpWriteAck.Value.IsSuccessful)
return new(new Exception("Send address package failed"));
// Delay some time before read register
await Task.Delay(TimeSpan.FromMilliseconds(delayMilliseconds));
// Read Jtag State Register
opts.IsWrite = false;
opts.Address = JtagAddr.STATE;
@ -317,7 +322,7 @@ public class Jtag
return udpDataResp.Value;
}
async ValueTask<Result<RecvDataPackage>> WriteFIFO(UInt32 devAddr, byte[] dataArray)
async ValueTask<Result<RecvDataPackage>> WriteFIFO(UInt32 devAddr, byte[] dataArray, UInt32 delayMilliseconds = 0)
{
var ret = false;
var opts = new SendAddrPackOptions();
@ -334,20 +339,21 @@ public class Jtag
var writeTimes = dataArray.Length / (256 * (32 / 8)) + 1;
for (var i = 0; i < writeTimes; i++)
{
// Sperate Data Array
var isLastData = i == writeTimes - 1;
// Write Jtag State Register
opts.IsWrite = true;
opts.BurstLength = isLastData ? (byte)(dataArray.Length - i * (256 * (32 / 8)) - 1) : (byte)255;
ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts));
if (!ret) return new(new Exception("Send 1st address package failed!"));
// Send Data Package
ret = await UDPClientPool.SendDataPackAsync(ep,
new SendDataPackage(
var sendDataArray =
isLastData ?
dataArray[(i * (256 * (32 / 8)))..] :
dataArray[(i * (256 * (32 / 8)))..((i + 1) * (256 * (32 / 8)) - 1)]
)
);
dataArray[(i * (256 * (32 / 8)))..((i + 1) * (256 * (32 / 8)))];
// Write Jtag State Register
opts.IsWrite = true;
opts.BurstLength = ((byte)(sendDataArray.Length / 4 - 1));
ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts));
if (!ret) return new(new Exception("Send 1st address package failed!"));
// Send Data Package
ret = await UDPClientPool.SendDataPackAsync(ep, new SendDataPackage(sendDataArray));
if (!ret) return new(new Exception("Send data package failed!"));
// Wait for Write Ack
@ -357,6 +363,9 @@ public class Jtag
return new(new Exception("Send address package failed"));
}
// Delay some time before read register
await Task.Delay(TimeSpan.FromMilliseconds(delayMilliseconds));
// Read Jtag State Register
opts.IsWrite = false;
opts.BurstLength = 0;
@ -373,10 +382,10 @@ public class Jtag
}
async ValueTask<Result<bool>> WriteFIFO
(UInt32 devAddr, UInt32 data, UInt32 result, UInt32 resultMask = 0xFF_FF_FF_FF)
(UInt32 devAddr, UInt32 data, UInt32 result, UInt32 resultMask = 0xFF_FF_FF_FF, UInt32 delayMilliseconds = 0)
{
var ret = false;
var retPack = await WriteFIFO(devAddr, data);
var retPack = await WriteFIFO(devAddr, data, delayMilliseconds);
if (!retPack.IsSuccessful) return new(retPack.Error);
if (retPack.Value.Options.Data is null)
@ -394,10 +403,10 @@ public class Jtag
}
async ValueTask<Result<bool>> WriteFIFO
(UInt32 devAddr, byte[] data, UInt32 result, UInt32 resultMask = 0xFF_FF_FF_FF)
(UInt32 devAddr, byte[] data, UInt32 result, UInt32 resultMask = 0xFF_FF_FF_FF, UInt32 delayMilliseconds = 0)
{
var ret = false;
var retPack = await WriteFIFO(devAddr, data);
var retPack = await WriteFIFO(devAddr, data, delayMilliseconds);
if (retPack.Value.Options.Data is null)
return new(new Exception($"Data is Null, package: {retPack.Value.Options.ToString()}"));
@ -413,6 +422,45 @@ public class Jtag
return ret;
}
async ValueTask<Result<bool>> WaitForWriteFIFO
(UInt32 devAddr, byte[] data, UInt32 result,
UInt32 resultMask = 0xFF_FF_FF_FF, UInt32 timeout = 10_000, UInt32 cycle = 500)
{
{
var wrRet = await WriteFIFO(devAddr, data, result, resultMask);
if (!wrRet.IsSuccessful) return new(wrRet.Error);
if (wrRet.Value) return true;
}
// Wait some time
var ret = false;
var startTime = DateTime.Now;
var isTimeout = false;
var timeleft = TimeSpan.FromMilliseconds(timeout);
while (!isTimeout)
{
// Check whether timeout
var elapsed = DateTime.Now - startTime;
isTimeout = elapsed >= TimeSpan.FromMilliseconds(timeout);
if (isTimeout) break;
timeleft = TimeSpan.FromMilliseconds(timeout) - elapsed;
// Check FIFO
var retPack = await ReadFIFO(JtagAddr.STATE);
if (Common.Number.BitsCheck(retPack.Value, result, resultMask))
{
ret = true;
break;
}
// Wait
await Task.Delay(TimeSpan.FromMilliseconds(cycle));
}
return ret;
}
async ValueTask<Result<bool>> ClearAllRegisters()
{
@ -447,7 +495,7 @@ public class Jtag
return await WriteFIFO(
JtagAddr.WRITE_CMD,
Common.Number.MultiBitsToNumber(JtagCmd.CMD_JTAG_IDLE_DELAY, JtagCmd.LEN_CMD_JTAG, milliseconds, 28).Value,
0x01_00_00_00, JtagState.CMD_EXEC_FINISH);
0x01_00_00_00, JtagState.CMD_EXEC_FINISH, (milliseconds / CLOCK_FREQ) + 100);
}
async ValueTask<Result<bool>> ExecRDCmd(uint command)
@ -472,7 +520,7 @@ public class Jtag
return await ClearWriteDataReg();
}
async ValueTask<Result<bool>> LoadDRCareInput(byte[] bytesArray)
async ValueTask<Result<bool>> LoadDRCareInput(byte[] bytesArray, UInt32 timeout = 10_000, UInt32 cycle = 500)
{
var bytesLen = ((uint)(bytesArray.Length * 8));
if (bytesLen > Math.Pow(2, 28)) return new(new Exception("Length is over 2^(28 - 3)"));
@ -481,13 +529,17 @@ public class Jtag
var ret = await WriteFIFO(
JtagAddr.WRITE_CMD,
Common.Number.MultiBitsToNumber(JtagCmd.CMD_JTAG_LOAD_DR_CAREI, JtagCmd.LEN_CMD_JTAG, bytesLen, 28).Value,
0x01_00_00_00, JtagState.CMD_EXEC_FINISH);
0, 0);
if (!ret.IsSuccessful) return new(ret.Error);
else if (!ret.Value) return new(new Exception("Write CMD_JTAG_LOAD_DR_CAREI Failed"));
}
{
var ret = await WriteFIFO(JtagAddr.WRITE_DATA, bytesArray, 0x01_00_00_00, JtagState.CMD_EXEC_FINISH);
var ret = await WaitForWriteFIFO(
JtagAddr.WRITE_DATA,
bytesArray, 0x01_00_00_00,
JtagState.CMD_EXEC_FINISH,
timeout, cycle);
if (!ret.IsSuccessful) return new(ret.Error);
else if (!ret.Value) return new(new Exception("Write Data Failed"));

View File

@ -116,6 +116,7 @@ public class UDPServer
/// </summary>
/// <param name="ipAddr"> 目标IP地址 </param>
/// <param name="timeout">超时时间</param>
/// <param name="cycle">延迟时间</param>
/// <param name="callerName">调用函数名称</param>
/// <param name="callerLineNum">调用函数位置</param>
/// <returns>
@ -124,7 +125,7 @@ public class UDPServer
/// Optional 存在时,为最先收到的数据
/// </returns>
public async ValueTask<Optional<UDPData>> FindDataAsync(
string ipAddr, int timeout = 1000,
string ipAddr, int timeout = 1000, int cycle = 0,
[CallerMemberName] string callerName = "",
[CallerLineNumber] int callerLineNum = 0)
{
@ -153,6 +154,8 @@ public class UDPServer
break;
}
}
await Task.Delay(cycle);
}
if (data is null)
@ -171,8 +174,9 @@ public class UDPServer
/// </summary>
/// <param name="ipAddr">IP地址</param>
/// <param name="timeout">超时时间</param>
/// <param name="cycle">延迟时间</param>
/// <returns>数据列表</returns>
public async ValueTask<Optional<List<UDPData>>> GetDataArrayAsync(string ipAddr, int timeout = 1000)
public async ValueTask<Optional<List<UDPData>>> GetDataArrayAsync(string ipAddr, int timeout = 1000, int cycle = 0)
{
List<UDPData>? data = null;

View File

@ -20,10 +20,10 @@ namespace WebProtocol
/// <summary> Package Burst Type </summary>
public enum BurstType
{
/// <summary> Extended Type </summary>
ExtendBurst = 0b00,
/// <summary> Fixed Type </summary>
FixedBurst = 0b01,
FixedBurst = 0b00,
/// <summary> Extended Type </summary>
ExtendBurst = 0b01,
}