using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TeamAAS_VP.Models.Lights;
namespace TeamAAS_VP.Core.Lights
{
///
/// 基于 KCS 协议的光源控制器实现。
/// 该类通过注入的 与物理设备通信,
/// 并提供通道创建、连接/断开、初始化、全部开/关及通道亮度的内部读写实现。
///
public class KCSLightController : LightControllerBase
{
// 通信协议抽象,用于发送/接收字节数据
private readonly ICommunicationProtocol _protocol;
// 使用 ASCII 编码将字符串转换为字节流
private readonly Encoding _encoding;
//光源配置
private readonly LightControllerConfig _config;
///
/// 创建一个新的 实例。
///
/// 控制器的唯一标识符。
/// 用于与设备通信的协议实现(必须已实现连接/发送/接收等)。
/// 该控制器管理的通道数量。
/// 控制器的配置对象。
public KCSLightController(int id, ICommunicationProtocol protocol,int channelCount, LightControllerConfig config)
: base(id, channelCount,config)
{
_protocol = protocol;
_encoding = Encoding.ASCII;
_config = config;
}
///
/// 为指定索引创建通道实例。
///
/// 通道索引(从 0 开始)。
/// 通道名称。
/// 返回对应的 实例。
protected override ILightChannel CreateChannel(int index,string channelName)
{
return new KCSLightChannel(index, this, channelName);
}
///
/// 异步建立与设备的连接并在成功后执行初始化。
///
/// 若连接成功返回 true,否则返回 false。
public override async Task ConnectAsync()
{
var connected = await _protocol.ConnectAsync();
if (connected)
{
IsConnected = true;
await InitializeAsync();
}
return connected;
}
///
/// 异步断开与设备的连接并更新连接状态。
///
public override async Task DisconnectAsync()
{
await _protocol.DisconnectAsync();
IsConnected = false;
}
///
/// 异步初始化控制器,通常用于测试通信并同步初始状态。
/// 目前实现通过读取第 0 通道亮度来验证通信链路是否正常。
///
/// 若初始化成功返回 true;若发生异常或通信失败返回 false。
public override async Task InitializeAsync()
{
try
{
// 初始化操作:读取第 0 通道亮度以测试通信是否正常
await GetChannelBrightnessInternal(0); // 测试通信
return true;
}
catch
{
// 初始化失败(通信异常等)
return false;
}
}
///
/// 将所有通道设置为打开状态。命令格式参考控制器手册。
/// 构造格式示例:S{CH1:DDD}T{CH2:DDD}T...C#
/// 其中每个通道使用 3 位亮度值(D3),后跟动作字符 'T' 表示开。
///
/// 若设备返回确认字符 '!' 则认为操作成功。
public override async Task TurnOnAllAsync()
{
StringBuilder commandBuilder = new StringBuilder("S");
for (int i = 0; i < ChannelCount; i++)
{
var channel = (KCSLightChannel)ChannelsInternal[i];
// 使用三位数字格式表示亮度(例如 005、120、255)
commandBuilder.Append(channel.CurrentBrightness.ToString("D3"));
// 'T' 表示打开当前通道
commandBuilder.Append("T");
}
// 以 C# 结尾表示执行命令(协议特定)
commandBuilder.Append("C#");
var response = await SendCommandAsync(commandBuilder.ToString());
// 期望设备返回 "!" 表示成功(根据协议)
return response?.Trim() == "!";
}
///
/// 将所有通道设置为关闭状态。
/// 构造格式示例:S000F000F...C#
/// 其中 '000' 表示亮度 0,'F' 表示关闭通道。
///
/// 若设备返回确认字符 '!' 则认为操作成功。
public override async Task TurnOffAllAsync()
{
StringBuilder commandBuilder = new StringBuilder("S");
for (int i = 0; i < ChannelCount; i++)
{
// 将每个通道设置为 000(亮度 0)并附带 'F' 动作表示关闭
commandBuilder.Append("000");
commandBuilder.Append("F");
}
commandBuilder.Append("C#");
var response = await SendCommandAsync(commandBuilder.ToString());
return response?.Trim() == "!";
}
///
/// 将字符串命令编码为字节并通过协议发送,接收响应后以字符串返回。
///
/// 要发送的命令字符串(协议约定的格式)。
/// 设备响应的字符串表示(使用 ASCII 解码)。
internal async Task SendCommandAsync(string command)
{
var data = _encoding.GetBytes(command);
// 使用协议的 SendAndReceiveAsync 发送数据并等待响应(超时时间以协议或调用方为准)
var response = await _protocol.SendAndReceiveAsync(data, 1000);
return _encoding.GetString(response);
}
///
/// 读取指定通道的亮度(内部方法)。
/// 命令格式示例:S{ChannelLetter}#,例如读取第 0 通道为 S A #。
/// 响应预期长度为 5 字符,亮度位于索引 2..4(3 个字符)。
///
/// 通道索引(从 0 开始)。
/// 解析得到的亮度值(0-999);若解析失败或响应格式不符则返回 0。
internal async Task GetChannelBrightnessInternal(int channelIndex)
{
// 通道字母从 'A' 开始递增
string command = $"S{(char)('A' + channelIndex)}#";
if (_config.LightModel == LightModel.KCS_KDC3_24V300W_8T)
{
command = $"SR{(char)('A' + channelIndex)}#";
}
var response = await SendCommandAsync(command);
// 响应示例(假设):?XDDD(总长度 5),亮度在索引 2 开始的 3 个字符
if (response.Length == 5)
{
string valueStr = response.Substring(2, 3);
if (int.TryParse(valueStr, out int brightness))
{
return brightness;
}
}
else if (response.Length == 7)
{
string valueStr = response.Substring(3, 3);
if (int.TryParse(valueStr, out int brightness))
{
return brightness;
}
}
// 返回默认亮度 0(表示读取失败或设备返回异常)
return 0;
}
///
/// 设置指定通道的亮度(内部方法)。
/// 命令格式示例:S{ChannelLetter}0{DDD}#,其中 '0' 可能为协议占位符,具体请参考设备手册。
/// 成功时设备返回与通道字母相同的字符作为确认。
///
/// 通道索引(从 0 开始)。
/// 目标亮度(0-999)。方法内部会格式化为三位数字。
/// 若设备返回与通道字母相同的字符则认为设置成功。
internal async Task SetChannelBrightnessInternal(int channelIndex, int brightness)
{
string command = $"S{(char)('A' + channelIndex)}0{brightness.ToString("D3")}#";
var response = await SendCommandAsync(command);
if (response=="!")
{
return true;
}
// 成功时返回通道字母(例如 'A'),去除空白后比较
return response?.Trim() == ((char)('A' + channelIndex)).ToString();
}
}
}