fix: 修改部分外设BASE偏移量;增加WS2812后端监控器;DSO寄
This commit is contained in:
168
server/src/Peripherals/WS2812Client.cs
Normal file
168
server/src/Peripherals/WS2812Client.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
using System.Net;
|
||||
using DotNext;
|
||||
|
||||
namespace Peripherals.WS2812Client;
|
||||
|
||||
class WS2812Addr
|
||||
{
|
||||
public const UInt32 BASE = 0xB0_00_01_00;
|
||||
public const int LED_COUNT = 128;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RGB颜色结构体,包含红、绿、蓝三个颜色分量
|
||||
/// </summary>
|
||||
public struct RGBColor
|
||||
{
|
||||
public byte Red { get; set; }
|
||||
public byte Green { get; set; }
|
||||
public byte Blue { get; set; }
|
||||
|
||||
public RGBColor(byte red, byte green, byte blue)
|
||||
{
|
||||
Red = red;
|
||||
Green = green;
|
||||
Blue = blue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从32位数据的低24位提取RGB颜色
|
||||
/// </summary>
|
||||
/// <param name="data">32位数据</param>
|
||||
/// <returns>RGB颜色</returns>
|
||||
public static RGBColor FromUInt32(UInt32 data)
|
||||
{
|
||||
return new RGBColor(
|
||||
(byte)((data >> 16) & 0xFF), // Red
|
||||
(byte)((data >> 8) & 0xFF), // Green
|
||||
(byte)(data & 0xFF) // Blue
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为32位数据格式
|
||||
/// </summary>
|
||||
/// <returns>32位数据</returns>
|
||||
public UInt32 ToUInt32()
|
||||
{
|
||||
return ((UInt32)Red << 16) | ((UInt32)Green << 8) | (UInt32)Blue;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"RGB({Red}, {Green}, {Blue})";
|
||||
}
|
||||
}
|
||||
|
||||
public class WS2812Client
|
||||
{
|
||||
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
|
||||
readonly int timeout = 500;
|
||||
readonly int taskID;
|
||||
readonly int port;
|
||||
readonly string address;
|
||||
private IPEndPoint ep;
|
||||
|
||||
public WS2812Client(string address, int port, int taskID, int timeout = 500)
|
||||
{
|
||||
if (timeout < 0)
|
||||
throw new ArgumentException("Timeout couldn't be negative", nameof(timeout));
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
this.ep = new IPEndPoint(IPAddress.Parse(address), port);
|
||||
this.taskID = taskID;
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定灯珠的RGB颜色
|
||||
/// </summary>
|
||||
/// <param name="ledIndex">灯珠索引,范围0-127</param>
|
||||
/// <returns>RGB颜色结果</returns>
|
||||
public async ValueTask<Result<RGBColor>> GetLedColor(int ledIndex)
|
||||
{
|
||||
if (ledIndex < 0 || ledIndex >= WS2812Addr.LED_COUNT)
|
||||
{
|
||||
return new(new ArgumentOutOfRangeException(nameof(ledIndex),
|
||||
$"LED index must be between 0 and {WS2812Addr.LED_COUNT - 1}"));
|
||||
}
|
||||
|
||||
if (MsgBus.IsRunning)
|
||||
MsgBus.UDPServer.ClearUDPData(this.address, this.taskID);
|
||||
else
|
||||
return new(new Exception("Message Bus not work!"));
|
||||
|
||||
var addr = WS2812Addr.BASE + (UInt32)(ledIndex * 4); // 每个地址32位,步长为4字节
|
||||
var ret = await UDPClientPool.ReadAddrByte(this.ep, this.taskID, addr, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Get LED {ledIndex} color failed: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
var retData = ret.Value.Options.Data;
|
||||
if (retData is null)
|
||||
return new(new Exception($"Device {address} receive none"));
|
||||
if (retData.Length < 4)
|
||||
{
|
||||
var error = new Exception($"Invalid data length: expected 4 bytes, got {retData.Length}");
|
||||
logger.Error($"Get LED {ledIndex} color failed: {error}");
|
||||
return new(error);
|
||||
}
|
||||
|
||||
var colorData = Convert.ToUInt32(Common.Number.BytesToUInt64(retData).Value);
|
||||
var color = RGBColor.FromUInt32(colorData);
|
||||
return new(color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有灯珠的RGB颜色
|
||||
/// </summary>
|
||||
/// <returns>包含所有灯珠颜色的数组</returns>
|
||||
public async ValueTask<Result<RGBColor[]>> GetAllLedColors()
|
||||
{
|
||||
if (MsgBus.IsRunning)
|
||||
MsgBus.UDPServer.ClearUDPData(this.address, this.taskID);
|
||||
else
|
||||
return new(new Exception("Message Bus not work!"));
|
||||
|
||||
try
|
||||
{
|
||||
// 一次性读取所有LED数据,每个LED占用4字节,总共128*4=512字节
|
||||
var ret = await UDPClientPool.ReadAddr4Bytes(this.ep, this.taskID, WS2812Addr.BASE, WS2812Addr.LED_COUNT, this.timeout);
|
||||
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Get all LED colors failed: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
|
||||
var data = ret.Value;
|
||||
var expectedLength = WS2812Addr.LED_COUNT * 4; // 128 * 4 = 512 bytes
|
||||
|
||||
if (data.Length < expectedLength)
|
||||
{
|
||||
var error = new Exception($"Invalid data length: expected {expectedLength} bytes, got {data.Length}");
|
||||
logger.Error(error.Message);
|
||||
return new(error);
|
||||
}
|
||||
|
||||
var colors = new RGBColor[WS2812Addr.LED_COUNT];
|
||||
|
||||
for (int i = 0; i < WS2812Addr.LED_COUNT; i++)
|
||||
{
|
||||
var offset = i * 4;
|
||||
// 将4字节数据转换为UInt32
|
||||
var colorData = BitConverter.ToUInt32(data, offset);
|
||||
colors[i] = RGBColor.FromUInt32(colorData);
|
||||
}
|
||||
|
||||
return new(colors);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error($"Get all LED colors failed: {ex}");
|
||||
return new(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user