maybe fix bug: download bitstream failed
This commit is contained in:
parent
5ea541ef4b
commit
4e752d4c9e
17
.justfile
17
.justfile
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue