Ejemplo n.º 1
0
        public static int DataTypeToSizeByte(Type t, PlcArea area)
        {
            if (t.IsArray)
            {
                t = t.GetElementType();
            }

            if (area == PlcArea.CT || area == PlcArea.TM)
            {
                return(1);
            }

            if (t == typeof(bool) || t == typeof(byte) || t == typeof(char))
            {
                return(1);
            }

            if (t == typeof(Int16) || t == typeof(UInt16))
            {
                return(2);
            }

            if (t == typeof(Int32) || t == typeof(UInt32) || t == typeof(double))
            {
                return(4);
            }


            return(0);
        }
Ejemplo n.º 2
0
        public static ReadItem CreateFromTag(string tag)
        {
            var     parts      = tag.Split(new[] { ',' });
            var     start      = parts[0].Split(new[] { '.' });
            var     withPrefix = start.Length == 3;
            PlcArea selector   = 0;
            ushort  length     = 1;
            ushort  offset     = UInt16.Parse(start[start.Length - 1]);
            ushort  db         = 0;

            if (!TryDetectArea(start[withPrefix ? 1 : 0], ref selector, ref db))
            {
                throw new ArgumentException($"Invalid area in tag <{tag}>");
            }

            if (parts.Length > 2)
            {
                length = UInt16.Parse(parts[2]);
            }

            offset = DetectTypes(parts[1], length, offset, out Type vtype, out Type rType);

            return(new ReadItem
            {
                Area = selector,
                DbNumber = db,
                Offset = offset,
                Length = length,
                VarType = vtype,
                ResultType = rType
            });
        }
Ejemplo n.º 3
0
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="area">Where to read:  e.g.  DB1  or M or...</param>
        /// <param name="offset">offset in bytes, if you address booleans, you have to pass the address in bits (byteoffset * 8 + bitoffset)</param>
        /// <param name="length">The number of items to read</param>
        /// <returns></returns>
        public static ReadItem Create <T>(string area, ushort offset, ushort length = 1)
        {
            PlcArea selector = 0;
            ushort  db       = 0;

            if (!TryDetectArea(area, ref selector, ref db))
            {
                throw new ArgumentException($"Invalid area <{area}>");
            }

            var  t = typeof(T);
            Type vtype;
            Type rType;

            if (t.IsArray)
            {
                vtype = t.GetElementType();
                rType = t;
            }
            else
            {
                vtype = t;
                rType = length > 1 ? typeof(T[]) : vtype;
            }

            return(new ReadItem
            {
                Area = selector,
                DbNumber = db,
                Offset = offset,
                Length = length,
                VarType = vtype,
                ResultType = rType
            });
        }
Ejemplo n.º 4
0
 public RequestItem(PlcArea area, ushort dbNumber, ushort numberOfItems, int offset, ItemDataTransportSize transportSize, Memory <byte> address)
 {
     Area          = area;
     DbNumber      = dbNumber;
     NumberOfItems = numberOfItems;
     Offset        = offset;
     Address       = address;
     DetermineTransportAndElementSize(area, transportSize);
 }
Ejemplo n.º 5
0
 protected RequestItem(PlcArea area, ushort dbNumber, ushort numberOfItems, int offset, DataTransportSize transportSize, ushort elementSize, Memory <byte> address)
 {
     Area          = area;
     DbNumber      = dbNumber;
     NumberOfItems = numberOfItems;
     Offset        = offset;
     TransportSize = transportSize;
     Address       = address;
     ElementSize   = elementSize;
 }
Ejemplo n.º 6
0
        private static int CalculateSizeForGenericWriteOperation <T>(PlcArea area, T value, int length = -1)
        {
            var size = Dacs7Client.CalculateSizeForGenericWriteOperation(area, value, length, out Type elementType);

            if (typeof(T) == typeof(string))
            {
                size -= 2;
            }
            return(size);
        }
Ejemplo n.º 7
0
        public static byte GetTransportSize(PlcArea area, Type t)
        {
            if (area == PlcArea.CT || area == PlcArea.TM)
            {
                return(0x01);
            }

            if (t.IsArray)
            {
                t = t.GetElementType();
            }


            if (t == typeof(bool))
            {
                return((byte)ItemDataTransportSize.Bit);
            }

            if (t == typeof(byte) || t == typeof(string) || t == typeof(Memory <byte>))
            {
                return((byte)ItemDataTransportSize.Byte);
            }

            if (t == typeof(char))
            {
                return((byte)ItemDataTransportSize.Char);
            }

            if (t == typeof(ushort))
            {
                return((byte)ItemDataTransportSize.Word);
            }

            if (t == typeof(short))
            {
                return((byte)ItemDataTransportSize.Int);
            }

            if (t == typeof(uint))
            {
                return((byte)ItemDataTransportSize.Dword);
            }

            if (t == typeof(int))
            {
                return((byte)ItemDataTransportSize.Dint);
            }

            if (t == typeof(float))
            {
                return((byte)ItemDataTransportSize.Real);
            }

            return(0);
        }
Ejemplo n.º 8
0
        //TODO:  Handle array of bool correct!!!!
        public static IMessage CreateWriteRequest(ushort unitId, PlcArea area, ushort dbnr, int offset, ushort length, object data)
        {
            var msg           = Message.Create();
            var isArray       = data is Array;
            var isBool        = isArray ? (data as Array).GetValue(0) is bool : data is bool; // Handle Array of bools
            var numberOfItems = !isBool ? 1 : length;
            var itemLength    = isBool ? (ushort)1 : length;
            var payloadLength = (ushort)(!isBool ? length + 4 : length * 6 - 1); //=we need a fillbyte between each item has to be a fill byte if the length is odd.
            var paramLength   = (ushort)(!isBool ? 14 : 2 + 12 * numberOfItems);

            FillCommHeader(msg, (byte)PduType.Job, payloadLength, paramLength, unitId);
            AddReadWriteParameter(msg, (byte)FunctionCode.WriteVar, Convert.ToByte(numberOfItems));
            var t          = data.GetType();
            var enumerable = ConvertDataToByteArray(data);
            var typeLength = TransportSizeHelper.DataTypeToSizeByte(t, area);

            for (var i = 0; i < numberOfItems; i++)
            {
                var size = isBool || area == PlcArea.CT || area == PlcArea.TM ? (byte)ItemDataTransportSize.Bit : (byte)ItemDataTransportSize.Byte;
                var addr = i * typeLength + offset;

                var prefix = $"Item[{i}].";
                msg.SetAttribute(prefix + "VariableSpecification", (byte)0x12);
                const byte specLength = 0x0a;
                msg.SetAttribute(prefix + "LengthOfAddressSpecification", specLength);
                msg.SetAttribute(prefix + "SyntaxId", (byte)ItemSyntaxId.S7Any);
                msg.SetAttribute(prefix + "TransportSize", (byte)size);
                msg.SetAttribute(prefix + "ItemSpecLength", itemLength);
                msg.SetAttribute(prefix + "DbNumber", dbnr);
                msg.SetAttribute(prefix + "Area", area);

                var offsetAddress = size == 0x01 ? addr : addr * 8;
                var address       = new byte[3];
                address[2]    = (byte)(offsetAddress & 0x000000FF);
                offsetAddress = offsetAddress >> 8;
                address[1]    = (byte)(offsetAddress & 0x000000FF);
                offsetAddress = offsetAddress >> 8;
                address[0]    = (byte)(offsetAddress & 0x000000FF);

                msg.SetAttribute(prefix + "Address", address);
            }


            for (var i = 0; i < numberOfItems; i++)
            {
                var prefix = $"DataItem[{i}].";
                msg.SetAttribute(prefix + "ItemDataReturnCode", (byte)0x00);
                msg.SetAttribute(prefix + "ItemDataTransportSize", isBool ? (byte)DataTransportSize.Bit : (byte)DataTransportSize.Byte);
                msg.SetAttribute(prefix + "ItemDataLength", itemLength);
                msg.SetAttribute(prefix + "ItemData", isBool ? new byte[] { enumerable[i] } : enumerable);
            }

            return(msg);
        }
Ejemplo n.º 9
0
 public void TryParseTagTests(string tag, PlcArea resultArea, int offset, int length, Type resultType, Type vartype = null)
 {
     if (vartype == null)
     {
         vartype = resultType;
     }
     Assert.True(TagParser.TryParseTag(tag, out var result));
     Assert.Equal(resultArea, result.Area);
     Assert.Equal(offset, result.Offset);
     Assert.Equal(length, result.Length);
     Assert.Equal(resultType, result.ResultType);
     Assert.Equal(vartype, result.VarType);
 }
Ejemplo n.º 10
0
 public PlcDataEntry(PlcArea area, ushort dbNumber, ushort length, Memory <byte> data = default)
 {
     Area     = area;
     DbNumber = dbNumber;
     Length   = length;
     if (!data.IsEmpty)
     {
         _externalData = data;
     }
     else
     {
         _owner = MemoryPool <byte> .Shared.Rent(length);
     }
 }
Ejemplo n.º 11
0
        public bool Release(PlcArea area, ushort dbNumber = 0)
        {
            if (!_plcData.TryGetValue(area, out var areaData))
            {
                return(false);
            }

            if (!areaData.TryGetValue(dbNumber, out var dataEntry))
            {
                return(false);
            }

            dataEntry?.Dispose();
            return(true);
        }
Ejemplo n.º 12
0
 /// <summary>
 /// Create a WriteOperationParameter instance to write data to any area.
 /// </summary>
 /// <typeparam name="T">Specifies the type of the value we want to write.</typeparam>
 /// <param name="area">The target <see cref="PlcArea"></see> we want to write.</param>
 /// <param name="offset">This is the offset to the data you want to write.(offset is normally the number of bytes from the beginning of the area,
 /// excepted the data type is a boolean, then the offset is in number of bits. This means ByteOffset*8+BitNumber)</param>
 /// <param name="value">This is the value we want to write to the PLC.</param>
 /// <returns></returns>
 public static WriteOperationParameter Create <T>(PlcArea area, int offset, T value)
 {
     if (area == PlcArea.DB)
     {
         throw new ArgumentException("The argument area could not be of type DB.");
     }
     return(new WriteOperationParameter
     {
         Area = area,
         Offset = offset,
         Type = typeof(T),
         Data = value,
         Args = new[] { CalculateSizeForGenericWriteOperation <T>(PlcArea.DB, value) }
     });
 }
Ejemplo n.º 13
0
        public static ushort GetElementSize(PlcArea area, Type t, PlcEncoding encoding)
        {
            if (area == PlcArea.CT || area == PlcArea.TM)
            {
                return(2);
            }

            if (t.IsArray)
            {
                t = t.GetElementType();
            }

            if (t == typeof(byte) || t == typeof(Memory <byte>))
            {
                return(1);
            }
            if (t == typeof(bool))
            {
                return(1);
            }
            if (t == typeof(char) || t == typeof(string))
            {
                return((ushort)(encoding == PlcEncoding.Unicode ? 2 : 1));
            }
            if (t == typeof(short) || t == typeof(ushort))
            {
                return(2);
            }
            if (t == typeof(int) || t == typeof(uint))
            {
                return(4);
            }
            if (t == typeof(ulong) || t == typeof(long))
            {
                return(8);
            }
            if (t == typeof(float))
            {
                return(4);
            }
            if (t == typeof(sbyte))
            {
                return(1);
            }

            return(1);
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Create a ReadOperationParameter instance by the given arguments
        /// </summary>
        /// <typeparam name="T">Specifies the type of the value we want to read.</typeparam>
        /// <param name="area">The target <see cref="PlcArea"></see> from which we want to read.</param>
        /// <param name="offset">This is the offset to the data you want to read.(offset is normally the number of bytes from the beginning of the area,
        /// excepted the data type is a boolean, then the offset is in number of bits. This means ByteOffset*8+BitNumber)</param>
        /// <param name="numberOfItems">Number of items of the T to read. This could be the string length for a string, or the number of bytes/int for an array and so on.
        /// The default value is always 1.
        /// Reading array of BOOLs is not supported in this case at the moment!</param>
        /// <returns></returns>
        public static ReadOperationParameter Create <T>(PlcArea area, int offset, int numberOfItems = -1)
        {
            if (area == PlcArea.DB)
            {
                throw new ArgumentException("The argument area could not be DB.");
            }
            var t = typeof(T);

            CalculateElementLength <T>(ref offset, ref numberOfItems, t, area);

            return(new ReadOperationParameter
            {
                Area = area,
                Offset = offset,
                Type = t,
                Args = new[] { numberOfItems }
            });
        }
Ejemplo n.º 15
0
        public bool Register(PlcArea area, ushort dataLength, Memory <byte> data, ushort dbNumber = 0)
        {
            if (!_plcData.TryGetValue(area, out var areaData))
            {
                areaData = new Dictionary <ushort, PlcDataEntry>();
                _plcData.Add(area, areaData);
            }

            if (!areaData.TryGetValue(dbNumber, out var dataEntry))
            {
                dataEntry = new PlcDataEntry
                            (
                    area: area,
                    dbNumber: dbNumber,
                    length: dataLength,
                    data: data
                            );
                areaData.Add(dbNumber, dataEntry);
                return(true);
            }
            return(false);
        }
Ejemplo n.º 16
0
        private static bool TryDetectArea(string area, ref PlcArea selector, ref ushort db)
        {
            switch (area.ToUpper())
            {
            // Inputs
            case "I": selector = PlcArea.IB; break;      // English

            case "E": selector = PlcArea.IB; break;      // German

            // Marker
            case "M": selector = PlcArea.FB; break;      // English and German

            // Ouputs
            case "Q": selector = PlcArea.QB; break;      // English

            case "A": selector = PlcArea.QB; break;      // German

            // Timer
            case "T": selector = PlcArea.TM; break;      // English and German

            // Counter
            case "C": selector = PlcArea.CT; break;      // English

            case "Z": selector = PlcArea.CT; break;      // German

            // Datablocks
            case var s when Regex.IsMatch(s, "^DB\\d+$", RegexOptions.IgnoreCase):
            {
                selector = PlcArea.DB;
                db       = UInt16.Parse(s.Substring(2));
                break;
            }

            default: return(false);
            }

            return(true);
        }
Ejemplo n.º 17
0
        public static IMessage CreateReadRequest(ushort unitId, PlcArea area, ushort dbnr, int offset, ushort length, Type t)
        {
            var msg   = Message.Create();
            var isBit = t == typeof(bool);

            FillCommHeader(msg, (byte)PduType.Job, 0, 14, unitId);
            AddReadWriteParameter(msg, (byte)FunctionCode.ReadVar, 1);
            for (var i = 0; i < 1; i++)
            {
                var size = isBit || area == PlcArea.CT || area == PlcArea.TM ? (byte)ItemDataTransportSize.Bit : (byte)ItemDataTransportSize.Byte;

                var prefix = $"Item[{i}].";
                msg.SetAttribute(prefix + "VariableSpecification", (byte)0x12);
                const byte specLength = 0x0a;
                msg.SetAttribute(prefix + "LengthOfAddressSpecification", specLength);
                msg.SetAttribute(prefix + "SyntaxId", (byte)ItemSyntaxId.S7Any);
                msg.SetAttribute(prefix + "TransportSize", (byte)size);
                msg.SetAttribute(prefix + "ItemSpecLength", length);
                msg.SetAttribute(prefix + "DbNumber", dbnr);
                msg.SetAttribute(prefix + "Area", area);


                offset = isBit ? offset : (offset * 8);
                var address = new byte[3];
                address[2] = (byte)(offset & 0x000000FF);
                offset     = offset >> 8;
                address[1] = (byte)(offset & 0x000000FF);
                offset     = offset >> 8;
                address[0] = (byte)(offset & 0x000000FF);

                msg.SetAttribute(prefix + "Address", address);
                offset += specLength + 2;
            }

            return(msg);
        }
Ejemplo n.º 18
0
        protected void DetermineTransportAndElementSize(PlcArea area, ItemDataTransportSize t)
        {
            if (area == PlcArea.CT || area == PlcArea.TM)
            {
                TransportSize = DataTransportSize.OctetString;
                ElementSize   = 2;
                return;
            }

            switch (t)
            {
            case ItemDataTransportSize.Bit:
            {
                TransportSize = DataTransportSize.Bit;
                ElementSize   = 1;
            }
            break;

            case ItemDataTransportSize.Byte:
            case ItemDataTransportSize.Char:
            {
                TransportSize = DataTransportSize.Byte;
                ElementSize   = 1;
            }
            break;

            case ItemDataTransportSize.Word:
            {
                TransportSize = DataTransportSize.Byte;
                ElementSize   = 2;
            }
            break;

            case ItemDataTransportSize.Int:
            {
                TransportSize = DataTransportSize.Int;
                ElementSize   = 2;
            }
            break;

            case ItemDataTransportSize.Dword:
            {
                TransportSize = DataTransportSize.Byte;
                ElementSize   = 4;
            }
            break;

            case ItemDataTransportSize.Dint:
            {
                TransportSize = DataTransportSize.Dint;
                ElementSize   = 4;
            }
            break;

            case ItemDataTransportSize.Real:
            {
                TransportSize = DataTransportSize.Real;
                ElementSize   = 4;
            }
            break;

            default:
            {
                TransportSize = DataTransportSize.Byte;
                ElementSize   = 1;
            }
            break;
            }
        }
Ejemplo n.º 19
0
 /// <summary>
 /// Create a WriteOperationParameter instance to write a bit.
 /// This is an specialization where you do not have to calculate the bit offset by yourselves.
 /// </summary>
 /// <param name="area">The target <see cref="PlcArea"></see> we want to write.</param>
 /// <param name="offset">This is the offset in byte to the data you want to write.</param>
 /// <param name="bitNumber">This is the number of the bit, in the byte with the given offset, we want to write.</param>
 /// <param name="value">This is the value we want to write to the PLC.</param>
 /// <returns></returns>
 public static WriteOperationParameter CreateForBit(PlcArea area, int offset, int bitNumber, bool value)
 {
     return(Create(area, offset * 8 + bitNumber, value));
 }
Ejemplo n.º 20
0
        private static void CalculateElementLength <T>(ref int offset, ref int numberOfItems, Type t, PlcArea area)
        {
            var isBool        = t == typeof(bool);
            var isString      = t == typeof(string);
            var elementLength = isString ? numberOfItems : TransportSizeHelper.DataTypeToSizeByte(typeof(T), area);

            if (numberOfItems >= 0)
            {
                if (isBool)
                {
                    offset /= 8;
                }
                else if (isString)
                {
                    numberOfItems = elementLength;
                }
                else
                {
                    numberOfItems = numberOfItems * elementLength;
                }
            }
            else
            {
                numberOfItems = 1;
            }
        }
Ejemplo n.º 21
0
 /// <summary>
 /// Create a ReadOperationParameter instance to read a bit.
 /// </summary>
 /// <param name="area">The target <see cref="PlcArea"></see> from which we want to read.</param>
 /// <param name="offset">This is the offset in byte to the data you want to read.</param>
 /// <param name="bitNumber">This is the number of the bit, in the byte with the given offset, we want to read.</param>
 /// <param name="numberOfItems">Number of items of the T to read. This could be the string length for a string, or the number of bytes/int for an array and so on.
 /// The default value is always 1.
 /// Reading array of BOOLs is not supported in this case at the moment!</param>
 /// <returns></returns>
 public static ReadOperationParameter CreateForBit(PlcArea area, int offset, int bitNumber, int numberOfItems = -1)
 {
     return(Create <bool>(area, offset * 8 + bitNumber, numberOfItems));
 }
Ejemplo n.º 22
0
 public ReadRequestItem(PlcArea area, ushort dbNumber, ushort numberOfItems, int offset, ItemDataTransportSize transportSize, Memory <byte> address)
     : base(area, dbNumber, numberOfItems, offset, transportSize, address)
 {
 }
Ejemplo n.º 23
0
 public bool Register(PlcArea area, ushort dataLength, ushort dbNumber = 0) => Register(area, dataLength, default, dbNumber);
Ejemplo n.º 24
0
 internal WriteRequestItem(PlcArea area, ushort dbNumber, ushort numberOfItems, int offset, DataTransportSize transportSize, ushort elementSize, Memory <byte> address, Memory <byte> data)
     : base(area, dbNumber, numberOfItems, offset, transportSize, elementSize, address)
 {
     Data = data;
 }
Ejemplo n.º 25
0
        public static bool TryDetectArea(ReadOnlySpan <char> area, out PlcArea selector, out ushort db)
        {
            db = 0;
            var singleElement = area.Length == 1;

            switch (area[0])
            {
            // Inputs
            case 'i' when singleElement: selector = PlcArea.IB; return(true);     // English

            case 'e' when singleElement: selector = PlcArea.IB; return(true);     // German

            case 'I' when singleElement: selector = PlcArea.IB; return(true);     // English

            case 'E' when singleElement: selector = PlcArea.IB; return(true);     // German

            // Marker
            case 'm' when singleElement: selector = PlcArea.FB; return(true);     // English and German

            case 'M' when singleElement: selector = PlcArea.FB; return(true);     // English and German

            // Ouputs
            case 'q' when singleElement: selector = PlcArea.QB; return(true);     // English

            case 'a' when singleElement: selector = PlcArea.QB; return(true);     // German

            case 'Q' when singleElement: selector = PlcArea.QB; return(true);     // English

            case 'A' when singleElement: selector = PlcArea.QB; return(true);     // German

            // Timer
            case 't' when singleElement: selector = PlcArea.TM; return(true);     // English and German

            case 'T' when singleElement: selector = PlcArea.TM; return(true);     // English and German

            // Counter
            case 'c' when singleElement: selector = PlcArea.CT; return(true);     // English

            case 'z' when singleElement: selector = PlcArea.CT; return(true);     // German

            case 'C' when singleElement: selector = PlcArea.CT; return(true);     // English

            case 'Z' when singleElement: selector = PlcArea.CT; return(true);     // German

            case 'd' when area.Length > 2:
            case 'D' when area.Length > 2:
            {
                // TODO: ReadOnlySpan<char>   !!!!
                // Datablocks
                //if (Regex.IsMatch(area.ToString(), "^db\\d+$", RegexOptions.IgnoreCase))
                if ((area[0] == 'D' || area[0] == 'd') && (area[1] == 'B' || area[1] == 'b'))
                {
                    selector = PlcArea.DB;
#if SPANSUPPORT
                    db = ushort.Parse(area.Slice(2));
#else
                    db = SpanToUShort(area.Slice(2));
#endif

                    if (db <= 0)
                    {
                        break;
                    }

                    return(true);
                }
            }
            break;
            }
            selector = PlcArea.DB;
            return(false);
        }