NanjingSDotIO.cs 10.4 KB
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TSA_V.DeviceLibrary;

class NanjingSDotIO : IOBase
{
    byte station = 1;
    public string IP;
    TcpClient tcpClient = new TcpClient();
    Thread iomonitorThread;
    ushort seq = 0;
    /// <summary>
    /// 
    /// </summary>
    /// <param name="changindex">变化的io列表</param>
    /// <param name="sta">所有IO状态</param>
    public delegate void IO_Changed(List<int> changindex, bool[] sta);
    public event IO_Changed DI_Changed_Event;
    public event IO_Changed DO_Changed_Event;
    /// <summary>
    /// 连接状态变化, 手动连接不触发
    /// </summary>
    public event EventHandler<bool> ConnectionState_Event;
    public NanjingSDotIO()
    {
        DIStartAddress = 0;
        DoStartAddress = 0;
    }
    ~NanjingSDotIO()
    {
        iomonitorrun = false;
        Close();
    }
    bool systemrun = false;
    /// <summary>
    /// 打开IO
    /// </summary>
    /// <returns></returns>
    public bool Open()
    {

        tcpClient.Dispose();
        tcpClient = new TcpClient();
        tcpClient.ReceiveTimeout = 50;
        tcpClient.SendTimeout = 50;
        lock (tcpClient)
        {
            try
            {
                var connectResult = tcpClient.ConnectAsync(IP, 502);
                if (connectResult.Wait(1000))
                {
                    systemrun = true;
                    iomonitorrun = true;
                    iomonitorThread = new Thread(new ThreadStart(iomonitor));
                    iomonitorThread.Start();
                    ConnectionState_Event?.Invoke(this, true);
                    return true;
                }
                else
                {

                    tcpClient.EndConnect(connectResult);
                    tcpClient.Close();
                    return false;
                }
            }
            catch
            {
                return false;
            }
        }

    }
    /// <summary>
    /// 关闭IO
    /// </summary>
    public void Close()
    {
        try
        {
            systemrun = false;
            iomonitorrun = false;
            if (tcpClient.Connected)
                tcpClient.Close();
        }
        catch { }
    }
    /// <summary>
    /// 连接状态
    /// </summary>
    public bool IsConn
    {
        get => iomonitorrun && systemrun;
    }

    bool iomonitorrun = false;
    /// <summary>
    /// 循环读全部IO
    /// </summary>
    void iomonitor()
    {
        try
        {
            iomonitorrun = true;
            while (iomonitorrun && systemrun)
            {
                Thread.Sleep(2);
                try
                {
                    ReadDO();
                }
                catch (SocketException)
                {
                    if (tcpClient != null && tcpClient.Connected)
                        tcpClient.Close();
                    ConnectionState_Event?.Invoke(this, false);
                    iomonitorrun = false;
                }
            }
            if (systemrun)
            {
                do
                {
                    Thread.Sleep(1000);
                } while (systemrun && !Open());
            }
        }
        catch (Exception ex)
        {
            TSA_V.Common.LogUtil.error($"IO模块{IP}出错:" + ex.ToString());
        }
    }

    /// <summary>
    /// 写io
    /// </summary>
    /// <param name="donum">地址</param>
    /// <param name="state">On/Off</param>
    /// <returns></returns>
    public bool WriteDO(int donum, bool state)
    {
        byte funCode = 0x0F;//批量写圈
        byte startAddress = (byte)(64 + donum);//写圈起始地址
        byte startLength = 1;
        var seqhead = BitConverter.GetBytes(seq);
        byte iostate = (byte)(state ? 1 : 0);
        byte[] by = new byte[]
        {
                //事物标识符
                seqhead[0],
                seqhead[1],
                //协议标识符 固定值
                0x00,
                0x00,
                //长度
                0x00,
                0x06,
                //从站地址
                station,
                //功能码
                funCode,
                0x00,
                startAddress, //起始地址
                0x00,
                startLength, //读个数
                0x01,
                iostate
        };
        by[5] = (byte)(by.Length - 6);
        bool check = true;
        lock (tcpClient)
        {
            try
            {
                seqadd();
                tcpClient.Client.Send(by);
                byte[] result = new byte[100];
                var ulength = tcpClient.Client.Receive(result);
                var newResult = result.ToList().Take(ulength).ToArray();
                if (newResult[0] == seqhead[0] && newResult[1] == seqhead[1])
                {
                    check = true;
                }
                else
                {
                    return false;
                }
            }
            catch
            {
                return false;
            }
        }


        /*
        var newResult = result.ToList().Take(ulength).ToArray();
        //输出报文
        var output = string.Join(" ", newResult.Select(x => x.ToString("X2")));

        */
        return check;
    }
    /// <summary>
    /// 所有DI状态
    /// </summary>
    public bool[] DIstate = new bool[64];
    /// <summary>
    /// 所有DO状态
    /// </summary>
    public bool[] DOstate = new bool[64];
    bool[] lastDIstate = new bool[64];
    bool[] lastDOstate = new bool[64];
    /// <summary>
    /// 读全部IO
    /// </summary>
    void ReadDO()
    {
        byte funCode = 0x01;//批量写圈
        byte startAddress = 0;//写圈起始地址
        byte startLength = 128;
        var seqhead = BitConverter.GetBytes(seq);
        byte[] by = new byte[]
        {
                //事物标识符
                seqhead[0],
                seqhead[1],
                //协议标识符 固定值
                0x00,
                0x00,
                //长度
                0x00,
                0x06,
                //从站地址
                station,
                //功能码
                funCode,
                0x00,
                startAddress, //起始地址
                0x00,
                startLength, //读个数
        };
        by[5] = (byte)(by.Length - 6);
        byte[] result = new byte[100];
        int ulength = 0;

        lock (tcpClient)
        {
            try
            {
                seqadd();
                tcpClient.Client.Send(by);
                ulength = tcpClient.Client.Receive(result);

            }
            catch (SocketException se)
            {
                throw se;
            }
        }
        var newResult = result;//.ToList().Take(ulength).ToArray();
                               //aa = BitConverter.ToString(newResult);
                               //Console.WriteLine(aa);
        if (newResult[0] == seqhead[0] && newResult[1] == seqhead[1])
        {
            int diIndex = 9;
            int doIndex = 17;

            for (int i = 0; i < 32; i++)
            {
                int a = (int)Math.Floor(i / 8d);
                int b = a * 2;
                DIstate[i + 8 * a] = Convert.ToBoolean(newResult[diIndex + b] >> i & 0x01);
                DIstate[i + 8 + 8 * a] = Convert.ToBoolean(newResult[diIndex + 1 + b] >> i & 0x01);
                DOstate[i + 8 * a] = Convert.ToBoolean(newResult[doIndex + b] >> i & 0x01);
                DOstate[i + 8 + 8 * a] = Convert.ToBoolean(newResult[doIndex + 1 + b] >> i & 0x01);
            }
            for (int i = 0; i < 64; i++)
            {
                List<int> dichgindex = new List<int>();
                List<int> dochgindex = new List<int>();
                if (lastDIstate[i] != DIstate[i])
                {
                    dichgindex.Add(i);
                    lastDIstate[i] = DIstate[i];
                }
                if (lastDOstate[i] != DOstate[i])
                {
                    dochgindex.Add(i);
                    lastDOstate[i] = DOstate[i];
                }
                if (dichgindex.Count > 0)
                    DI_Changed_Event?.BeginInvoke(dichgindex, DIstate, null, null);
                if (dochgindex.Count > 0)
                    DO_Changed_Event?.BeginInvoke(dochgindex, DOstate, null, null);
            }
        }
        else
        {

        }
        //输出报文
        //var output = string.Join(" ", newResult.Select(x => x.ToString("X2")));

    }

    void seqadd()
    {
        seq++;
        if (seq >= ushort.MaxValue - 10)
            seq = 0;
    }

    public override void ConnectionKND(List<string> dIODeviceNameList)
    {
    }

    public override void ReadAllDI(string deviceName, byte slaveId)
    {
        ReadDO();
    }

    public override void ReadAllDO(string deviceName, byte slaveId)
    {
        ReadDO();
    }

    public override void ConnectionIP(string kNDIP, ushort kNDPort)
    {
        this.IP = kNDIP;
        Open();
        iomonitorThread = new Thread(new ThreadStart(iomonitor));
    }

    public override void WriteSingleDO(string deviceName, byte slaveId, ushort index, IO_VALUE value, int time)
    {
        WriteDO(index, value == IO_VALUE.HIGH);
    }

    public override bool IsConnection(string kNDIP)
    {
        return IsConn;
    }

    public override void WriteSingleDO(string deviceName, byte slaveId, ushort index, IO_VALUE value)
    {
        WriteDO(index, value == IO_VALUE.HIGH);
    }

    public override IO_VALUE GetDIValue(string deviceName, byte slaveID, ushort v)
    {
        return DIstate[v] ? IO_VALUE.HIGH : IO_VALUE.LOW;
    }

    public override IO_VALUE GetDOValue(string deviceName, byte slaveID, ushort v)
    {
        return DOstate[v] ? IO_VALUE.HIGH : IO_VALUE.LOW;
    }

    public override IO_VALUE GetIOValue(ConfigIO configIO)
    {
        if (configIO.ProType.Equals(ConfigItemType.DI))
        {
            return DIstate[configIO.IOIndex] ? IO_VALUE.HIGH : IO_VALUE.LOW;
        }
        else {
            return DOstate[configIO.IOIndex] ? IO_VALUE.HIGH : IO_VALUE.LOW;
        }

            
    }

    public override void CloseAllDO()
    {
        for (int i = 0; i < 32; i++)
        {
            WriteDO(i, false);
        }
    }

    public override void CloseAllConnection()
    {
        Close();
    }
}