diff --git a/server/src/Controllers/NetConfigController.cs b/server/src/Controllers/NetConfigController.cs
new file mode 100644
index 0000000..c86ef5c
--- /dev/null
+++ b/server/src/Controllers/NetConfigController.cs
@@ -0,0 +1,280 @@
+using System.Net;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Cors;
+using Microsoft.AspNetCore.Mvc;
+using Peripherals.NetConfigClient;
+
+namespace server.Controllers;
+
+///
+/// 网络配置控制器(仅管理员权限)
+///
+[ApiController]
+[Route("api/[controller]")]
+[Authorize("Admin")]
+public class NetConfigController : ControllerBase
+{
+ private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
+
+ ///
+ /// 设置主机IP地址
+ ///
+ /// 板卡ID
+ /// 主机IP地址
+ /// 任务ID,默认为0
+ /// 操作结果
+ [HttpPost("SetHostIP")]
+ [EnableCors("Users")]
+ [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task SetHostIP(Guid boardId, string hostIp)
+ {
+ if (boardId == Guid.Empty)
+ return BadRequest("板卡ID不能为空");
+
+ if (string.IsNullOrWhiteSpace(hostIp))
+ return BadRequest("主机IP地址不能为空");
+
+ if (!IPAddress.TryParse(hostIp, out var ipAddress))
+ return BadRequest("IP地址格式不正确");
+
+ try
+ {
+ // 获取板卡信息
+ using var db = new Database.AppDataConnection();
+ var boardRet = db.GetBoardByID(boardId);
+ if (!boardRet.IsSuccessful)
+ return StatusCode(StatusCodes.Status500InternalServerError, "数据库操作失败");
+ if (!boardRet.Value.HasValue)
+ return NotFound("未找到对应的板卡");
+
+ var board = boardRet.Value.Value;
+
+ // 创建网络配置客户端
+ var netConfig = new NetConfig(board.IPAddr, board.Port, 0);
+ var result = await netConfig.SetHostIP(ipAddress);
+
+ if (!result.IsSuccessful)
+ {
+ logger.Error($"设置主机IP失败: {result.Error}");
+ return StatusCode(StatusCodes.Status500InternalServerError, $"设置失败: {result.Error}");
+ }
+
+ return Ok(result.Value);
+ }
+ catch (Exception ex)
+ {
+ logger.Error(ex, "设置主机IP时发生异常");
+ return StatusCode(StatusCodes.Status500InternalServerError, "设置失败,请稍后重试");
+ }
+ }
+
+ ///
+ /// 设置板卡IP地址
+ ///
+ /// 板卡ID
+ /// 板卡IP地址
+ /// 任务ID,默认为0
+ /// 操作结果
+ [HttpPost("SetBoardIP")]
+ [EnableCors("Users")]
+ [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task SetBoardIP(Guid boardId, string boardIp)
+ {
+ if (boardId == Guid.Empty)
+ return BadRequest("板卡ID不能为空");
+
+ if (string.IsNullOrWhiteSpace(boardIp))
+ return BadRequest("板卡IP地址不能为空");
+
+ if (!IPAddress.TryParse(boardIp, out var ipAddress))
+ return BadRequest("IP地址格式不正确");
+
+ try
+ {
+ // 获取板卡信息
+ using var db = new Database.AppDataConnection();
+ var boardRet = db.GetBoardByID(boardId);
+ if (!boardRet.IsSuccessful)
+ return StatusCode(StatusCodes.Status500InternalServerError, "数据库操作失败");
+ if (!boardRet.Value.HasValue)
+ return NotFound("未找到对应的板卡");
+
+ var board = boardRet.Value.Value;
+
+ // 创建网络配置客户端
+ var netConfig = new NetConfig(board.IPAddr, board.Port, 0);
+ var result = await netConfig.SetBoardIP(ipAddress);
+
+ if (!result.IsSuccessful)
+ {
+ logger.Error($"设置板卡IP失败: {result.Error}");
+ return StatusCode(StatusCodes.Status500InternalServerError, $"设置失败: {result.Error}");
+ }
+
+ return Ok(result.Value);
+ }
+ catch (Exception ex)
+ {
+ logger.Error(ex, "设置板卡IP时发生异常");
+ return StatusCode(StatusCodes.Status500InternalServerError, "设置失败,请稍后重试");
+ }
+ }
+
+ ///
+ /// 设置主机MAC地址
+ ///
+ /// 板卡ID
+ /// 主机MAC地址(格式:AA:BB:CC:DD:EE:FF)
+ /// 任务ID,默认为0
+ /// 操作结果
+ [HttpPost("SetHostMAC")]
+ [EnableCors("Users")]
+ [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task SetHostMAC(Guid boardId, string hostMac)
+ {
+ if (boardId == Guid.Empty)
+ return BadRequest("板卡ID不能为空");
+
+ if (string.IsNullOrWhiteSpace(hostMac))
+ return BadRequest("主机MAC地址不能为空");
+
+ // 解析MAC地址
+ if (!TryParseMacAddress(hostMac, out var macBytes))
+ return BadRequest("MAC地址格式不正确,请使用格式:AA:BB:CC:DD:EE:FF");
+
+ try
+ {
+ // 获取板卡信息
+ using var db = new Database.AppDataConnection();
+ var boardRet = db.GetBoardByID(boardId);
+ if (!boardRet.IsSuccessful)
+ return StatusCode(StatusCodes.Status500InternalServerError, "数据库操作失败");
+ if (!boardRet.Value.HasValue)
+ return NotFound("未找到对应的板卡");
+
+ var board = boardRet.Value.Value;
+
+ // 创建网络配置客户端
+ var netConfig = new NetConfig(board.IPAddr, board.Port, 0);
+ var result = await netConfig.SetHostMAC(macBytes);
+
+ if (!result.IsSuccessful)
+ {
+ logger.Error($"设置主机MAC地址失败: {result.Error}");
+ return StatusCode(StatusCodes.Status500InternalServerError, $"设置失败: {result.Error}");
+ }
+
+ return Ok(result.Value);
+ }
+ catch (Exception ex)
+ {
+ logger.Error(ex, "设置主机MAC地址时发生异常");
+ return StatusCode(StatusCodes.Status500InternalServerError, "设置失败,请稍后重试");
+ }
+ }
+
+ ///
+ /// 设置板卡MAC地址
+ ///
+ /// 板卡ID
+ /// 板卡MAC地址(格式:AA:BB:CC:DD:EE:FF)
+ /// 任务ID,默认为0
+ /// 操作结果
+ [HttpPost("SetBoardMAC")]
+ [EnableCors("Users")]
+ [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task SetBoardMAC(Guid boardId, string boardMac)
+ {
+ if (boardId == Guid.Empty)
+ return BadRequest("板卡ID不能为空");
+
+ if (string.IsNullOrWhiteSpace(boardMac))
+ return BadRequest("板卡MAC地址不能为空");
+
+ // 解析MAC地址
+ if (!TryParseMacAddress(boardMac, out var macBytes))
+ return BadRequest("MAC地址格式不正确,请使用格式:AA:BB:CC:DD:EE:FF");
+
+ try
+ {
+ // 获取板卡信息
+ using var db = new Database.AppDataConnection();
+ var boardRet = db.GetBoardByID(boardId);
+ if (!boardRet.IsSuccessful)
+ return StatusCode(StatusCodes.Status500InternalServerError, "数据库操作失败");
+ if (!boardRet.Value.HasValue)
+ return NotFound("未找到对应的板卡");
+
+ var board = boardRet.Value.Value;
+
+ // 创建网络配置客户端
+ var netConfig = new NetConfig(board.IPAddr, board.Port, 0);
+ var result = await netConfig.SetBoardMAC(macBytes);
+
+ if (!result.IsSuccessful)
+ {
+ logger.Error($"设置板卡MAC地址失败: {result.Error}");
+ return StatusCode(StatusCodes.Status500InternalServerError, $"设置失败: {result.Error}");
+ }
+
+ return Ok(result.Value);
+ }
+ catch (Exception ex)
+ {
+ logger.Error(ex, "设置板卡MAC地址时发生异常");
+ return StatusCode(StatusCodes.Status500InternalServerError, "设置失败,请稍后重试");
+ }
+ }
+
+ ///
+ /// 解析MAC地址字符串为字节数组
+ ///
+ /// MAC地址字符串
+ /// 解析后的字节数组
+ /// 是否解析成功
+ private static bool TryParseMacAddress(string macAddress, out byte[] macBytes)
+ {
+ macBytes = Array.Empty();
+
+ if (string.IsNullOrWhiteSpace(macAddress))
+ return false;
+
+ // 移除可能的分隔符并统一为冒号
+ var cleanMac = macAddress.Replace("-", ":").Replace(" ", "").ToUpper();
+
+ // 验证格式
+ if (cleanMac.Length != 17 || cleanMac.Count(c => c == ':') != 5)
+ return false;
+
+ var parts = cleanMac.Split(':');
+ if (parts.Length != 6)
+ return false;
+
+ try
+ {
+ macBytes = new byte[6];
+ for (int i = 0; i < 6; i++)
+ {
+ macBytes[i] = Convert.ToByte(parts[i], 16);
+ }
+ return true;
+ }
+ catch
+ {
+ macBytes = Array.Empty();
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/server/src/Peripherals/NetConfigClient.cs b/server/src/Peripherals/NetConfigClient.cs
new file mode 100644
index 0000000..78d7ffe
--- /dev/null
+++ b/server/src/Peripherals/NetConfigClient.cs
@@ -0,0 +1,174 @@
+using System.Net;
+using DotNext;
+
+namespace Peripherals.NetConfigClient;
+
+static class NetConfigAddr
+{
+ const UInt32 BASE = 0x30A7_0000;
+
+ public static readonly UInt32[] HOST_IP = { BASE + 0, BASE + 1, BASE + 2, BASE + 3 };
+ public static readonly UInt32[] BOARD_IP = { BASE + 4, BASE + 5, BASE + 6, BASE + 7 };
+ public static readonly UInt32[] HOST_MAC = { BASE + 8, BASE + 9, BASE + 10, BASE + 11, BASE + 12, BASE + 13 };
+ public static readonly UInt32[] BOARD_MAC = { BASE + 14, BASE + 15, BASE + 16, BASE + 17, BASE + 18, BASE + 19 };
+}
+
+
+///
+/// [TODO:description]
+///
+public class NetConfig
+{
+ private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
+
+ readonly int timeout = 2000;
+ readonly int taskID;
+ readonly int port;
+ readonly string address;
+ private IPEndPoint ep;
+
+ ///
+ /// [TODO:description]
+ ///
+ /// [TODO:parameter]
+ /// [TODO:parameter]
+ /// [TODO:parameter]
+ /// [TODO:parameter]
+ /// [TODO:return]
+ public NetConfig(string address, int port, int taskID, int timeout = 2000)
+ {
+ if (timeout < 0)
+ throw new ArgumentException("Timeout couldn't be negative", nameof(timeout));
+ this.address = address;
+ this.taskID = taskID;
+ this.port = port;
+ this.ep = new IPEndPoint(IPAddress.Parse(address), port);
+ this.timeout = timeout;
+ }
+
+ ///
+ /// [TODO:description]
+ ///
+ /// [TODO:parameter]
+ /// [TODO:return]
+ public async ValueTask> SetHostIP(IPAddress ip)
+ {
+ // 清除UDP服务器接收缓冲区
+ MsgBus.UDPServer.ClearUDPData(this.address, this.taskID);
+
+ var ipBytes = ip.GetAddressBytes();
+
+ {
+ var ret = await UDPClientPool.WriteAddrSeq(this.ep, this.taskID, NetConfigAddr.HOST_IP, ipBytes, this.timeout);
+ if (!ret.IsSuccessful)
+ {
+ logger.Error($"Failed to set host IP: {ret.Error}");
+ return new(ret.Error);
+ }
+
+ if (!ret.Value)
+ {
+ logger.Error($"Failed to set host IP: operation returned false");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ ///
+ /// [TODO:description]
+ ///
+ /// [TODO:parameter]
+ /// [TODO:return]
+ public async ValueTask> SetBoardIP(IPAddress ip)
+ {
+ // 清除UDP服务器接收缓冲区
+ MsgBus.UDPServer.ClearUDPData(this.address, this.taskID);
+
+ var ipBytes = ip.GetAddressBytes();
+
+ {
+ var ret = await UDPClientPool.WriteAddrSeq(this.ep, this.taskID, NetConfigAddr.BOARD_IP, ipBytes, this.timeout);
+ if (!ret.IsSuccessful)
+ {
+ logger.Error($"Failed to set board IP: {ret.Error}");
+ return new(ret.Error);
+ }
+
+ if (!ret.Value)
+ {
+ logger.Error($"Failed to set board IP: operation returned false");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ ///
+ /// [TODO:description]
+ ///
+ /// [TODO:parameter]
+ /// [TODO:return]
+ public async ValueTask> SetHostMAC(byte[] macAddress)
+ {
+ if (macAddress == null)
+ throw new ArgumentNullException(nameof(macAddress));
+ if (macAddress.Length != 6)
+ throw new ArgumentException("MAC address must be 6 bytes", nameof(macAddress));
+
+ // 清除UDP服务器接收缓冲区
+ MsgBus.UDPServer.ClearUDPData(this.address, this.taskID);
+
+ {
+ var ret = await UDPClientPool.WriteAddrSeq(this.ep, this.taskID, NetConfigAddr.HOST_MAC, macAddress, this.timeout);
+ if (!ret.IsSuccessful)
+ {
+ logger.Error($"Failed to set host MAC address: {ret.Error}");
+ return new(ret.Error);
+ }
+
+ if (!ret.Value)
+ {
+ logger.Error($"Failed to set host MAC address: operation returned false");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ ///
+ /// [TODO:description]
+ ///
+ /// [TODO:parameter]
+ /// [TODO:return]
+ public async ValueTask> SetBoardMAC(byte[] macAddress)
+ {
+ if (macAddress == null)
+ throw new ArgumentNullException(nameof(macAddress));
+ if (macAddress.Length != 6)
+ throw new ArgumentException("MAC address must be 6 bytes", nameof(macAddress));
+
+ // 清除UDP服务器接收缓冲区
+ MsgBus.UDPServer.ClearUDPData(this.address, this.taskID);
+
+ {
+ var ret = await UDPClientPool.WriteAddrSeq(this.ep, this.taskID, NetConfigAddr.BOARD_MAC, macAddress, this.timeout);
+ if (!ret.IsSuccessful)
+ {
+ logger.Error($"Failed to set board MAC address: {ret.Error}");
+ return new(ret.Error);
+ }
+
+ if (!ret.Value)
+ {
+ logger.Error($"Failed to set board MAC address: operation returned false");
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/server/src/UdpClientPool.cs b/server/src/UdpClientPool.cs
index 8620c63..3064459 100644
--- a/server/src/UdpClientPool.cs
+++ b/server/src/UdpClientPool.cs
@@ -559,7 +559,6 @@ public class UDPClientPool
IsWrite = true,
};
-
// Write Register
ret = await UDPClientPool.SendAddrPackAsync(endPoint, new SendAddrPackage(opts));
if (!ret) return new(new Exception("Send 1st address package failed!"));
@@ -602,8 +601,6 @@ public class UDPClientPool
IsWrite = true,
};
-
-
// Check Msg Bus
if (!MsgBus.IsRunning)
return new(new Exception("Message bus not working!"));
@@ -644,4 +641,40 @@ public class UDPClientPool
return true;
}
+
+ ///
+ /// [TODO:description]
+ ///
+ /// [TODO:parameter]
+ /// [TODO:parameter]
+ /// [TODO:parameter]
+ /// [TODO:parameter]
+ /// [TODO:parameter]
+ /// [TODO:return]
+ public static async ValueTask> WriteAddrSeq(IPEndPoint endPoint, int taskID, UInt32[] addr, byte[] data, int timeout = 1000)
+ {
+ var length = addr.Length;
+ if (length != data.Length)
+ {
+ logger.Error($"TODO");
+ return new(new ArgumentException($"TODO"));
+ }
+
+ for (int i = 0; i < length; i++)
+ {
+ var ret = await WriteAddr(endPoint, taskID, addr[i], (UInt32)data[i], timeout);
+ if (!ret.IsSuccessful)
+ {
+ logger.Error($"TODO");
+ return new(ret.Error);
+ }
+ if (!ret.Value)
+ {
+ logger.Error($"TODO");
+ return false;
+ }
+ }
+
+ return true;
+ }
}
diff --git a/server/src/UdpServer.cs b/server/src/UdpServer.cs
index a2f0452..f5d9323 100644
--- a/server/src/UdpServer.cs
+++ b/server/src/UdpServer.cs
@@ -266,7 +266,6 @@ public class UDPServer
sortedList.Clear();
break;
}
-
}
}
catch