diff --git a/.gitignore b/.gitignore index 0c7f6fd..f9c250d 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ lerna-debug.log* node_modules .DS_Store dist +**/wwwroot dist-ssr coverage *.local diff --git a/.justfile b/.justfile index b258d7a..e71e46d 100644 --- a/.justfile +++ b/.justfile @@ -1,3 +1,5 @@ +isSelfContained := "false" + @_show-dir: echo "Current Working Directory:" pwd @@ -12,6 +14,8 @@ clean: rm -rf "dist" update: + npm install + cd server && dotnet restore git submodule update --init --remote --recursive # 生成Restful API到网页客户端 @@ -22,16 +26,25 @@ gen-api: # 构建服务器,包含win与linux平台 [working-directory: "server"] -build-server: _show-dir - dotnet publish --self-contained false -t:PublishAllRids +build-server self-contained=isSelfContained: _show-dir + dotnet publish --self-contained {{self-contained}} -t:PublishAllRids + npm run build + rsync -avz --delete ../wwwroot/ ./bin/Release/net9.0/linux-x64/publish/wwwroot/ + rsync -avz --delete ../wwwroot/ ./bin/Release/net9.0/win-x64/publish/wwwroot/ -# 运行服务器 -[working-directory: "server"] -run-server: _show-dir - dotnet run +run-server: (build-server "true") + exec ./server/bin/Release/net9.0/linux-x64/publish/server + +run-web: + npm run build + npm run preview + +# 测试服务器 +dev-server: _show-dir + cd server && dotnet run # 运行网页客户端 -run-web: +dev-web: npm run dev # 运行测试用例测试服务器 diff --git a/package-lock.json b/package-lock.json index 9aa607e..272e09e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "@tailwindcss/postcss": "^4.0.12", "@tsconfig/node22": "^22.0.0", "@types/node": "^22.13.4", + "@vitejs/plugin-basic-ssl": "^2.0.0", "@vitejs/plugin-vue": "^5.2.1", "@vitejs/plugin-vue-jsx": "^4.1.1", "@vue/tsconfig": "^0.7.0", @@ -1636,6 +1637,19 @@ "undici-types": "~6.21.0" } }, + "node_modules/@vitejs/plugin-basic-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.0.0.tgz", + "integrity": "sha512-gc9Tjg8bUxBVSTzeWT3Njc0Cl3PakHFKdNfABnZWiUgbxqmHDEn7uECv3fHVylxoYgNzAcmU7ZrILz+BwSo3sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "peerDependencies": { + "vite": "^6.0.0" + } + }, "node_modules/@vitejs/plugin-vue": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.3.tgz", diff --git a/package.json b/package.json index 72a1321..c040e15 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@tailwindcss/postcss": "^4.0.12", "@tsconfig/node22": "^22.0.0", "@types/node": "^22.13.4", + "@vitejs/plugin-basic-ssl": "^2.0.0", "@vitejs/plugin-vue": "^5.2.1", "@vitejs/plugin-vue-jsx": "^4.1.1", "@vue/tsconfig": "^0.7.0", diff --git a/server/Program.cs b/server/Program.cs index cde87b1..abf13ce 100644 --- a/server/Program.cs +++ b/server/Program.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.FileProviders; using Newtonsoft.Json; using NLog; using NLog.Web; @@ -9,7 +10,6 @@ var logger = NLog.LogManager.Setup() .GetCurrentClassLogger(); logger.Debug("Init Main..."); - try { var builder = WebApplication.CreateBuilder(args); @@ -84,15 +84,24 @@ try // Application Settings var app = builder.Build(); // Configure the HTTP request pipeline. - // app.UseExceptionHandler(new ExceptionHandlerOptions() - // { - // AllowStatusCode404Response = true, - // ExceptionHandlingPath = "/error" - // }); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); + if (!app.Environment.IsDevelopment()) + { + // app.UseExceptionHandler("/Home/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + + // Serve static files + logger.Info($"Use Static Files : {Path.Combine(Directory.GetCurrentDirectory(), "wwwroot")}"); + app.UseDefaultFiles(); + app.UseStaticFiles(); // Serves files from wwwroot by default + app.UseStaticFiles(new StaticFileOptions + { + FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "assets")), + RequestPath = "/assets" + }); + app.MapFallbackToFile("index.html"); + } app.UseHttpsRedirection(); - app.UseStaticFiles(); app.UseRouting(); app.UseCors(); app.UseAuthorization(); @@ -103,15 +112,13 @@ try app.UseSwaggerUi(); // } + // Router + app.MapControllers(); + // Setup Program MsgBus.Init(); - // Router - // API Get - app.MapGet("/", () => Results.Redirect("/swagger")); - app.MapControllers(); - - app.Run("http://localhost:5000"); + app.Run(); } catch (Exception exception) { diff --git a/server/Properties/launchSettings.json b/server/Properties/launchSettings.json index ceb1922..fca3ffd 100644 --- a/server/Properties/launchSettings.json +++ b/server/Properties/launchSettings.json @@ -5,18 +5,20 @@ "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, - "applicationUrl": "http://localhost:5188", + "applicationUrl": "http://localhost:5000", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" + "ASPNETCORE_ENVIRONMENT": "Development", + "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy" } }, "https": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, - "applicationUrl": "https://localhost:7070;http://localhost:5188", + "applicationUrl": "https://localhost:7278;http://localhost:5000", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" + "ASPNETCORE_ENVIRONMENT": "Development", + "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy" } } } diff --git a/server/PublishAllRids.targets b/server/PublishAllRids.xml similarity index 100% rename from server/PublishAllRids.targets rename to server/PublishAllRids.xml diff --git a/server/server.csproj b/server/server.csproj index 7a5a3fb..3390c45 100644 --- a/server/server.csproj +++ b/server/server.csproj @@ -1,21 +1,26 @@ - - - - - net9.0 - enable - enable - true - win-x64;linux-x64; - true - - + + + + + + net9.0 + enable + enable + true + win-x64;linux-x64; + true + ../ + http://localhost:5173 + npm run dev + + + @@ -23,6 +28,6 @@ - - - + + + diff --git a/server/src/Controllers.cs b/server/src/Controllers.cs index 9bdae91..de626a8 100644 --- a/server/src/Controllers.cs +++ b/server/src/Controllers.cs @@ -8,6 +8,44 @@ using WebProtocol; namespace server.Controllers; +// /// +// /// [TODO:description] +// /// +// public class HomeController : ControllerBase +// { +// private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); +// +// string INDEX_HTML_PATH = Path.Combine(Environment.CurrentDirectory, "index.html"); +// +// /// +// /// [TODO:description] +// /// +// /// [TODO:return] +// [HttpGet("/")] +// public IResult Index() +// { +// return TypedResults.Content("Hello", "text/html"); +// } +// +// // [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] +// // public IResult Error() +// // { +// // return TypedResults.Ok(); +// // } +// +// /// +// /// [TODO:description] +// /// +// /// [TODO:return] +// [HttpGet("/hello")] +// [HttpPost("/hello")] +// public IActionResult Hello() +// { +// string randomString = Guid.NewGuid().ToString(); +// return this.Ok($"Hello World! GUID: {randomString}"); +// } +// } + /// /// UDP API /// @@ -346,6 +384,32 @@ public class JtagController : ControllerBase } } + + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:parameter] + /// [TODO:return] + [HttpPost("BoundaryScan")] + [EnableCors("Users")] + [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] + public async ValueTask BoundaryScan(string address, int port, int portNum) + { + var jtagCtrl = new JtagClient.Jtag(address, port); + var ret = await jtagCtrl.BoundaryScan(portNum); + if (!ret.IsSuccessful) + { + if (ret.Error is ArgumentException) + return TypedResults.BadRequest(ret.Error); + else return TypedResults.InternalServerError(ret.Error); + } + + return TypedResults.Ok(ret.Value); + } } /// diff --git a/server/src/JtagClient.cs b/server/src/JtagClient.cs index b02ed6e..afb5de6 100644 --- a/server/src/JtagClient.cs +++ b/server/src/JtagClient.cs @@ -368,6 +368,21 @@ public class JtagStatusReg } } +/// +/// [TODO:description] +/// +public class JtagBoundaryRegister +{ + /// + /// [TODO:description] + /// + public int PortNum { get; set; } + /// + /// [TODO:description] + /// + public UInt32[] PortStatus { get; set; } = new UInt32[] { }; +} + /// /// Jtag控制器 /// @@ -730,13 +745,13 @@ public class Jtag return true; } - async ValueTask> LoadDRCareOutput(UInt32 bytesLen) + async ValueTask> LoadDRCareOutput(UInt32 UInt32Num) { - if (bytesLen > Math.Pow(2, 28)) return new(new Exception("Length is over 2^(28 - 3)")); + if (UInt32Num > Math.Pow(2, 23)) return new(new Exception("Length is over 2^(28 - 5)")); var ret = await WriteFIFO( JtagAddr.WRITE_CMD, - Common.Number.MultiBitsToNumber(JtagCmd.CMD_JTAG_LOAD_DR_CAREO, JtagCmd.LEN_CMD_JTAG, 8 * bytesLen, 28).Value, + Common.Number.MultiBitsToNumber(JtagCmd.CMD_JTAG_LOAD_DR_CAREO, JtagCmd.LEN_CMD_JTAG, 32 * UInt32Num, 28).Value, 0x01_00_00_00, JtagState.CMD_EXEC_FINISH); if (ret.Value) @@ -745,6 +760,31 @@ public class Jtag return new(new Exception("LoadDRCareo Failed!")); } + async ValueTask> LoadDRCareOutputArray(UInt32 UInt32Num) + { + if (UInt32Num > Math.Pow(2, 23)) return new(new Exception("Length is over 2^(28 - 5)")); + + var ret = await WriteFIFO( + JtagAddr.WRITE_CMD, + Common.Number.MultiBitsToNumber(JtagCmd.CMD_JTAG_LOAD_DR_CAREO, JtagCmd.LEN_CMD_JTAG, 32 * UInt32Num, 28).Value, + 0x01_00_00_00, JtagState.CMD_EXEC_FINISH); + + if (ret.Value) + { + var array = new UInt32[UInt32Num]; + for (int i = 0; i < UInt32Num; i++) + { + var retData = await ReadFIFO(JtagAddr.READ_DATA); + if (!retData.IsSuccessful) + return new(new Exception("Read FIFO failed when Load DR")); + array[i] = retData.Value; + } + return array; + } + else + return new(new Exception("LoadDRCareo Failed!")); + } + /// /// 读取 JTAG 设备的 ID 代码 /// @@ -774,7 +814,7 @@ public class Jtag if (!ret.IsSuccessful) return new(ret.Error); else if (!ret.Value) return new(new Exception("Jtag Clear Write Registers Failed")); - var retData = await LoadDRCareOutput(4); + var retData = await LoadDRCareOutput(1); if (!retData.IsSuccessful) { return new(new Exception("Get ID Code Failed")); @@ -812,11 +852,9 @@ public class Jtag if (!ret.IsSuccessful) return new(ret.Error); else if (!ret.Value) return new(new Exception("Jtag Clear Write Registers Failed")); - var retData = await LoadDRCareOutput(4); + var retData = await LoadDRCareOutput(1); if (!retData.IsSuccessful) - { return new(new Exception("Read Status Reg Failed")); - } return retData.Value; } @@ -901,4 +939,46 @@ public class Jtag return true; } + + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:return] + public async ValueTask> BoundaryScan(int portNum) + { + if (portNum <= 0) + return new(new ArgumentException("The number of port couldn't be negative", nameof(portNum))); + + // Clear Data + await MsgBus.UDPServer.ClearUDPData(this.address); + + logger.Trace($"Clear up udp server {this.address} receive data"); + + Result ret; + + ret = await CloseTest(); + if (!ret.IsSuccessful) return new(ret.Error); + else if (!ret.Value) return new(new Exception("Jtag Close Test Failed")); + + ret = await RunTest(); + if (!ret.IsSuccessful) return new(ret.Error); + else if (!ret.Value) return new(new Exception("Jtag Run Test Failed")); + + logger.Trace("Jtag initialize"); + + ret = await ExecRDCmd(JtagCmd.JTAG_DR_SAMPLE); + if (!ret.IsSuccessful) return new(ret.Error); + else if (!ret.Value) return new(new Exception("Jtag Execute Command JTAG_DR_JRST Failed")); + + var retData = await LoadDRCareOutputArray(((uint)(portNum % 32 == 0 ? portNum / 32 : portNum / 32 + 1))); + if (!retData.IsSuccessful) + return new(new Exception("Read Status Reg Failed")); + + ret = await CloseTest(); + if (!ret.IsSuccessful) return new(ret.Error); + else if (!ret.Value) return new(new Exception("Jtag Close Test Failed")); + + return new JtagBoundaryRegister() { PortNum = portNum, PortStatus = retData.Value }; + } } diff --git a/vite.config.ts b/vite.config.ts index 3101b16..ac0ddd8 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -6,6 +6,7 @@ import vueJsx from '@vitejs/plugin-vue-jsx' import vueDevTools from 'vite-plugin-vue-devtools' import tailwindcss from '@tailwindcss/postcss' import autoprefixer from 'autoprefixer' +import basicSsl from '@vitejs/plugin-basic-ssl' // https://vite.dev/config/ export default defineConfig({ @@ -20,6 +21,7 @@ export default defineConfig({ }), vueJsx(), vueDevTools(), + // basicSsl() ], resolve: { alias: { @@ -33,5 +35,9 @@ export default defineConfig({ autoprefixer() ] } + }, + build: { + outDir: 'wwwroot', + emptyOutDir: true, // also necessary } })