/// <summary> /// Nexts the value in the time series. /// </summary> private DataValue NextValue( ISystemContext context, NumericRange indexRange, QualifiedName dataEncoding) { DataValue value = new DataValue(); if (m_mergedSeries == null) { // check for end of series. if (m_historyData == null || m_position >= m_historyData.Length) { return(GetLastBound(context, indexRange, dataEncoding)); } // process next value. HdaAttributeValue source = m_historyData[m_position++]; GetAttributeValue(context, indexRange, dataEncoding, m_attributeId, value, source); return(value); } // check for end of series. if (m_mergedSeries == null || m_position >= m_mergedSeries.Count) { return(GetLastBound(context, indexRange, dataEncoding)); } // process next value. HdaAttributeValue[] sources = m_mergedSeries[m_position++]; GetAttributeValue(context, indexRange, dataEncoding, m_attributeId, value, sources); return(value); }
/// <summary> /// Converts the attribute value to the specified type. /// </summary> protected T GetAttributeValue <T>(DataValue value, HdaAttributeValue source) { value.Value = null; // find the attribute value. if (source == null) { value.StatusCode = StatusCodes.BadOutOfService; return(default(T)); } // set the appropriate error code if no value found. if (source == null || source.Error < 0 || source.Error == ResultIds.S_NODATA) { value.StatusCode = StatusCodes.BadNoData; return(default(T)); } // update the source timestamp if a value is being read. value.SourceTimestamp = source.Timestamp; // check type conversion error. if (!typeof(T).IsInstanceOfType(source.Value)) { value.StatusCode = StatusCodes.BadTypeMismatch; return(default(T)); } // save the value and return the result. value.Value = (T)source.Value; return((T)source.Value); }
/// <summary> /// Sets the error for all attributes. /// </summary> /// <param name="error">The error.</param> public void SetError(int error) { if (m_attributeIds != null) { m_attributeValues = new HdaAttributeValue[m_attributeIds.Count]; for (int ii = 0; ii < m_attributeValues.Length; ii++) { m_attributeValues[ii] = new HdaAttributeValue(); m_attributeValues[ii].AttributeId = m_attributeIds[ii]; m_attributeValues[ii].Error = error; } } }
/// <summary> /// Sets the history for the attribute. /// </summary> public void SetHistoryResults( int[] attributeIds, HdaAttributeValue[][] results) { m_historyData = null; // save the primary series. if (results.Length > 0) { m_historyData = results[0]; } // create a merged series from multiple streams. if (results.Length > 1) { m_mergedSeries = new List <HdaAttributeValue[]>(); // find the first set. HdaAttributeValue[] tuple = new HdaAttributeValue[attributeIds.Length]; for (int ii = 0; ii < tuple.Length; ii++) { if (results[ii] != null) { tuple[ii] = results[ii][0]; } } m_mergedSeries.Add(tuple); // add in additional sets. int[] indexes = new int[attributeIds.Length]; while (tuple != null) { tuple = NextTuple(results, indexes); if (tuple != null) { m_mergedSeries.Add(tuple); } } } }
/// <summary> /// Gets the attribute value. /// </summary> /// <typeparam name="T">The expected type for the attribute value.</typeparam> /// <param name="attributeId">The attribute id.</param> /// <param name="value">The value to update.</param> /// <param name="isValue">if set to <c>true</c> if the attribute is required for the value attribute of a node.</param> /// <returns>The value cast to the type T.</returns> /// <remarks> /// This method sets the StatusCode in the DataValue if an error occurs and returns default(T). /// The DataValue.Value attribute is set to the value cast to type T. /// </remarks> public T GetAttributeValue <T>(uint attributeId, DataValue value, bool isValue) { value.Value = null; // find the attribute value. HdaAttributeValue result = GetAttributeValue(attributeId); if (result == null) { value.StatusCode = StatusCodes.BadOutOfService; return(default(T)); } // set the appropriate error code if no value found. if (result == null || result.Error < 0 || result.Error == ResultIds.S_NODATA) { value.StatusCode = StatusCodes.BadNotFound; return(default(T)); } // update the source timestamp if a value is being read. if (isValue) { value.SourceTimestamp = result.Timestamp; } // check type conversion error. if (!typeof(T).IsInstanceOfType(result.Value)) { value.StatusCode = StatusCodes.BadTypeMismatch; return(default(T)); } // save the value and return the result. value.Value = (T)result.Value; return((T)result.Value); }
/// <summary> /// Updates the attributes for the items. /// </summary> public HdaAttributeValue[] ReadAttributeValues(int serverHandle, params int[] attributeIds) { string methodName = "IOPCHDA_SyncRead.ReadAttribute"; OPCHDA_TIME htStartTime; htStartTime.bString = 1; htStartTime.szTime = "NOW"; htStartTime.ftTime.dwHighDateTime = 0; htStartTime.ftTime.dwLowDateTime = 0; OPCHDA_TIME htEndTime; htEndTime.bString = 1; htEndTime.szTime = String.Empty; htEndTime.ftTime.dwHighDateTime = 0; htEndTime.ftTime.dwLowDateTime = 0; IntPtr ppAttributeValues; IntPtr ppErrors; try { IOPCHDA_SyncRead server = BeginComCall<IOPCHDA_SyncRead>(methodName, true); server.ReadAttribute( ref htStartTime, ref htEndTime, serverHandle, attributeIds.Length, attributeIds, out ppAttributeValues, out ppErrors); } catch (Exception e) { ComCallError(methodName, e); return null; } finally { EndComCall(methodName); } int[] errors = ComUtils.GetInt32s(ref ppErrors, attributeIds.Length, true); HdaAttributeValue[] results = new HdaAttributeValue[attributeIds.Length]; IntPtr pos = ppAttributeValues; for (int ii = 0; ii < attributeIds.Length; ii++) { HdaAttributeValue result = results[ii] = new HdaAttributeValue(); result.AttributeId = Utils.ToUInt32(attributeIds[ii]); result.Error = errors[ii]; OPCHDA_ATTRIBUTE attributes = (OPCHDA_ATTRIBUTE)Marshal.PtrToStructure(pos, typeof(OPCHDA_ATTRIBUTE)); if (attributes.dwNumValues > 0) { object[] values = ComUtils.GetVARIANTs(ref attributes.vAttributeValues, attributes.dwNumValues, true); DateTime[] timestamps = ComUtils.GetDateTimes(ref attributes.ftTimeStamps, attributes.dwNumValues, true); result.Value = ComUtils.ProcessComValue(values[0]); result.Timestamp = timestamps[0]; } pos = (IntPtr)(pos.ToInt64() + Marshal.SizeOf(typeof(OPCHDA_ATTRIBUTE))); } Marshal.FreeCoTaskMem(ppAttributeValues); return results; }
/// <summary> /// Reads the raw modified data for an item. /// </summary> private StatusCode ReadAttributes(HdaHistoryReadAttributeRequest request, params int[] attributeIds) { string methodName = "IOPCHDA_SyncRead.ReadAttribute"; OPCHDA_TIME htStartTime = ConvertTime(request.StartTime); OPCHDA_TIME htEndTime = ConvertTime(request.EndTime); IntPtr ppAttributeValues; IntPtr ppErrors; try { IOPCHDA_SyncRead server = BeginComCall<IOPCHDA_SyncRead>(methodName, true); server.ReadAttribute( ref htStartTime, ref htEndTime, request.ServerHandle, attributeIds.Length, attributeIds, out ppAttributeValues, out ppErrors); } catch (Exception e) { ComCallError(methodName, e); return StatusCodes.BadUnexpectedError; } finally { EndComCall(methodName); } StatusCode status = StatusCodes.Good; // error in one attribute means operation failed. int[] errors = ComUtils.GetInt32s(ref ppErrors, attributeIds.Length, true); for (int ii = 0; ii < errors.Length; ii++) { if (errors[ii] < 0) { status = StatusCodes.BadNodeIdUnknown; break; } } // unmarshal results. HdaAttributeValue[][] results = new HdaAttributeValue[attributeIds.Length][]; IntPtr pos = ppAttributeValues; for (int ii = 0; ii < attributeIds.Length; ii++) { OPCHDA_ATTRIBUTE attributes = (OPCHDA_ATTRIBUTE)Marshal.PtrToStructure(pos, typeof(OPCHDA_ATTRIBUTE)); if (attributes.dwNumValues > 0) { results[ii] = new HdaAttributeValue[attributes.dwNumValues]; object[] values = ComUtils.GetVARIANTs(ref attributes.vAttributeValues, attributes.dwNumValues, true); DateTime[] timestamps = ComUtils.GetDateTimes(ref attributes.ftTimeStamps, attributes.dwNumValues, true); for (int jj = 0; jj < values.Length; jj++) { HdaAttributeValue result = results[ii][jj] = new HdaAttributeValue(); result.AttributeId = Utils.ToUInt32(attributeIds[ii]); result.Value = ComUtils.ProcessComValue(values[jj]); result.Timestamp = timestamps[jj]; result.Error = ResultIds.S_OK; } } else { results[ii] = new HdaAttributeValue[1]; HdaAttributeValue result = results[ii][0] = new HdaAttributeValue(); result.AttributeId = Utils.ToUInt32(attributeIds[ii]); result.Value = null; result.Timestamp = request.StartTime; result.Error = ResultIds.S_NODATA; } pos = (IntPtr)(pos.ToInt64() + Marshal.SizeOf(typeof(OPCHDA_ATTRIBUTE))); } Marshal.FreeCoTaskMem(ppAttributeValues); // save the results. request.SetHistoryResults(attributeIds, results); return StatusCodes.Good; }
private HdaAttributeValue[] NextTuple(HdaAttributeValue[][] results, int[] indexes) { int soonest = -1; DateTime timestamp = DateTime.MaxValue; for (int ii = 0; ii < indexes.Length; ii++) { // get the next index for the series. int index = indexes[ii] + 1; // check if at the end of the series. if (index >= results[ii].Length) { continue; } // check the timestamp. HdaAttributeValue value = results[ii][index]; if (value.Timestamp < timestamp) { timestamp = value.Timestamp; soonest = ii; } } // check if at end. if (soonest == -1) { return(null); } // increment all series with a matching timestamp. for (int ii = 0; ii < indexes.Length; ii++) { // get the next index for the series. int index = indexes[ii] + 1; // check if at the end of the series. if (index >= results[ii].Length) { continue; } // check the timestamp. HdaAttributeValue value = results[ii][index]; if (value.Timestamp == timestamp) { indexes[ii]++; } } // build the tuple. HdaAttributeValue[] tuple = new HdaAttributeValue[indexes.Length]; for (int ii = 0; ii < indexes.Length; ii++) { tuple[ii] = results[ii][indexes[ii]]; } return(tuple); }
/// <summary> /// Gets the result for the read operation. /// </summary> /// <param name="context">The context.</param> /// <param name="attribute">The attribute.</param> /// <param name="nodeToRead">The node to read.</param> /// <param name="value">The value.</param> /// <param name="diagnosticsMasks">The diagnostics masks.</param> /// <returns></returns> public ServiceResult GetResult( ISystemContext context, HdaAttributeState attribute, ReadValueId nodeToRead, DataValue value, DiagnosticsMasks diagnosticsMasks) { if (nodeToRead.AttributeId != Attributes.Value) { // check if reading access level. if (nodeToRead.AttributeId == Attributes.AccessLevel || nodeToRead.AttributeId == Attributes.UserAccessLevel) { HdaAttributeValue result = GetAttributeValue(attribute.Attribute.Id); if (result == null || result.Error < 0 || result.Error == ResultIds.S_NODATA) { value.StatusCode = StatusCodes.BadNotFound; return(value.StatusCode); } value.Value = AccessLevels.CurrentRead; if (result.Error != ResultIds.S_CURRENTVALUE) { value.Value = (byte)(AccessLevels.CurrentRead | AccessLevels.HistoryRead); } return(value.StatusCode); } return(StatusCodes.BadAttributeIdInvalid); } // convert values when required. switch (attribute.Attribute.Id) { case Constants.OPCHDA_NORMAL_MAXIMUM: { double high = this.GetAttributeValue <double>(Constants.OPCHDA_NORMAL_MAXIMUM, value, true); if (StatusCode.IsBad(value.StatusCode)) { return(value.StatusCode); } double low = this.GetAttributeValue <double>(Constants.OPCHDA_NORMAL_MINIMUM, value, true); if (StatusCode.IsBad(value.StatusCode)) { return(value.StatusCode); } value.Value = new Range(high, low); break; } case Constants.OPCHDA_HIGH_ENTRY_LIMIT: { double high = this.GetAttributeValue <double>(Constants.OPCHDA_HIGH_ENTRY_LIMIT, value, true); if (StatusCode.IsBad(value.StatusCode)) { return(value.StatusCode); } double low = this.GetAttributeValue <double>(Constants.OPCHDA_LOW_ENTRY_LIMIT, value, true); if (StatusCode.IsBad(value.StatusCode)) { return(value.StatusCode); } value.Value = new Range(high, low); break; } case Constants.OPCHDA_ENG_UNITS: { string units = this.GetAttributeValue <string>(Constants.OPCHDA_ENG_UNITS, value, true); if (StatusCode.IsBad(value.StatusCode)) { return(value.StatusCode); } value.Value = new EUInformation(units, Namespaces.ComInterop); break; } case Constants.OPCHDA_MAX_TIME_INT: case Constants.OPCHDA_MIN_TIME_INT: { string number = this.GetAttributeValue <string>(attribute.Attribute.Id, value, true); if (StatusCode.IsBad(value.StatusCode)) { return(value.StatusCode); } try { value.Value = Convert.ToDouble(number); } catch (Exception) { value.StatusCode = StatusCodes.BadTypeMismatch; return(value.StatusCode); } break; } case Constants.OPCHDA_EXCEPTION_DEV_TYPE: { short number = this.GetAttributeValue <short>(attribute.Attribute.Id, value, true); if (StatusCode.IsBad(value.StatusCode)) { return(value.StatusCode); } value.Value = (int)number; break; } default: { object result = this.GetAttributeValue <object>(attribute.Attribute.Id, value, true); if (StatusCode.IsBad(value.StatusCode)) { return(value.StatusCode); } value.Value = result; break; } } // check if the attribute value is missing. if (value.StatusCode == StatusCodes.BadNotFound) { return(StatusCodes.BadNodeIdUnknown); } return(ApplyIndexRangeAndDataEncoding(context, nodeToRead, value)); }
/// <summary> /// Finds the children for hda item configuration. /// </summary> /// <param name="client">The client.</param> /// <param name="children">The children.</param> /// <param name="attributes">The attribute values.</param> private void FindChildrenForHdaItemConfiguration(ComHdaClient client, List<BaseInstanceState> children, HdaAttributeValue[] attributes) { BaseInstanceState child = null; if (IsRequired(ReferenceTypeIds.HasProperty, false)) { for (int ii = 0; ii < attributes.Length; ii++) { if (attributes[ii].Error < 0 || attributes[ii].Error == ResultIds.S_NODATA) { continue; } bool skip = true; switch (attributes[ii].AttributeId) { case Constants.OPCHDA_DERIVE_EQUATION: case Constants.OPCHDA_STEPPED: case Constants.OPCHDA_MAX_TIME_INT: case Constants.OPCHDA_MIN_TIME_INT: case Constants.OPCHDA_EXCEPTION_DEV: case Constants.OPCHDA_EXCEPTION_DEV_TYPE: { skip = false; break; } } if (skip) { continue; } child = client.FindItemAttribute(m_itemId, attributes[ii].AttributeId, m_namespaceIndex); if (child != null) { children.Add(child); } } } }