This repository has been archived on 2025-10-29. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
FPGA_WebLab/server/src/Peripherals/WS2812Client.cs

171 lines
5.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Net;
using DotNext;
using Tapper;
namespace Peripherals.WS2812Client;
class WS2812Addr
{
public const UInt32 BASE = 0xB0_00_01_00;
public const int LED_COUNT = 128;
}
/// <summary>
/// RGB颜色结构体包含红、绿、蓝三个颜色分量
/// </summary>
[TranspilationSource]
public class 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);
}
}
}