Opc.Ua.NumericRange.UpdateRange C# (CSharp) Method

UpdateRange() public method

Applies the multidimensional index range.
public UpdateRange ( object &dst, object src ) : Opc.Ua.StatusCode
dst object
src object
return Opc.Ua.StatusCode
        public StatusCode UpdateRange(ref object dst, object src)
        {
            // check for trivial case.
            if (dst == null)
            {
                return StatusCodes.BadIndexRangeNoData;
            }

            TypeInfo dstTypeInfo = TypeInfo.Construct(dst);

            // check for subset of string or byte string.
            if (dstTypeInfo.ValueRank == ValueRanks.Scalar)
            {
                if (this.Dimensions > 1)
                {
                    return StatusCodes.BadIndexRangeInvalid;
                }

                // check for subset of string.
                if (dstTypeInfo.BuiltInType == BuiltInType.String)
                {
                    string srcString = src as string;
                    char[] dstString = ((string)dst).ToCharArray();

                    if (srcString == null || srcString.Length != this.Count)
                    {
                        return StatusCodes.BadIndexRangeInvalid;
                    }

                    if (this.m_begin >= dstString.Length || ((this.m_end > 0 && this.m_end >= dstString.Length)))
                    {
                        return StatusCodes.BadIndexRangeNoData;
                    }

                    for (int jj = 0; jj < srcString.Length; jj++)
                    {
                        dstString[this.m_begin + jj] = srcString[jj];
                    }

                    dst = new string(dstString);
                    return StatusCodes.Good;
                }

                // update elements within a byte string.
                else if (dstTypeInfo.BuiltInType == BuiltInType.ByteString)
                {
                    byte[] srcString = src as byte[];
                    byte[] dstString = (byte[])dst;

                    if (srcString == null || srcString.Length != this.Count)
                    {
                        return StatusCodes.BadIndexRangeInvalid;
                    }

                    if (this.m_begin >= dstString.Length || ((this.m_end > 0 && this.m_end >= dstString.Length)))
                    {
                        return StatusCodes.BadIndexRangeNoData;
                    }

                    for (int jj = 0; jj < srcString.Length; jj++)
                    {
                        dstString[this.m_begin + jj] = srcString[jj];
                    }

                    return StatusCodes.Good;
                }

                // index range not supported.
                return StatusCodes.BadIndexRangeInvalid;
            }

            Array srcArray = src as Array;
            Array dstArray = dst as Array;

            // check for invalid target.
            if (dstArray == null)
            {
                return StatusCodes.BadIndexRangeInvalid;
            }

            // check for input specified as a matrix.
            if (srcArray == null)
            {
                Matrix matrix = src as Matrix;

                if (matrix == null || matrix.Dimensions.Length != m_subranges.Length)
                {
                    return StatusCodes.BadIndexRangeInvalid;
                }

                srcArray = matrix.ToArray();
            }

            TypeInfo srcTypeInfo = TypeInfo.Construct(srcArray);

            if (srcTypeInfo.BuiltInType != dstTypeInfo.BuiltInType && dstTypeInfo.BuiltInType != BuiltInType.Variant)
            {
                return StatusCodes.BadIndexRangeInvalid;
            }

            if (srcTypeInfo.ValueRank != dstTypeInfo.ValueRank)
            {
                return StatusCodes.BadIndexRangeInvalid;
            }

            // handle one dimension.
            if (m_subranges == null)
            {
                if (dstTypeInfo.ValueRank > 1)
                {
                    return StatusCodes.BadIndexRangeInvalid;
                }

                if (srcArray.Length != this.Count)
                {
                    return StatusCodes.BadIndexRangeInvalid;
                }

                if (this.m_begin >= dstArray.Length || ((this.m_end > 0 && this.m_end >= dstArray.Length)))
                {
                    return StatusCodes.BadIndexRangeNoData;
                }

                for (int jj = 0; jj < srcArray.Length; jj++)
                {
                    dstArray.SetValue(srcArray.GetValue(jj), this.m_begin + jj);
                }

                return StatusCodes.Good;
            }
            
            // check for matching dimensions.
            NumericRange? finalRange = null;

            if (m_subranges != null && m_subranges.Length > srcTypeInfo.ValueRank)
            {
                if (srcTypeInfo.BuiltInType == BuiltInType.ByteString || srcTypeInfo.BuiltInType == BuiltInType.String)
                {
                    if (m_subranges.Length == srcTypeInfo.ValueRank+1)
                    {
                        finalRange = m_subranges[m_subranges.Length-1];
                    }
                }

                if (finalRange == null)
                {
                    return StatusCodes.BadIndexRangeNoData;
                }
            }

            // get the dimensions of the array being copied.
            int srcCount = 1;
            int[] dimensions = new int[srcTypeInfo.ValueRank];

            for (int ii = 0; ii < dimensions.Length; ii++)
            {
                if (m_subranges.Length < ii)
                {
                    if (m_subranges[ii].Count != srcArray.GetLength(ii))
                    {
                        return StatusCodes.BadIndexRangeInvalid;
                    }
                }
                
                dimensions[ii] = srcArray.GetLength(ii);
                srcCount *= dimensions[ii];
            }

            // check that the index range falls with the target array.
            int[] dstIndexes = new int[dimensions.Length];

            for (int ii = 0; ii < srcCount; ii++)
            {
                // check target dimensions.
                int divisor = srcCount;

                for (int jj = 0; jj < dimensions.Length; jj++)
                {
                    divisor /= dimensions[jj];
                    int index = (ii/divisor)%dimensions[jj];
                    int start = 0;

                    if (m_subranges.Length > jj)
                    {
                        start = m_subranges[jj].m_begin;
                    }

                    if (start + index >= dstArray.GetLength(jj))
                    {
                        return StatusCodes.BadIndexRangeNoData;
                    }

                    dstIndexes[jj] = start + index;
                }

                if (finalRange == null)
                {
                    continue;
                }

                // check for subset of string or byte string.
                int last = finalRange.Value.m_begin;

                if (finalRange.Value.m_end > 0)
                {
                    last = finalRange.Value.m_end;
                }

                object element = dstArray.GetValue(dstIndexes);

                // check for subset of string.
                if (dstTypeInfo.BuiltInType == BuiltInType.String)
                {
                    string str = (string)element;

                    if (str == null || last >= str.Length)
                    {
                        return StatusCodes.BadIndexRangeNoData;
                    }
                }

                // check for subset of byte string.
                else if (dstTypeInfo.BuiltInType == BuiltInType.ByteString)
                {
                    byte[] str = (byte[])element;

                    if (str == null || last >= str.Length)
                    {
                        return StatusCodes.BadIndexRangeNoData;
                    }
                }
            }

            // copy data.
            int[] srcIndexes = new int[dimensions.Length];

            for (int ii = 0; ii < srcCount; ii++)
            {
                // calculate dimensions.
                int divisor = srcCount;

                for (int jj = 0; jj < dimensions.Length; jj++)
                {
                    divisor /= dimensions[jj];
                    int index = (ii / divisor) % dimensions[jj];
                    int start = 0;

                    if (m_subranges.Length > jj)
                    {
                        start = m_subranges[jj].m_begin;
                    }

                    if (start + index >= dstArray.GetLength(jj))
                    {
                        return StatusCodes.BadIndexRangeNoData;
                    }

                    srcIndexes[jj] = index;
                    dstIndexes[jj] = start + index;
                }

                // get the element to copy.
                object element1 = srcArray.GetValue(srcIndexes);

                if (finalRange == null)
                {
                    dstArray.SetValue(element1, dstIndexes);
                    continue;
                }
                
                object element2 = dstArray.GetValue(dstIndexes);

                // update elements within a string.
                if (dstTypeInfo.BuiltInType == BuiltInType.String)
                {
                    string srcString = (string)element1;
                    char[] dstString = ((string)element2).ToCharArray();

                    if (srcString != null)
                    {
                        for (int jj = 0; jj < srcString.Length; jj++)
                        {
                            dstString[finalRange.Value.m_begin + jj] = srcString[jj];
                        }
                    }

                    dstArray.SetValue(new string(dstString), dstIndexes);
                }

                // update elements within a byte string.
                else if (dstTypeInfo.BuiltInType == BuiltInType.ByteString)
                {
                    byte[] srcString = (byte[])element1;
                    byte[] dstString = (byte[])element2;

                    if (srcString != null)
                    {
                        for (int jj = 0; jj < srcString.Length; jj++)
                        {
                            dstString[finalRange.Value.m_begin + jj] = srcString[jj];
                        }
                    }
                }
            }

            return StatusCodes.Good;
        }

Usage Example

コード例 #1
0
        private ServiceResult OnWriteAnalog(
            ISystemContext context,
            NodeState node,
            NumericRange indexRange,
            QualifiedName dataEncoding,
            ref object value,
            ref StatusCode statusCode,
            ref DateTime timestamp)
        {
            AnalogItemState variable = node as AnalogItemState;

            // verify data type.
            Opc.Ua.TypeInfo typeInfo = Opc.Ua.TypeInfo.IsInstanceOfDataType(
                value,
                variable.DataType,
                variable.ValueRank,
                context.NamespaceUris,
                context.TypeTable);

            if (typeInfo == null || typeInfo == Opc.Ua.TypeInfo.Unknown)
            {
                return StatusCodes.BadTypeMismatch;
            }

            // check index range.
            if (variable.ValueRank >= 0)
            {
                if (indexRange != NumericRange.Empty)
                {
                    object target = variable.Value;
                    ServiceResult result = indexRange.UpdateRange(ref target, value);

                    if (ServiceResult.IsBad(result))
                    {
                        return result;
                    }

                    value = target;
                }
            }

            // check instrument range.
            else
            {
                if (indexRange != NumericRange.Empty)
                {
                    return StatusCodes.BadIndexRangeInvalid;
                }

                double number = Convert.ToDouble(value);

                if (variable.InstrumentRange != null && (number < variable.InstrumentRange.Value.Low || number > variable.InstrumentRange.Value.High))
                {
                    return StatusCodes.BadOutOfRange;
                }
            }

            return ServiceResult.Good;
        }