| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902 | using System.Net.Sockets;using System.Text.RegularExpressions;namespace FinsTcp;//This is a copy of a Open library POmronFinsTCP.Net//I have modified tcpclient sendtimeout and receivetimeout time to make sure it can know connect status when device connect into a switch//Please ignore all the warnings and Messages,I know the code is in a mess, but it is working.//I will modified and optimize the code later - Zixuan//Fix all warnings and Messages and make code more readable - 2025/06/10 Zixuanpublic class FinsTcpBase : Tcp{    public byte PlcNode { get; private set; }    public byte PcNode { get; private set; }    //    // Summary:    //     Fins读写指令生成    //    // Parameters:    //   rw:    //     读写类型    //    //   mr:    //     寄存器类型    //    //   mt:    //     地址类型    //    //   ch:    //     起始地址    //    //   offset:    //     位地址:00-15,字地址则为00    //    //   cnt:    //     地址个数,按位读写只能是1    public bool Link(string rIP, int rPort = 9600, int sendTimeout = 1000, int receiveTimeout = 1000)    {        if (this._client is null)            return false;        _client.SendTimeout = sendTimeout;        _client.ReceiveTimeout = receiveTimeout;        _client.NoDelay = true;        if (!_client.ConnectAsync(rIP, rPort).Wait(sendTimeout))            return false;        _stream = _client.GetStream();        Thread.Sleep(10);        if (!SendData(FinsClass.HandShakePack))            return false;        byte[] array = new byte[24];        if (!ReceiveData(array))            return false;        if (array[15] != 0)            return false;        PcNode = array[19];        PlcNode = array[23];        return true;    }    public bool Close()    {        try        {            _stream?.Close();            _client?.Close();            return true;        }        catch        {            return false;        }    }    public bool ReadWords(string mrch, short cnt, out short[]? reData)    {        reData = default;        if (!ConvertClass.GetPlcMemory(mrch, out string txtq, out PlcMemory plcMemory))            return false;        return ReadWords(plcMemory, short.Parse(txtq), cnt, out reData);    }    public bool ReadWords(PlcMemory mr, short ch, short cnt, out short[] reData)    {        reData = new short[cnt];        int num = 30 + cnt * 2;        byte[] array = new byte[num];        byte[] sd = FinsClass.FinsCmd(Operation.Read, mr, MemoryType.Word, ch, 0, cnt, PlcNode, PcNode);        if (!SendData(sd))            return false;        if (!ReceiveData(array))            return false;        bool flag = array[11] switch        {            3 => ErrorCode.CheckHeadError(array[15]),            _ => true        };        if (!flag)            return false;        if (!ErrorCode.CheckEndCode(array[28], array[29]))            return false;        for (int i = 0; i < cnt; i++)        {            byte[] value = [array[30 + i * 2 + 1], array[30 + i * 2]];            reData[i] = BitConverter.ToInt16(value, 0);        }        return true;    }    public bool ReadWord(string mrch, out short reData)    {        reData = default;        if (!ConvertClass.GetPlcMemory(mrch, out string txtq, out PlcMemory plcMemory))            return false;        return ReadWord(plcMemory, short.Parse(txtq), out reData);    }    public bool ReadWord(PlcMemory mr, short ch, out short reData)    {        reData = 0;        if (!ReadWords(mr, ch, 1, out var reData2))            return false;        reData = reData2[0];        return true;    }    public bool WriteWords(string mrch, short cnt, short[] inData)    {        if (!ConvertClass.GetPlcMemory(mrch, out string txtq, out PlcMemory plcMemory))            return false;        return WriteWords(plcMemory, short.Parse(txtq), cnt, inData);    }    public bool WriteWords(PlcMemory mr, short ch, short cnt, short[] inData)    {        byte[] array = new byte[30];        byte[] array2 = FinsClass.FinsCmd(Operation.Write, mr, MemoryType.Word, ch, 0, cnt, PlcNode, PcNode);        byte[] array3 = new byte[cnt * 2];        for (int i = 0; i < cnt; i++)        {            byte[] bytes = BitConverter.GetBytes(inData[i]);            array3[i * 2] = bytes[1];            array3[i * 2 + 1] = bytes[0];        }        byte[] array4 = new byte[cnt * 2 + 34];        array2.CopyTo(array4, 0);        array3.CopyTo(array4, 34);        if (!SendData(array4))            return false;        if (!ReceiveData(array))            return false;        bool flag = array[11] switch        {            3 => ErrorCode.CheckHeadError(array[15]),            _ => true        };        if (!flag)            return false;        return ErrorCode.CheckEndCode(array[28], array[29]);    }    public bool WriteWord(string mrch, short inData)    {        if (!ConvertClass.GetPlcMemory(mrch, out string txtq, out PlcMemory plcMemory))            return false;        return WriteWord(plcMemory, short.Parse(txtq), inData);    }    public bool WriteWord(PlcMemory mr, short ch, short inData)    {        short[] inData2 = [inData];        if (!WriteWords(mr, ch, 1, inData2))            return false;        return true;    }    public bool GetBitState(string mrch, out short bs)    {        bs = default;        if (!ConvertClass.GetPlcMemory(mrch, out string txtq, out PlcMemory plcMemory))            return false;        return GetBitState(plcMemory, txtq, out bs);    }    public bool GetBitStates(string mrch, out bool[]? bs, short cnt = 1)    {        bs = default;        if (!ConvertClass.GetPlcMemory(mrch, out string txtq, out PlcMemory plcMemory))            return false;        return GetBitStates(plcMemory, txtq, out bs, cnt);    }    public bool GetBitStates(PlcMemory mr, string ch, out bool[] bs, short cnt = 1)    {        bs = new bool[cnt];        byte[] array = new byte[30 + cnt];        short ch2 = short.Parse(ch.Split(['.'])[0]);        short offset = short.Parse(ch.Split(['.'])[1]);        byte[] command = FinsClass.FinsCmd(Operation.Read, mr, MemoryType.Bit, ch2, offset, cnt, PlcNode, PcNode);        if (!SendData(command))            return false;        if (!ReceiveData(array))            return false;        bool flag = array[11] switch        {            3 => ErrorCode.CheckHeadError(array[15]),            _ => true        };        if (!flag)            return false;        if (!ErrorCode.CheckEndCode(array[28], array[29]))            return false;        for (int i = 0; i < cnt; i++)            bs[i] = array[30 + i] == 1;        return true;    }    public bool GetBitState(PlcMemory mr, string ch, out short bs)    {        bs = 0;        byte[] array = new byte[31];        string[] spilts = ch.Split('.');        short ch2 = short.Parse(spilts[0]);        short offset = short.Parse(spilts[1]);        byte[] sd = FinsClass.FinsCmd(Operation.Read, mr, MemoryType.Bit, ch2, offset, 1, PlcNode, PcNode);        if (!SendData(sd))            return false;        if (!ReceiveData(array))            return false;        bool flag = array[11] switch        {            3 => ErrorCode.CheckHeadError(array[15]),            _ => true        };        if (!flag)            return false;        if (!ErrorCode.CheckEndCode(array[28], array[29]))            return false;        bs = array[30];        return true;    }    public bool SetBitState(string mrch, BitState bs)    {        if (!ConvertClass.GetPlcMemory(mrch, out string txtq, out PlcMemory plcMemory))            return false;        return SetBitState(plcMemory, txtq, bs);    }    public bool SetBitState(PlcMemory mr, string ch, BitState bs)    {        byte[] array = new byte[30];        string[] spilts = ch.Split('.');        short ch2 = short.Parse(spilts[0]);        short offset = short.Parse(spilts[1]);        byte[] array2 = FinsClass.FinsCmd(Operation.Write, mr, MemoryType.Bit, ch2, offset, 1, PlcNode, PcNode);        byte[] array3 = new byte[35];        array2.CopyTo(array3, 0);        array3[34] = (byte)bs;        if (!SendData(array3))            return false;        if (!ReceiveData(array))            return false;        bool flag = array[11] switch        {            3 => ErrorCode.CheckHeadError(array[15]),            _ => true        };        if (!flag)            return false;        if (!ErrorCode.CheckEndCode(array[28], array[29]))            return false;        return true;    }    public bool ReadReal(string mrch, out float reData)    {        reData = default;        if (!ConvertClass.GetPlcMemory(mrch, out string txtq, out PlcMemory plcMemory))            return false;        return ReadReal(plcMemory, short.Parse(txtq), out reData);    }    public bool ReadReal(PlcMemory mr, short ch, out float reData)    {        reData = 0f;        int num = 34;        byte[] array = new byte[num];        byte[] sd = FinsClass.FinsCmd(Operation.Read, mr, MemoryType.Word, ch, 0, 2, PlcNode, PcNode);        if (!SendData(sd))            return false;        if (!ReceiveData(array))            return false;        bool flag = array[11] switch        {            3 => ErrorCode.CheckHeadError(array[15]),            _ => true        };        if (!flag)            return false;        if (!ErrorCode.CheckEndCode(array[28], array[29]))            return false;        byte[] value = [array[31], array[30], array[33], array[32]];        reData = BitConverter.ToSingle(value, 0);        return true;    }    public bool WriteReal(string mrch, float reData)    {        if (!ConvertClass.GetPlcMemory(mrch, out string txtq, out PlcMemory plcMemory))            return false;        return WriteReal(plcMemory, short.Parse(txtq), reData);    }    public bool WriteReal(PlcMemory mr, short ch, float reData)    {        if (BitConverter.GetBytes(reData) is not byte[] bytes)            return false;        short[] array = new short[2];        array[0] = BitConverter.ToInt16(bytes, 0);        if (bytes.Length > 2)            array[1] = BitConverter.ToInt16(bytes, 2);        return WriteWords(mr, ch, 2, array);    }    public bool ReadInt32(string mrch, out int reData)    {        reData = default;        if (!ConvertClass.GetPlcMemory(mrch, out string txtq, out PlcMemory plcMemory))            return false;        return ReadInt32(plcMemory, short.Parse(txtq), out reData);    }    public bool ReadInt32(PlcMemory mr, short ch, out int reData)    {        reData = 0;        int num = 34;        byte[] array = new byte[num];        byte[] sd = FinsClass.FinsCmd(Operation.Read, mr, MemoryType.Word, ch, 0, 2, PlcNode, PcNode);        if (!SendData(sd))            return false;        if (!ReceiveData(array))            return false;        bool flag = array[11] switch        {            3 => ErrorCode.CheckHeadError(array[15]),            _ => true        };        if (!flag)            return false;        if (!ErrorCode.CheckEndCode(array[28], array[29]))            return false;        byte[] value = [array[31], array[30], array[33], array[32]];        reData = BitConverter.ToInt32(value, 0);        return true;    }    public bool WriteInt32(string mrch, int reData)    {        if (!ConvertClass.GetPlcMemory(mrch, out string txtq, out PlcMemory plcMemory))            return false;        return WriteInt32(plcMemory, short.Parse(txtq), reData);    }    public bool WriteInt32(PlcMemory mr, short ch, int reData)    {        if (BitConverter.GetBytes(reData) is not byte[] bytes)            return false;        short[] array = new short[2];        array[0] = BitConverter.ToInt16(bytes, 0);        if (bytes.Length > 2)            array[1] = BitConverter.ToInt16(bytes, 2);        return WriteWords(mr, ch, 2, array);    }}public class Tcp{    public Tcp()    {        this._client = new();    }    protected readonly TcpClient _client;    protected NetworkStream? _stream;    protected bool SendData(byte[] sd)    {        if (_stream == null)            return false;        try        {            _stream.Write(sd, 0, sd.Length);            return true;        }        catch        {            return false;        }    }    protected bool ReceiveData(byte[] rd)    {        if (_stream == null)            return false;        try        {            int num = 0;            do            {                int num2 = _stream.Read(rd, num, rd.Length - num);                if (num2 == 0)                    return false;                num += num2;            }            while (num < rd.Length);            return true;        }        catch        {            return false;        }    }}internal class ConvertClass{    //    // Summary:    //     得到枚举值    //    // Parameters:    //   txt:    //     如:D100,W100.1    //    //   txtq:100.1    internal static bool GetPlcMemory(string txt, out string txtq, out PlcMemory plcMemory)    {        txtq = string.Empty;        char c = txt.Trim().ToUpper().FirstOrDefault();        plcMemory = c switch        {            'D' => PlcMemory.DM,            'W' => PlcMemory.WR,            'H' => PlcMemory.HR,            'A' => PlcMemory.AR,            'C' => PlcMemory.CNT,            'I' => PlcMemory.CIO,            'T' => PlcMemory.TIM,            _ => PlcMemory.Undefined,        };        if (plcMemory == PlcMemory.Undefined)            return false;        txtq = Regex.Replace(txt, "[^0-9.]", "");        return true;    }}internal class ErrorCode{    //    // Summary:    //     (若返回的头指令为3)检查命令头中的错误代码    //    // Parameters:    //   Code:    //     错误代码    //    // Returns:    //     指示程序是否可以继续进行    internal static bool CheckHeadError(byte Code)    {        Console.WriteLine($"Error Code {Code}");        return Code == 0;    }    //    // Summary:    //     检查命令帧中的EndCode    //    // Parameters:    //   Main:    //     主码    //    //   Sub:    //     副码    //    // Returns:    //     指示程序是否可以继续进行    internal static bool CheckEndCode(byte Main, byte Sub)    {        //Totally dont understand what's doing here, Replace with the code below        return Main == 0 && (Sub == 64 || Sub == 0);        //switch (Main)        //{        //    case 0:        //        switch (Sub)        //        {        //            case 0:        //            case 64:        //                return true;        //            case 1:        //                return false;        //        }        //        break;        //    case 1:        //        switch (Sub)        //        {        //            case 1:        //            case 2:        //            case 3:        //            case 4:        //            case 5:        //            case 6:        //                return false;        //        }        //        break;        //    case 2:        //        switch (Sub)        //        {        //            case 1:        //            case 2:        //            case 3:        //            case 4:        //            case 5:        //                return false;        //        }        //        break;        //    case 3:        //        switch (Sub)        //        {        //            case 1:        //            case 2:        //            case 3:        //            case 4:        //                return false;        //        }        //        break;        //    case 4:        //        switch (Sub)        //        {        //            case 1:        //            case 2:        //                return false;        //        }        //        break;        //    case 5:        //        switch (Sub)        //        {        //            case 1:        //            case 2:        //            case 3:        //            case 4:        //                return false;        //        }        //        break;        //    case 16:        //        switch (Sub)        //        {        //            case 1:        //            case 2:        //            case 3:        //            case 4:        //            case 5:        //                return false;        //        }        //        break;        //    case 17:        //        switch (Sub)        //        {        //            case 1:        //            case 2:        //            case 3:        //            case 4:        //            case 6:        //            case 9:        //            case 10:        //            case 11:        //            case 12:        //                return false;        //        }        //        break;        //    case 32:        //        switch (Sub)        //        {        //            case 2:        //            case 3:        //            case 4:        //            case 5:        //            case 6:        //            case 7:        //                return false;        //        }        //        break;        //    case 33:        //        switch (Sub)        //        {        //            case 1:        //            case 2:        //            case 3:        //            case 5:        //            case 6:        //            case 7:        //            case 8:        //                return false;        //        }        //        break;        //    case 34:        //        switch (Sub)        //        {        //            case 1:        //            case 2:        //            case 3:        //            case 4:        //            case 5:        //            case 6:        //            case 7:        //            case 8:        //                return false;        //        }        //        break;        //    case 35:        //        switch (Sub)        //        {        //            case 1:        //            case 2:        //            case 3:        //                return false;        //        }        //        break;        //    case 36:        //        {        //            byte b5 = Sub;        //            byte b6 = b5;        //            if (b6 != 1)        //            {        //                break;        //            }        //            return false;        //        }        //    case 37:        //        switch (Sub)        //        {        //            case 2:        //            case 3:        //            case 4:        //            case 5:        //            case 6:        //            case 7:        //            case 9:        //            case 10:        //            case 13:        //            case 15:        //            case 16:        //                return false;        //        }        //        break;        //    case 38:        //        switch (Sub)        //        {        //            case 1:        //            case 2:        //            case 4:        //            case 5:        //            case 6:        //            case 7:        //            case 8:        //            case 9:        //            case 10:        //            case 11:        //                return false;        //        }        //        break;        //    case 48:        //        {        //            byte b3 = Sub;        //            byte b4 = b3;        //            if (b4 != 1)        //            {        //                break;        //            }        //            return false;        //        }        //    case 64:        //        {        //            byte b = Sub;        //            byte b2 = b;        //            if (b2 != 1)        //            {        //                break;        //            }        //            return false;        //        }        //}        //return false;    }}internal class FinsClass{    //    // Summary:    //     获取内存区码    //    // Parameters:    //   mr:    //     寄存器类型    //    //   mt:    //     地址类型    internal static byte GetMemoryCode(PlcMemory mr, MemoryType mt)    {        if (mt == MemoryType.Bit)        {            return mr switch            {                PlcMemory.CIO => 48,                PlcMemory.WR => 49,                PlcMemory.HR => 50,                PlcMemory.AR => 51,                PlcMemory.DM => 2,                PlcMemory.CNT or PlcMemory.TIM => 9,                _ => 0,            };        }        return mr switch        {            PlcMemory.CIO => 176,            PlcMemory.WR => 177,            PlcMemory.HR => 178,            PlcMemory.AR => 179,            PlcMemory.DM => 130,            PlcMemory.CNT or PlcMemory.TIM => 137,            _ => 0,        };    }    internal static byte[] FinsCmd(Operation rw, PlcMemory mr, MemoryType mt, short ch, short offset, short cnt, byte PlcNode, byte PcNode)    {        byte[] array =         [            70, 73, 78, 83, 0, 0, 0, 0, 0, 0,            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,            0, 0, 0, 0         ];        if (rw == Operation.Read)        {            array[6] = 0;            array[7] = 26;        }        else if (mt == MemoryType.Word)        {            array[6] = (byte)((cnt * 2 + 26) / 256);            array[7] = (byte)((cnt * 2 + 26) % 256);        }        else        {            array[6] = 0;            array[7] = 27;        }        array[11] = 2;        array[16] = 128;        array[18] = 2;        array[20] = PlcNode;        array[23] = PcNode;        array[25] = byte.MaxValue;        if (rw == Operation.Read)        {            array[26] = 1;            array[27] = 1;        }        else        {            array[26] = 1;            array[27] = 2;        }        array[28] = FinsClass.GetMemoryCode(mr, mt);        if (mr == PlcMemory.CNT)        {            array[29] = (byte)(ch / 256 + 128);            array[30] = (byte)(ch % 256);        }        else        {            array[29] = (byte)(ch / 256);            array[30] = (byte)(ch % 256);            array[31] = (byte)offset;        }        array[32] = (byte)(cnt / 256);        array[33] = (byte)(cnt % 256);        return array;    }    public static byte[] Header = [0x46, 0x49, 0x4E, 0x53];    public static byte[] HandShakePack =        [            0x46, 0x49, 0x4E, 0x53,     //Header            0x00, 0x00, 0x00, 0x0c,     //Length            0x00, 0x00, 0x00, 0x00,     //Command            0x00, 0x00, 0x00, 0x00,     //ErrorCode            0x00, 0x00, 0x00, 0x00      //Client Node        ];}public enum PlcMemory{    CIO,    WR,    HR,    AR,    DM,    CNT,    TIM,    Undefined,}public enum Operation{    Read,    Write}public enum MemoryType{    Bit,    Word}public enum BitState{    ON = 1,    OFF = 0}
 |