/* * Copyright (c) 2025 LG Electronics Inc. * SPDX-License-Identifier: LicenseRef-LGE-Proprietary */ using Aurora.Api.Devices; using System; using System.Collections.Generic; using System.Text; namespace VisionLight { /// /// [상시 조명 컨트롤러 - 4CH / 시리얼 통신][Series] /// Range : (0,255) /// Baudrate : 19200 or 9600 bps /// DataBit : 8 bit /// StopBit : 1 bit /// ParityBit : None /// internal class Light_LVS_PN : LightBase_Serial { public const byte CMD_SINGLE_CHANNEL_OFF = 0x45; // E public const byte CMD_SINGLE_CHANNEL_BRIGHTNESS = 0x4C; // L public const byte CMD_ALL_CHANNEL_BRIGHTNESS = 0x41; // A public const byte CMD_VALUE_SEPARATOR = 0x2C; // , public const byte BYTE_ACK = 0x06; // 06 public const byte BYTE_NAK = 0x15; // 21 public const byte BYTE_CR = 0x0D; // 13 public const byte BYTE_LF = 0x0A; // 10 public const byte BYTE_0 = 0x30; // 48 public const byte LENGTH_SINGLE_CHANNEL_OFF_REQUEST_MSG = 4; public const byte LENGTH_SINGLE_CHANNEL_BRIGHTNESS_REQUEST_MSG = 7; public const byte LENGTH_ALL_CHANNEL_BRIGHTNESS_REQUEST_MSG = 18; public const byte LENGTH_RESPONSE_MSG = 1; public Light_LVS_PN(string deviceId) : base(deviceId) { } protected override eLightResult SetOnImpl(int channel) { SetLevelImpl(LastChLevels[channel], channel); return eLightResult.OK; } protected override eLightResult SetOffImpl(int channel) { if (!IsValidChannel(channel)) { LOG.E(string.Format("Argument Error! Ch : {0}", channel.ToString())); return eLightResult.NG; } lock (LockThis) { byte[] requestMsg = CreateSingleChannelOffReqMsg(channel); if (SerialConn.Write(requestMsg)) { byte[] responseMsg = new byte[LENGTH_RESPONSE_MSG]; if (SerialConn.Read(responseMsg) <= 0) { LOG.E("ReadError"); return eLightResult.NG; } var isValid = ValidateResponse(responseMsg); if (!isValid) { LOG.E("NAK"); return eLightResult.NG; } } } return eLightResult.OK; } private static byte[] CreateSingleChannelOffReqMsg(int iChannel) { byte[] requestMsg = new byte[LENGTH_SINGLE_CHANNEL_OFF_REQUEST_MSG]; requestMsg[0] = CMD_SINGLE_CHANNEL_OFF; requestMsg[1] = ConvertChannelIntToByte(iChannel); requestMsg[requestMsg.Length - 2] = BYTE_CR; requestMsg[requestMsg.Length - 1] = BYTE_LF; return requestMsg; } protected override eLightResult SetLevelImpl(int level, int channel) { try { if (!IsValidChannel(channel) || !IsValidBrightness(level)) { LOG.E(string.Format("Argument Error! Ch : {0}, Value : {1}", channel, level)); return eLightResult.NG; } lock (LockThis) { byte[] requestMsg = CreateSingleChannelBrightnessReqMsg(channel, level); if (SerialConn.Write(requestMsg)) { byte[] responseMsg = new byte[LENGTH_RESPONSE_MSG]; if (SerialConn.Read(responseMsg) <= 0) { LOG.E("ReadError"); return eLightResult.NG; } var isValid = ValidateResponse(responseMsg); if (!isValid) { LOG.E("NAK"); return eLightResult.NG; } } } return eLightResult.OK; } catch (Exception e) { LOG.FuncE(e.Message); } return eLightResult.NG; } private bool IsValidChannel(int channel) { return IsValidValue(channel, LightConfig.Channels.Min, LightConfig.Channels.Max); } private bool IsValidBrightness(int value) { return IsValidValue(value, LightConfig.DimRange.Min, LightConfig.DimRange.Max); } private static bool IsValidValue(int value, int min, int max) { return min <= value && value <= max; } private static byte[] CreateSingleChannelBrightnessReqMsg(int iChannel, int iValue) { byte[] requestMsg = new byte[LENGTH_SINGLE_CHANNEL_BRIGHTNESS_REQUEST_MSG]; byte[] valueByte = ConvertBrightnessIntToBytes(iValue); requestMsg[0] = CMD_SINGLE_CHANNEL_BRIGHTNESS; requestMsg[1] = ConvertChannelIntToByte(iChannel); Array.Copy(valueByte, 0, requestMsg, 2, valueByte.Length); requestMsg[requestMsg.Length - 2] = BYTE_CR; requestMsg[requestMsg.Length - 1] = BYTE_LF; return requestMsg; } private static byte ConvertChannelIntToByte(int iChannel) { return (byte)(iChannel + BYTE_0); } private static byte[] ConvertBrightnessIntToBytes(int iValue) { return Encoding.Default.GetBytes(ConvertBrightnessIntToString(iValue)); } private static string ConvertBrightnessIntToString(int iValue) { return string.Format("{0:000}", iValue); } private static bool ValidateResponse(byte[] msg) { return msg[0] == BYTE_ACK; } public bool SetLightValue(List values) { if (values.Count != LightConfig.Channels.Max) { return false; } for (int i = 0; i < values.Count; i++) { if (!IsValidBrightness(values[i])) { LOG.E(string.Format("Argument Error! Ch : {0}, Value : {1}", (i + 1), values[i])); return false; } } lock (LockThis) { byte[] requestMsg = CreateAllChannelBrightnessReqMsg(values); if (SerialConn.Write(requestMsg)) { byte[] responseMsg = new byte[LENGTH_RESPONSE_MSG]; if (SerialConn.Read(responseMsg) <= 0) { LOG.E("ReadError"); return false; } var isValid = ValidateResponse(responseMsg); if (!isValid) { LOG.E("NAK"); return false; } } } return true; } private static byte[] CreateAllChannelBrightnessReqMsg(List values) { byte[] requestMsg = new byte[LENGTH_ALL_CHANNEL_BRIGHTNESS_REQUEST_MSG]; byte[] valueByte = ConvertBrightnessIntToBytes(values); requestMsg[0] = CMD_ALL_CHANNEL_BRIGHTNESS; Array.Copy(valueByte, 0, requestMsg, 1, valueByte.Length); requestMsg[requestMsg.Length - 2] = BYTE_CR; requestMsg[requestMsg.Length - 1] = BYTE_LF; return requestMsg; } private static byte[] ConvertBrightnessIntToBytes(List values) { string valueStr = string.Format("{0},{1},{2},{3}", ConvertBrightnessIntToString(values[0]), ConvertBrightnessIntToString(values[1]), ConvertBrightnessIntToString(values[2]), ConvertBrightnessIntToString(values[3])); return Encoding.Default.GetBytes(valueStr); } } }