feat: 完成实验板动态ip与动态mac

This commit is contained in:
SikongJueluo 2025-07-17 15:49:31 +08:00
parent e4ead72d53
commit f5dd474ba0
No known key found for this signature in database
4 changed files with 490 additions and 4 deletions

View File

@ -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;
/// <summary>
/// 网络配置控制器(仅管理员权限)
/// </summary>
[ApiController]
[Route("api/[controller]")]
[Authorize("Admin")]
public class NetConfigController : ControllerBase
{
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
/// <summary>
/// 设置主机IP地址
/// </summary>
/// <param name="boardId">板卡ID</param>
/// <param name="hostIp">主机IP地址</param>
/// <param name="taskId">任务ID默认为0</param>
/// <returns>操作结果</returns>
[HttpPost("SetHostIP")]
[EnableCors("Users")]
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> 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, "设置失败,请稍后重试");
}
}
/// <summary>
/// 设置板卡IP地址
/// </summary>
/// <param name="boardId">板卡ID</param>
/// <param name="boardIp">板卡IP地址</param>
/// <param name="taskId">任务ID默认为0</param>
/// <returns>操作结果</returns>
[HttpPost("SetBoardIP")]
[EnableCors("Users")]
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> 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, "设置失败,请稍后重试");
}
}
/// <summary>
/// 设置主机MAC地址
/// </summary>
/// <param name="boardId">板卡ID</param>
/// <param name="hostMac">主机MAC地址格式AA:BB:CC:DD:EE:FF</param>
/// <param name="taskId">任务ID默认为0</param>
/// <returns>操作结果</returns>
[HttpPost("SetHostMAC")]
[EnableCors("Users")]
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> 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, "设置失败,请稍后重试");
}
}
/// <summary>
/// 设置板卡MAC地址
/// </summary>
/// <param name="boardId">板卡ID</param>
/// <param name="boardMac">板卡MAC地址格式AA:BB:CC:DD:EE:FF</param>
/// <param name="taskId">任务ID默认为0</param>
/// <returns>操作结果</returns>
[HttpPost("SetBoardMAC")]
[EnableCors("Users")]
[ProducesResponseType(typeof(bool), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> 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, "设置失败,请稍后重试");
}
}
/// <summary>
/// 解析MAC地址字符串为字节数组
/// </summary>
/// <param name="macAddress">MAC地址字符串</param>
/// <param name="macBytes">解析后的字节数组</param>
/// <returns>是否解析成功</returns>
private static bool TryParseMacAddress(string macAddress, out byte[] macBytes)
{
macBytes = Array.Empty<byte>();
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<byte>();
return false;
}
}
}

View File

@ -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 };
}
/// <summary>
/// [TODO:description]
/// </summary>
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;
/// <summary>
/// [TODO:description]
/// </summary>
/// <param name="address">[TODO:parameter]</param>
/// <param name="port">[TODO:parameter]</param>
/// <param name="taskID">[TODO:parameter]</param>
/// <param name="timeout">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
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;
}
/// <summary>
/// [TODO:description]
/// </summary>
/// <param name="ip">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
public async ValueTask<Result<bool>> 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;
}
/// <summary>
/// [TODO:description]
/// </summary>
/// <param name="ip">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
public async ValueTask<Result<bool>> 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;
}
/// <summary>
/// [TODO:description]
/// </summary>
/// <param name="macAddress">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
public async ValueTask<Result<bool>> 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;
}
/// <summary>
/// [TODO:description]
/// </summary>
/// <param name="macAddress">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
public async ValueTask<Result<bool>> 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;
}
}

View File

@ -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;
}
/// <summary>
/// [TODO:description]
/// </summary>
/// <param name="endPoint">[TODO:parameter]</param>
/// <param name="taskID">[TODO:parameter]</param>
/// <param name="addr">[TODO:parameter]</param>
/// <param name="data">[TODO:parameter]</param>
/// <param name="timeout">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
public static async ValueTask<Result<bool>> 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;
}
}

View File

@ -266,7 +266,6 @@ public class UDPServer
sortedList.Clear();
break;
}
}
}
catch