NirenIO.cs 8.9 KB
using BLL;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

class NiRenIO: IO_Interface
{
    const int IoCount = 8;
    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_a;
    public event IO_Changed DO_Changed_Event;
    /// <summary>
    /// 连接状态变化, 手动连接不触发
    /// </summary>
    public event EventHandler<bool> ConnectionState_Event;
    public NiRenIO(string ip)
    {
        this.IP = ip;

        //DOdata[0] = 0x00;
        //DOdata[1] = 0x00;
        iomonitorThread = new Thread(new ThreadStart(iomonitor));
    }

    public event IOManage.DI_Changed DI_Changed_Event;


    ~NiRenIO()
    {
        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, 12345);
                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;
    }
    string IO_Interface.IP { get; set; }
    public int Port { get; set; }

    bool iomonitorrun = false;
    /// <summary>
    /// 循环读全部IO
    /// </summary>
    void iomonitor()
    {
        iomonitorrun = true;
        while (iomonitorrun && systemrun)
        {
            Thread.Sleep(3);
            try
            {
                ReadDO();
            }
            catch (SocketException)
            {
                readerrtimes = 0;
                if (tcpClient.Connected)
                    tcpClient.Close();
                ConnectionState_Event?.Invoke(this, false);
                iomonitorrun = false;
            }
            catch(Exception)
            {

            }
        }
        if (systemrun)
        {
            do
            {
                Thread.Sleep(1000);
            } while (systemrun && !Open());
        }
    }

    /// <summary>
    /// 写io
    /// </summary>
    /// <param name="donum">地址</param>
    /// <param name="state">On/Off</param>
    /// <returns></returns>
    public bool WriteDO(int donum, bool state)
    {

        const string CMD_WriteDI = "AT+STACH{0}={1}\r\n";

        var CMDSEND = string.Format(CMD_WriteDI, donum + 1, state ? "1": "0");
        Debug.WriteLine("CMDSEND:" + CMDSEND);
        var sendbyte = Encoding.ASCII.GetBytes(CMDSEND);
        lock (tcpClient)
        {
            try
            {
                tcpClient.Client.Send(sendbyte);
                Thread.Sleep(2);
                byte[] result = new byte[100];
                var ulength = tcpClient.Client.Receive(result);
                if (ulength > 0) {
                    var recive = Encoding.ASCII.GetString(result, 0, ulength);
                    Debug.WriteLine("recive:" + recive);
                    if (recive.StartsWith("OK"))
                        return true;
                }

            }
            catch
            {
                return false;
            }
        }


        return false;
    }
    /// <summary>
    /// 所有DI状态
    /// </summary>
    public bool[] DIstate = new bool[IoCount];
    /// <summary>
    /// 所有DO状态
    /// </summary>
    public bool[] DOstate = new bool[IoCount];
    bool[] lastDIstate = new bool[IoCount];
    bool[] lastDOstate = new bool[IoCount];
    int readerrtimes = 0;
    /// <summary>
    /// 读全部IO
    /// </summary>
    void ReadDO()
    {
        
        const string CMD_ReadDI = "AT+OCCH0=?\r\n";
        const string CMD_ReadD0 = "AT+STACH0=?\r\n";
        const string CMD_ReadALL = CMD_ReadDI + CMD_ReadD0;

        var sendbyte = Encoding.ASCII.GetBytes(CMD_ReadALL);
        Debug.WriteLine("CMD_ReadALL:"+ CMD_ReadALL);
        var resultbuffer = new byte[2048];
        int ulength = 0;
        lock (tcpClient)
        {
            try
            {
                tcpClient.Client.Send(sendbyte);
                Thread.Sleep(5);
                ulength = tcpClient.Client.Receive(resultbuffer);
                readerrtimes = 0;
            }
            catch (SocketException se)
            {
                readerrtimes++;
                Thread.Sleep(100);
                if (readerrtimes > 5)
                {
                    Debug.WriteLine("Read IO Error");
                    throw se;
                }
                return;
            }
        }
        if (ulength == 0) {
            return;        
        }

        var recive = Encoding.ASCII.GetString(resultbuffer, 0, ulength);
        Debug.WriteLine("recive:"+ recive);
        var datas = recive.Split(new char[] { '\r', '\n' });
        /*
            +STACH1:0,100000
            +STACH2:0,100000
            +OCCH1:0
            +OCCH2:0
         */
        foreach (var data in datas) {
            if (!data.StartsWith("+"))
                continue;

            if (data.StartsWith("+STACH"))
            {
                var ds = data.Split(':');
                var d = ds[0].Substring(6);
                if (!int.TryParse(d, out int doindex))
                    continue;
                doindex = doindex - 1;
                var sta = ds[1].StartsWith("1") ? true : false;
                DOstate[doindex] = sta;
            }
            else if (data.StartsWith("+OCCH"))
            {
                var ds = data.Split(':');
                var d = ds[0].Substring(5);
                if (!int.TryParse(d, out int doindex))
                    continue;
                doindex = doindex - 1;
                var sta = ds[1].StartsWith("1") ? true : false;
                DIstate[doindex] = sta;
            }

        }

        for (int i = 0; i < IoCount; 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_a?.BeginInvoke(dichgindex, DIstate, null, null);
                var statuses =DIstate.Select(d => { return d ? Status.On : Status.Off; }).ToArray();
                DI_Changed_Event?.BeginInvoke(statuses, null, null);
            }
            if (dochgindex.Count > 0)
                DO_Changed_Event?.BeginInvoke(dochgindex, DOstate, null, null);
        }

    }

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

    public bool Connect()
    {
        return Open();
    }

    public bool ReadDI(Addr add, out Status sta)
    {
        sta = Status.Off;
        try
        {
            int index = ((int)add) - 10200;
            var onoff = DIstate[index];
            sta = onoff? Status.On : Status.Off;
            return true;
        }
        catch
        {
            return false;
        }
    }

    public bool ReadDO(Addr add, out Status sta)
    {
        sta = DOstate[(int)add - 100]? Status.On : Status.Off;
        return true;
    }

    public bool WriteDO(int add, Status sta)
    {
        for (int i = 0; i < 10; i++)
        {
            if (WriteDO(add, sta == Status.On))
            {
                return true;
            }
            Thread.Sleep(100);
        }
        return false;
    }
}