using System.Net; using Common; using DotNext; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; 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 /// [ApiController] [Route("api/[controller]")] public class UDPController : ControllerBase { private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); private const string LOCALHOST = "127.0.0.1"; /// /// 页面 /// [HttpGet] public string Index() { return "This is UDP Controller"; } /// /// 发送字符串 /// /// IPV4 或者 IPV6 地址 /// 设备端口号 /// 发送的文本 /// 发送成功 /// 发送失败 [HttpPost("SendString")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async ValueTask SendString(string address = LOCALHOST, int port = 1234, string text = "Hello Server!") { var endPoint = new IPEndPoint(IPAddress.Parse(address), port); var ret = await UDPClientPool.SendStringAsync(endPoint, [text]); if (ret) { return TypedResults.Ok(); } else { return TypedResults.InternalServerError(); } } /// /// 发送二进制数据 /// /// IPV4 或者 IPV6 地址 /// 设备端口号 /// 16进制文本 [HttpPost("SendBytes")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async ValueTask SendBytes(string address, int port, string bytes) { var endPoint = new IPEndPoint(IPAddress.Parse(address), port); var ret = await UDPClientPool.SendBytesAsync(endPoint, Number.StringToBytes(bytes)); if (ret) { return TypedResults.Ok(); } else { return TypedResults.InternalServerError(); } } /// /// 发送地址包 /// /// IP地址 /// UDP 端口号 /// 地址包选项 [HttpPost("SendAddrPackage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async ValueTask SendAddrPackage( string address, int port, [FromBody] SendAddrPackOptions opts) { var endPoint = new IPEndPoint(IPAddress.Parse(address), port); var ret = await UDPClientPool.SendAddrPackAsync(endPoint, new WebProtocol.SendAddrPackage(opts)); if (ret) { return TypedResults.Ok(); } else { return TypedResults.InternalServerError(); } } /// /// 发送数据包 /// /// IP地址 /// UDP 端口号 /// 16进制数据 [HttpPost("SendDataPackage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async ValueTask SendDataPackage(string address, int port, string data) { var endPoint = new IPEndPoint(IPAddress.Parse(address), port); var ret = await UDPClientPool.SendDataPackAsync(endPoint, new WebProtocol.SendDataPackage(Number.StringToBytes(data))); if (ret) { return TypedResults.Ok(); } else { return TypedResults.InternalServerError(); } } /// /// 获取指定IP地址接受的数据列表 /// /// IP地址 [HttpGet("GetRecvDataArray")] [ProducesResponseType(typeof(List), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async ValueTask GetRecvDataArray(string address) { var ret = await MsgBus.UDPServer.GetDataArrayAsync(address); if (ret.HasValue) { var dataJson = JsonConvert.SerializeObject(ret.Value); logger.Debug($"Get Receive Successfully: {dataJson}"); return TypedResults.Ok(ret.Value); } else { logger.Debug("Get Receive Failed"); return TypedResults.InternalServerError(); } } } /// /// Jtag API /// [ApiController] [Route("api/[controller]")] public class JtagController : ControllerBase { private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); private const string BITSTREAM_PATH = "bitstream/Jtag"; /// /// 页面 /// [HttpGet] public string Index() { return "This is Jtag Controller"; } /// /// 执行一个Jtag命令 /// /// 设备地址 /// 设备端口 /// 16进制设备目的地址(Jtag) /// 16进制命令 [HttpPost("RunCommand")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async ValueTask RunCommand(string address, int port, string hexDevAddr, string hexCmd) { var jtagCtrl = new JtagClient.Jtag(address, port); var ret = await jtagCtrl.WriteFIFO(Convert.ToUInt32(hexDevAddr, 16), Convert.ToUInt32(hexCmd, 16)); if (ret.IsSuccessful) { return TypedResults.Ok(ret.Value); } else { return TypedResults.InternalServerError(ret.Error); } } /// /// 获取Jtag ID Code /// /// 设备地址 /// 设备端口 [HttpGet("GetDeviceIDCode")] [ProducesResponseType(typeof(uint), StatusCodes.Status200OK)] [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] public async ValueTask GetDeviceIDCode(string address, int port) { var jtagCtrl = new JtagClient.Jtag(address, port); var ret = await jtagCtrl.ReadIDCode(); if (ret.IsSuccessful) { logger.Info($"Get device {address} ID code: 0x{ret.Value:X4}"); return TypedResults.Ok(ret.Value); } else { logger.Error(ret.Error); return TypedResults.InternalServerError(ret.Error); } } /// /// 获取状态寄存器 /// /// 设备地址 /// 设备端口 [HttpGet("ReadStatusReg")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async ValueTask ReadStatusReg(string address, int port) { var jtagCtrl = new JtagClient.Jtag(address, port); var ret = await jtagCtrl.ReadStatusReg(); if (ret.IsSuccessful) { var binaryValue = Common.String.Reverse(Convert.ToString(ret.Value, 2).PadLeft(32, '0')); var decodeValue = new JtagClient.JtagStatusReg(ret.Value); logger.Info($"Read device {address} Status Register: \n\t 0b{binaryValue} \n\t {decodeValue}"); return TypedResults.Ok(new { original = ret.Value, binaryValue, decodeValue, }); } else { logger.Error(ret.Error); return TypedResults.InternalServerError(ret.Error); } } /// /// 上传比特流文件 /// /// 设备地址 /// 比特流文件 [HttpPost("UploadBitstream")] [EnableCors("Users")] [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)] [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)] public async ValueTask UploadBitstream(string address, IFormFile file) { if (file == null || file.Length == 0) return TypedResults.BadRequest("未选择文件"); // 生成安全的文件名(避免路径遍历攻击) var fileName = Path.GetRandomFileName(); var uploadsFolder = Path.Combine(Environment.CurrentDirectory, $"{BITSTREAM_PATH}/{address}"); // 如果存在文件,则删除原文件再上传 if (Directory.Exists(uploadsFolder)) { Directory.Delete(uploadsFolder, true); } Directory.CreateDirectory(uploadsFolder); var filePath = Path.Combine(uploadsFolder, fileName); using (var stream = new FileStream(filePath, FileMode.Create)) { await file.CopyToAsync(stream); } logger.Info($"Device {address} Upload Bitstream Successfully"); return TypedResults.Ok(true); } /// /// 通过Jtag下载比特流文件 /// /// 设备地址 /// 设备端口 [HttpPost("DownloadBitstream")] [EnableCors("Users")] [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)] [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] public async ValueTask DownloadBitstream(string address, int port) { // 检查文件 var fileDir = Path.Combine(Environment.CurrentDirectory, $"{BITSTREAM_PATH}/{address}"); if (!Directory.Exists(fileDir)) return TypedResults.BadRequest("Empty bitstream, Please upload it first"); try { // 读取文件 var filePath = Directory.GetFiles(fileDir)[0]; 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"); // 定义缓冲区大小: 32KB byte[] buffer = new byte[32 * 1024]; byte[] revBuffer = new byte[32 * 1024]; long totalBytesRead = 0; // 使用异步流读取文件 using (var memoryStream = new MemoryStream()) { int bytesRead; while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { // 反转 32bits var retBuffer = Common.Number.ReverseBytes(buffer, 4); if (!retBuffer.IsSuccessful) return TypedResults.InternalServerError(retBuffer.Error); revBuffer = retBuffer.Value; await memoryStream.WriteAsync(revBuffer, 0, bytesRead); totalBytesRead += bytesRead; } // 将所有数据转换为字节数组(注意:如果文件非常大,可能不适合完全加载到内存) var fileBytes = memoryStream.ToArray(); // 下载比特流 var jtagCtrl = new JtagClient.Jtag(address, port); var ret = await jtagCtrl.DownloadBitstream(fileBytes); if (ret.IsSuccessful) { logger.Info($"Device {address} dowload bitstream successfully"); return TypedResults.Ok(ret.Value); } else { logger.Error(ret.Error); return TypedResults.InternalServerError(ret.Error); } } } } catch (Exception error) { return TypedResults.InternalServerError(error); } finally { } } /// /// [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); } } /// /// 远程更新 /// [ApiController] [Route("api/[controller]")] public class RemoteUpdater : ControllerBase { private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); private const string BITSTREAM_PATH = "bitstream/RemoteUpdate"; /// /// 上传远程更新比特流文件 /// /// 设备地址 /// 黄金比特流文件 /// 比特流文件1 /// 比特流文件2 /// 比特流文件3 /// 上传结果 [HttpPost("UploadBitstream")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public async ValueTask UploadBitstreams( string address, IFormFile? goldenBitream, IFormFile? bitstream1, IFormFile? bitstream2, IFormFile? bitstream3) { if ((goldenBitream is null || goldenBitream.Length == 0) && (bitstream1 is null || bitstream1.Length == 0) && (bitstream2 is null || bitstream2.Length == 0) && (bitstream3 is null || bitstream3.Length == 0)) return TypedResults.BadRequest("未选择文件"); // 生成安全的文件名(避免路径遍历攻击) var fileName = Path.GetRandomFileName(); var uploadsFolder = Path.Combine(Environment.CurrentDirectory, $"{BITSTREAM_PATH}/{address}"); // 如果存在文件,则删除原文件再上传 if (Directory.Exists(uploadsFolder)) { Directory.Delete(uploadsFolder, true); } Directory.CreateDirectory(uploadsFolder); for (int bitstreamNum = 0; bitstreamNum < 4; bitstreamNum++) { IFormFile file; if (bitstreamNum == 0 && goldenBitream is not null) file = goldenBitream; else if (bitstreamNum == 1 && bitstream1 is not null) file = bitstream1; else if (bitstreamNum == 2 && bitstream2 is not null) file = bitstream2; else if (bitstreamNum == 3 && bitstream3 is not null) file = bitstream3; else continue; var fileFolder = Path.Combine(uploadsFolder, bitstreamNum.ToString()); Directory.CreateDirectory(fileFolder); var filePath = Path.Combine(fileFolder, fileName); using (var stream = new FileStream(filePath, FileMode.Create)) { await file.CopyToAsync(stream); } } logger.Info($"Device {address} Upload Bitstream Successfully"); return TypedResults.Ok("Bitstream Upload Successfully"); } private async ValueTask> ProcessBitstream(string filePath) { using (var fileStream = System.IO.File.Open(filePath, System.IO.FileMode.Open)) { if (fileStream is null || fileStream.Length <= 0) return new(new ArgumentException("Wrong bitstream path")); // 定义缓冲区大小: 32KB byte[] buffer = new byte[32 * 1024]; byte[] revBuffer = new byte[32 * 1024]; long totalBytesRead = 0; // 使用异步流读取文件 using (var memoryStream = new MemoryStream()) { int bytesRead; while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { // 反转 32bits var retBuffer = Common.Number.ReverseBytes(buffer, 4); if (!retBuffer.IsSuccessful) return new(retBuffer.Error); revBuffer = retBuffer.Value; await memoryStream.WriteAsync(revBuffer, 0, bytesRead); totalBytesRead += bytesRead; } // 将所有数据转换为字节数组(注意:如果文件非常大,可能不适合完全加载到内存) var restStreamLen = memoryStream.Length % (4 * 1024); if (restStreamLen != 0) { var appendLen = ((int)(4 * 1024 - restStreamLen)); var bytesAppend = new byte[appendLen]; Array.Fill(bytesAppend, 0xFF); await memoryStream.WriteAsync(bytesAppend, 0, appendLen); } return new(memoryStream.ToArray()); } } } /// /// 远程更新单个比特流文件 /// /// 设备地址 /// 设备端口 /// 比特流位号 [HttpPost("DownloadBitstream")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async ValueTask UpdateBitstream(string address, int port, int bitstreamNum) { // 检查文件 var fileDir = Path.Combine(Environment.CurrentDirectory, $"{BITSTREAM_PATH}/{address}/{bitstreamNum}"); if (!Directory.Exists(fileDir)) return TypedResults.BadRequest("Empty bitstream, Please upload it first"); try { // 读取文件 var filePath = Directory.GetFiles(fileDir)[0]; var fileBytes = await ProcessBitstream(filePath); if (!fileBytes.IsSuccessful) return TypedResults.InternalServerError(fileBytes.Error); // 下载比特流 var remoteUpdater = new RemoteUpdate.RemoteUpdateClient(address, port); var ret = await remoteUpdater.UpdateBitstream(bitstreamNum, fileBytes.Value); if (ret.IsSuccessful) { logger.Info($"Device {address} Update bitstream successfully"); return TypedResults.Ok(ret.Value); } else { logger.Error(ret.Error); return TypedResults.InternalServerError(ret.Error); } } catch (Exception error) { return TypedResults.InternalServerError(error); } } /// /// 下载多个比特流文件 /// /// 设备地址 /// 设备端口 /// 比特流编号 /// 总共上传比特流的数量 [HttpPost("DownloadMultiBitstreams")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async ValueTask DownloadMultiBitstreams(string address, int port, int? bitstreamNum) { // 检查文件 var bitstreamsFolder = Path.Combine(Environment.CurrentDirectory, $"{BITSTREAM_PATH}/{address}"); if (!Directory.Exists(bitstreamsFolder)) return TypedResults.BadRequest("Empty bitstream, Please upload it first"); try { var bitstreams = new List() { null, null, null, null }; int cnt = 0; // 上传比特流数量 for (int i = 0; i < 4; i++) { var bitstreamDir = Path.Combine(bitstreamsFolder, i.ToString()); if (!Directory.Exists(bitstreamDir)) continue; cnt++; // 读取文件 var filePath = Directory.GetFiles(bitstreamDir)[0]; var fileBytes = await ProcessBitstream(filePath); if (!fileBytes.IsSuccessful) return TypedResults.InternalServerError(fileBytes.Error); bitstreams[i] = fileBytes.Value; } // 下载比特流 var remoteUpdater = new RemoteUpdate.RemoteUpdateClient(address, port); { var ret = await remoteUpdater.UploadBitstreams(bitstreams[0], bitstreams[1], bitstreams[2], bitstreams[3]); if (!ret.IsSuccessful) return TypedResults.InternalServerError(ret.Error); if (!ret.Value) return TypedResults.InternalServerError("Upload MultiBitstreams failed"); } if (bitstreamNum is not null) { var ret = await remoteUpdater.HotResetBitstream(bitstreamNum ?? 0); if (!ret.IsSuccessful) return TypedResults.InternalServerError(ret.Error); if (!ret.Value) return TypedResults.InternalServerError("Hot reset failed"); } return TypedResults.Ok(cnt); } catch (Exception error) { return TypedResults.InternalServerError(error); } } /// /// 热复位比特流文件 /// /// 设备地址 /// 设备端口 /// 比特流编号 /// 操作结果 [HttpPost("HotResetBitstream")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async ValueTask HotResetBitstream(string address, int port, int bitstreamNum) { var remoteUpdater = new RemoteUpdate.RemoteUpdateClient(address, port); var ret = await remoteUpdater.HotResetBitstream(bitstreamNum); if (ret.IsSuccessful) { logger.Info($"Device {address}即可 Update bitstream successfully"); return TypedResults.Ok(ret.Value); } else { logger.Error(ret.Error); return TypedResults.InternalServerError(ret.Error); } } } /// /// 数据控制器 /// [ApiController] [Route("api/[controller]")] public class Data : ControllerBase { private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); /// /// 创建数据库表 /// /// 插入的记录数 [EnableCors("Development")] [HttpPost("CreateTable")] public IResult CreateTables() { using var db = new Database.AppDataConnection(); db.CreateAllTables(); return TypedResults.Ok(); } /// /// 删除数据库表 /// /// 插入的记录数 [EnableCors("Development")] [HttpDelete("DropTables")] public IResult DropTables() { using var db = new Database.AppDataConnection(); db.DropAllTables(); return TypedResults.Ok(); } /// /// 获取所有用户 /// /// 用户列表 [HttpGet("AllUsers")] public IResult AllUsers() { using var db = new Database.AppDataConnection(); var ret = db.User.ToList(); return TypedResults.Ok(ret); } /// /// 注册新用户 /// /// 用户名 /// 操作结果 [HttpPost("SignUpUser")] public IResult SignUpUser(string name) { if (name.Length > 255) return TypedResults.BadRequest("Name Couln't over 255 characters"); using var db = new Database.AppDataConnection(); var ret = db.AddUser(name); return TypedResults.Ok(ret); } } /// /// 日志控制器 /// [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]; }