using Aurora.Api.Devices; using Hermes; using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace AuroraLight.Fainstec { internal class ENLight : SerialConn, IENLight { private string _deviceId; private int _lightChannelCount; public bool _commError { get; set; } = false; private SerialConnConfig _connConfig; readonly int BYTE_MAX = 1024; public int[] LightValue { get; set; } const int LIGHT_MAX_VALUE = 255; protected int m_timeOut = 1; public ENLight(string deviceId, bool isSimul, int lightChannelCount) : base(deviceId, isSimul) { _deviceId = deviceId; _lightChannelCount = lightChannelCount; LightValue = new int[lightChannelCount]; } public enum _CommandType { SendStartOfHeader = 0x01, SendEndOfTransmission = 0x04, ReceiveAcknowledge = 0x06, ReceiveNegativeAcknowledge = 0x15, } public enum _OperationCoed { Write = 0x00, Read = 0x01, } public enum _RegisterAddress { ReadTestRegister = 0x00, ReadWriteTestRegister = 0x04, ChannelSelectRegister = 0x20, StepValueRegister = 0x28, ChannelOnOffRegister = 0x34, AllChannelBrightnessReadRegister1 = 0x38, AllChannelBrightnessReadRegister2 = 0x3C, EthernetEnvironmentAddressRegister = 0x40, EthernetEnvironmentDataRegister = 0x44, } public enum _ChannelControl { Channel1 = 0x01, Channel2 = 0x02, Channel3 = 0x04, Channel4 = 0x08, Channel5 = 0x10, Channel6 = 0x20, Channel7 = 0x40, Channel8 = 0x80, ChannelAll = 0xFF, } protected BitArray m_channelOnOffStatus = new BitArray(8); public BitArray ChannelOnOffStatus { get { lock (this) { return m_channelOnOffStatus; } } set { lock (this) { m_channelOnOffStatus = value; } } } #region 비트 연산 protected static byte[] BitArrayToByteArray(BitArray bits) { byte[] ret = new byte[(bits.Length - 1) / 8 + 1]; bits.CopyTo(ret, 0); return ret; } #endregion public bool InitInternal(SerialConnConfig conn) { _connConfig = conn; LightValue = Enumerable.Repeat(0, (int)_lightChannelCount).ToArray(); bool bRet = false; try { // Legacy 에는 Buffer clear 를 위한 Reset 함수가 있으나, Aurora SerialConn 에서는 Write 할때 Buffer clear 를 자동으로 해준다. // Open 할때 자동으로 켜줄것인가? 켜는함수는 따로 호출할것인가. Legacy 에서는 자동으로 켜줬는데 다른 Device 는 자동으로 켜주지 않는다. bRet = Open(_connConfig) == E1.OK; if (bRet) { bRet = OffLightInternal() == E1.OK; if (bRet) Log.D(string.Format("[ {0} CONNECTED ]", _deviceId)); _commError = !bRet; } else { _commError = true; } return bRet; } catch (Exception e) { Log.W($"InitInternal Failed. ( {e.Message} )"); return bRet; } } public bool IsPortErrorInternal() { return _commError; } public int OffLightInternal() { try { if (!IsConnected()) return E2.NOT_CONNECTED; SetAllLightPowerStatus(false); return E1.OK; } catch (Exception e) { Log.W($"OffLightInternal Failed. ( {e.Message} )"); return E2.CANCELLED; } } public int OffLightInternal(int iChannel) { try { if (!IsConnected()) return E2.NOT_CONNECTED; SetLightPowerStatus(iChannel, false); return E1.OK; } catch (Exception e) { Log.W($"{iChannel}ch OffLightInternal Failed. ( {e.Message} )"); return E2.CANCELLED; } } public int SetLightValueInternal(List values) { try { bool bRet = true; for (int i = 0; i < values.Count; i++) { if (SetLightBrightness(i, values[i]) != E1.OK) bRet = false; } return bRet ? E1.OK : E2.CANCELLED; } catch (Exception e) { Log.W($"SetLightValueInternal Failed. ( {e.Message} )"); return E2.CANCELLED; } } public int SetLightValueInternal(int iChannel, int iValue) { try { return SetLightBrightness(iChannel, iValue); } catch (Exception e) { Log.W($"{iChannel}ch SetLightValueInternal Failed. ( {e.Message} )"); return E2.CANCELLED; } } public void SetAllLightPowerStatus(bool on) { for (int i = 0; i < _lightChannelCount; i++) { SetLightPowerStatus(i, on); } } /// /// 조명의 채널을 키고 끄는 함수(밝기 값은 유지됨) /// /// 설정할 조명 채널(0부터 시작) /// ON/OFF public void SetLightPowerStatus(int channel, bool bOn) { try { if (!IsConnected()) return; else if (channel < 0 || _lightChannelCount - 1 < channel) return; lock (this) { byte[] command = new byte[6]; command[0] = Convert.ToByte(_CommandType.SendStartOfHeader); // SOH(Start Of Header) command[1] = Convert.ToByte(_OperationCoed.Write); // OperationCdoe(Write:0x00, Read:0x01) command[2] = 0x01; // DataLength command[3] = Convert.ToByte(_RegisterAddress.ChannelOnOffRegister); // Address ChannelOnOffStatus.Set(channel, bOn); command[4] = BitArrayToByteArray(ChannelOnOffStatus)[0]; command[5] = Convert.ToByte(_CommandType.SendEndOfTransmission); // EOT(End Of Transmission) // write 로 쓰고 read 로 받았는지 확인하는듯하다. // Aurora 에서는 ReadExisting 으로 하면 command 를 write 한 다음 대답을 받아오는것 같다. // on, off 는 어디서 처리? string strRecieve; ReadExisting(command, out strRecieve); //strRecieve 를 가지고 제대로 받았는지 return 할 수도 있을것 같다. } } catch (Exception e) { Log.W($"{channel}ch SetLightPowerStatus Failed. ( {e.Message} )"); } } public int SetLightBrightness(int channel, int brightnessValue) { try { if (!IsConnected()) return E2.NOT_CONNECTED; if (!ChannelValidCheck(channel)) return E2.INVALID_ARGUMENT; if (!ValueValidCheck(brightnessValue)) return E2.INVALID_ARGUMENT; lock (this) { uint targetLightValue = (uint)Math.Ceiling(LIGHT_MAX_VALUE * (brightnessValue * 0.01)); byte[] command = new byte[6]; command[0] = Convert.ToByte(_CommandType.SendStartOfHeader); // SOH(Start Of Header) command[1] = Convert.ToByte(_OperationCoed.Write); // OperationCdoe(Write:0x00, Read:0x01) command[2] = 0x01; // DataLength command[3] = Convert.ToByte(_RegisterAddress.StepValueRegister); // Address command[4] = Convert.ToByte(targetLightValue); // Data command[5] = Convert.ToByte(_CommandType.SendEndOfTransmission); // EOT(End Of Transmission) string strRecieve; ReadExisting(command, out strRecieve); byte receiveData = Convert.ToByte(strRecieve[0]); bool bAckExist = receiveData == (int)_CommandType.ReceiveAcknowledge ? true : false; bool bNakExist = receiveData == (int)_CommandType.ReceiveNegativeAcknowledge ? true : false; if (bAckExist == true && bNakExist == false) { LightValue[channel] = brightnessValue; return E1.OK; } else return E2.UNAVAILABLE; } } catch (Exception e) { Log.W($"{channel}ch SetLightBrightness Failed. ( {e.Message} )"); return E2.CANCELLED; } } private bool ChannelValidCheck(int iChannel) { if (iChannel < _lightChannelCount && iChannel >= 0) { return true; } else { Log.W($"Channel is not exist. Range : 0~{(int)_lightChannelCount - 1} Input : {iChannel}"); return false; } } private bool ValueValidCheck(int iValue) { if (iValue <= 255 && iValue >= 0) { return true; } else { Log.W($"LightValue Range Error. Range : 0~255, Input : {iValue}"); return false; } } } }