LEDColorArtNet.cs 10.5 KB
using SmartShelf.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace SmartShelf.DeviceLibrary
{ 
    /// <summary>
    /// 三色灯ArtNet协议,RGB,红蓝绿
    /// </summary>
    public class LEDColorArtNet : LEDBaseModule
    { 
        //private const ushort Max_DMX = 16;
        //private int Max_Light = 170;
        private int datalength = 512;

        private List<byte[]> dmxDatas = null;
        private string phyIP = "";
        private string phyAddr = "00";
        private  IPEndPoint iep = null;
        internal LEDColorArtNet(string ip) : base(ip)
        {
            this.phyIP = ip;

            phyAddr = "00";
            if (!String.IsNullOrEmpty(LEDManager.DefaultIP) || LEDManager.ConnectionMode.Equals(1))
            {
                try
                {
                    string[] array = phyIP.Split('.');
                    if (array.Length == 4)
                    {
                        int addr = Convert.ToInt32(array[3]);

                        phyAddr = ((byte)addr).ToString("X2");
                    }
                }
                catch (Exception ex)
                {
                    LogUtil.error("IP【" + ip + "】解析phyAddr出错:" + ex.ToString());
                }
            }
            if (!String.IsNullOrEmpty(LEDManager.DefaultIP) && LEDManager.ConnectionMode.Equals(0))
            {
                iep = new IPEndPoint(IPAddress.Parse(LEDManager.DefaultIP), 6454);
            }
            else
            {
                iep = new IPEndPoint(IPAddress.Parse(ip), 6454);
            }
            LogUtil.info(" LEDColorArtNet 初始化 IP ["+ phyIP + "] phyAddr["+phyAddr+ "] iep.Address [" + iep.Address+"]");
            Max_Light = 170;
            Max_DMX = 16;
            datalength = 512;
            Max_Light = datalength / 3;
            dmxDatas = new List<byte[]>(Max_DMX);

            AllLightOff();
        }

        private void InitDatas()
        {

            dmxDatas = new List<byte[]>(Max_DMX);
            for (int i = 0; i < Max_DMX; i++)
            {
                dmxDatas.Add(new byte[datalength]);
            }
        }
        private void UpdateLightData(int dmx, int index, byte red = 0, byte green = 0, byte blue = 0)
        {
            int ldmx = dmx;
            int lIndex = index;
            if (index >= Max_Light)
            {
                ldmx = index / Max_Light;
                lIndex = index % Max_Light;
            }
            if (ldmx >= dmxDatas.Count)
            {
                LogUtil.error(" UpdateLightData error:  dmx [" + ldmx + "] MAX_UNI[" + Max_DMX + "]");
                return;
            }
            byte[] data = dmxDatas[ldmx];

            int redIndex = LEDManager.ColorRule.IndexOf('R');
            int greedIndex = LEDManager.ColorRule.IndexOf('G');
            int blueIndex = LEDManager.ColorRule.IndexOf('B');

            //SPI第二通道为蓝色,DMX第二通道为绿色
            data[lIndex * 3+redIndex] = red;
            data[lIndex * 3 + greedIndex] = green;
            data[lIndex * 3 + blueIndex] = blue;

            ////SPI第二通道为蓝色,DMX第二通道为绿色
            //data[lIndex * 3] = red;
            //data[lIndex * 3 + 1] = green;
            //data[lIndex * 3 + 2] = blue;
        }
        public override void AllLightOff(int dmx = -1)
        {
            InitDatas();
            PushToDevice();
        }

        public override void AllLightOn(int dmx = -1)
        {
            AllLightOn(Light.DefaultLight(dmx, 1));
        }

        public override void AllLightOn(Light light)
        {
            for (int i = 0; i < Max_DMX; i++)
            {
                byte[] data = dmxDatas[i];
                for (int index = 0; index < Max_Light; index++)
                {
                    UpdateLightData(i, index, light.Red, light.Green, light.Blue);
                }
            }
            PushToDevice();
        }

        /// <summary>
        /// 只有某些灯亮,其他灯灭掉
        /// </summary>
        /// <param name="lights"></param>
        public override void OnlyLightOn(params Light[] lights)
        {
            AllLightOff();
            LightOn(lights);
        }

        /// <summary>
        /// 在之前的状态之上点亮某些灯
        /// </summary>
        /// <param name="lights"></param>
        public override void LightOn(params Light[] lights)
        {
            foreach (Light light in lights)
            {
                UpdateLightData(light.dmx, light.index, light.Red, light.Green, light.Blue);

            }
            PushToDevice();
        }

        public override void LightOff(int dmx, params int[] lightIndexs)
        {
            foreach (int lightId in lightIndexs)
            {
                UpdateLightData(dmx, lightId, 0, 0, 0);

            }

            PushToDevice();
        }
        public override void LightOff(params Light[] lights)
        {
            foreach (Light light in lights)
            {
                UpdateLightData(light.dmx, light.index, 0, 0, 0);

            }

            PushToDevice();
        }


        private void PushToDevice()
        {
            //闲置的时候会有不起作用的情况,这里多发几遍
            for (int time = 0; time < 2; time++)
            {
                UdpClient myUdpClient = new UdpClient(); 
                try
                {
                    for (int i = 0; i < dmxDatas.Count; i++)
                    {
                        byte[] toSend = ToSPIData(i, dmxDatas[i]);
                        myUdpClient.Send(toSend, toSend.Length, iep);
                    }
                }
                catch (Exception err)
                {
                    Console.WriteLine("发送失败");
                }
                finally
                {
                    myUdpClient.Close();
                }

            }
        }



        /// <summary>
        /// 46:51:35:31:32:4e:65:74: 	数据包头[16]	 
        //0b:00:	OpCode
        //40:
        //06: 序列号
        //00:
        //01: 更新标准:0=写到缓存,未输出到dmxData;1=无缓存,立即输出到dmxData
        //03:	0=没有广播,只控制指定域;1=对设备的所有端口广播;2=对某个子网内的所有域广播;3,对网络下的所有子网广播;0xff=对所有网络设备的所有口广播
        //34:	字节的高4位为子网,字节的低4位为dmxData域,;子网:0~15,DMX域:0~15;
        //02:	IP灯光网络地址:0~127
        //02:00:  通道数512
        //00:00:00: 第0个灯RBG
        //00:00:00: 第1个灯RBG
        //...: 第n个灯RBG
        /// </summary>
        /// <returns></returns>
        private byte[] ToSPIData(int dmxIndex, byte[] dmxData)
        {
            string ID = "41:72:74:2D:4E:65:74:00:";// 8字节数据包头: "FQ512Net" 
            //string head = "46:51:35:31:32:4e:65:74:";// 8字节数据包头: "FQ512Net" 
            string OpCode = "00:50:";	 //指令2字节
            string ProVer = "000e";
            string seq = "00";
            string phy = "00";
            phy = phyAddr;
            string SubUni = "00";
            SubUni = String.Format("{0:X}", dmxIndex).PadLeft(2, '0');
            string Net = "00";
            int len = dmxData.Length;
            string str = String.Format("{0:X}", dmxData.Length).PadLeft(4, '0');

            string length = "0200";
            length = str;
            //string Broadcast = "0";//0=没有广播,只控制指定域;1=对设备的所有端口广播;2=对某个子网内的所有域广播;3,对网络下的所有子网广播;0xff=对所有网络设备的所有口广播
            //string SubUni = "00";// IP灯光子网地址:0~255;子网又可分,字节的高4位为子网,字节的低4位为dmxData域,;子网:0~15,DMX域:0~15;
            //string net = "" + dmxIndex + "00"; //IP灯光网络地址:0~127
            string preStr = ID + OpCode + ProVer + seq + phy + SubUni + Net + length;
            //       preStr = "4172742d4e657400:0050:";
            byte[] preBytes = StringToByte(preStr);
            byte[] toSend = new byte[preBytes.Length + dmxData.Length];
            Array.Copy(preBytes, 0, toSend, 0, preBytes.Length);
            Array.Copy(dmxData, 0, toSend, preBytes.Length, dmxData.Length);
            return toSend;
        }
        //41 72 74 2D 4E 65 74 00 00 20 00 0E 00 00

        //        Artnet 地址
        //Artnet 协议中,设备的设置一般为 X:Y,其中 X 为 subnet, Y 为 universe,均为 16
        //进制,共可以容纳 256 个 Universe。此时对应的控台端,当设置对应的 Universe
        //的时候应注意 16 进制到 10 进制的转换。比如 Artnet 协议设备端(Arkaos)设
        //置为 2:1,则控台端应设备为 16*2+1 = 33.
        //控台的 IP 地址应设置为:2.B.C.D ,其中 BCD 为 0-255

        //41 72 74 2D 4E 65 74 00 00 50 00 0E 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
    }
}