/// <summary> /// Prompts the user to view the values of a trend. /// </summary> public bool ShowDialog(TsCHdaServer server, TsCHdaItemValueCollection values, bool readOnly) { if (server == null) { throw new ArgumentNullException("server"); } if (values == null) { throw new ArgumentNullException("values"); } // initialize controls. trendCtrl_.Initialize(server, values); trendCtrl_.ReadOnly = readOnly; // show the dialog. if (ShowDialog() != DialogResult.OK) { return(false); } // update collection if not read only. if (!readOnly) { values.Clear(); foreach (TsCHdaItemValue value in trendCtrl_.GetValues()) { values.Add(value); } } return(true); }
/// <summary> /// Unmarshals and deallocates an OPCHDA_ITEM structure. /// </summary> internal static TsCHdaItemValueCollection GetItemValueCollection(OpcRcw.Hda.OPCHDA_ITEM input, bool deallocate) { TsCHdaItemValueCollection output = new TsCHdaItemValueCollection(); output.ClientHandle = input.hClient; output.Aggregate = input.haAggregate; object[] values = Com.Interop.GetVARIANTs(ref input.pvDataValues, input.dwCount, deallocate); DateTime[] timestamps = Utilities.Interop.GetDateTimes(ref input.pftTimeStamps, input.dwCount, deallocate); int[] qualities = Utilities.Interop.GetInt32s(ref input.pdwQualities, input.dwCount, deallocate); for (int ii = 0; ii < input.dwCount; ii++) { TsCHdaItemValue value = new TsCHdaItemValue(); value.Value = values[ii]; value.Timestamp = timestamps[ii]; value.Quality = new TsCDaQuality((short)(qualities[ii] & 0x0000FFFF)); value.HistorianQuality = (TsCHdaQuality)((int)(qualities[ii] & 0xFFFF0000)); output.Add(value); } return(output); }
/// <summary> /// Unmarshals and deallocates an array of OPCHDA_ITEM structures. /// </summary> internal static TsCHdaItemValueCollection[] GetItemValueCollections(ref IntPtr pInput, int count, bool deallocate) { TsCHdaItemValueCollection[] output = null; if (pInput != IntPtr.Zero && count > 0) { output = new TsCHdaItemValueCollection[count]; IntPtr pos = pInput; for (int ii = 0; ii < count; ii++) { output[ii] = GetItemValueCollection(pos, deallocate); pos = (IntPtr)(pos.ToInt64() + Marshal.SizeOf(typeof(OpcRcw.Hda.OPCHDA_ITEM))); } if (deallocate) { Marshal.FreeCoTaskMem(pInput); pInput = IntPtr.Zero; } } return(output); }
/// <summary> /// Determines what time units should be used for the value collection. /// </summary> private double CalculateUnits(TsCHdaItemValueCollection values) { TimeSpan range = (values.EndTime - values.StartTime); if (values.Count > 0) { // calculate the total span. range = (values[values.Count - 1].Timestamp - values[0].Timestamp); // up to 100 hours before switching to days. if (Math.Abs(range.TotalDays) > 4) { return(TimeSpan.TicksPerDay); } // up to 1000 minutes before switching to hours. if (Math.Abs(range.TotalHours) > 16) { return(TimeSpan.TicksPerHour); } // up to 1000 seconds before switching to minutes. if (Math.Abs(range.TotalMinutes) > 16) { return(TimeSpan.TicksPerMinute); } } // default is seconds. return(TimeSpan.TicksPerSecond); }
/// <summary> /// Compares the expected results to the actual results. /// </summary> private bool CheckResults(TsCHdaItemValueCollection expected, TsCHdaItemValueCollection actual) { // check result codes. if (expected.Result.Name.Name != actual.Result.Name.Name) { return(false); } // check that number of results are equal. if (expected.Count != actual.Count) { return(false); } for (int ii = 0; ii < expected.Count; ii++) { // compare timestamps. if (expected[ii].Timestamp != actual[ii].Timestamp) { return(false); } // compare quality. if (expected[ii].Quality != actual[ii].Quality) { return(false); } // compare histrorian quality. if (expected[ii].HistorianQuality != actual[ii].HistorianQuality) { return(false); } // check for null (empty or bad values). if (expected[ii].Value == null || actual[ii].Value == null) { if (expected[ii].Value != actual[ii].Value) { return(false); } } // comapare value - allowing for some round off errors. else { decimal expectedValue = System.Convert.ToDecimal(expected[ii].Value); decimal actualValue = System.Convert.ToDecimal(actual[ii].Value); if (Math.Abs(expectedValue - actualValue) > 0.001M) { return(false); } } } // test passed - actual results match expected. return(true); }
/// <summary> /// Called when a batch of data from playback request arrives. /// </summary> public void OnPlayback( int dwTransactionID, int hrStatus, int dwNumItems, IntPtr ppItemValues, int[] phrErrors) { try { lock (this) { // lookup request transaction. Request request = (Request)m_requests[dwTransactionID]; if (request == null) { return; } // unmarshal results. TsCHdaItemValueCollection[] results = new TsCHdaItemValueCollection[dwNumItems]; // the data is transfered as a array of pointers to items instead of simply // as an array of items. This is due to a mistake in the HDA IDL. int[] pItems = Technosoftware.DaAeHdaClient.Utilities.Interop.GetInt32s(ref ppItemValues, dwNumItems, false); for (int ii = 0; ii < dwNumItems; ii++) { // get pointer to item. IntPtr pItem = (IntPtr)pItems[ii]; // unmarshal item as an array of length 1. TsCHdaItemValueCollection[] item = Interop.GetItemValueCollections(ref pItem, 1, false); if (item != null && item.Length == 1) { results[ii] = item[0]; results[ii].ServerHandle = results[ii].ClientHandle; results[ii].ClientHandle = null; results[ii].Result = Technosoftware.DaAeHdaClient.Utilities.Interop.GetResultID(phrErrors[ii]); } } // invoke callback - remove request if unexpected error occured. if (request.InvokeCallback(results)) { m_requests.Remove(request.RequestID); } } } catch (Exception exception) { HandleException(dwTransactionID, exception); } }
/// <summary> /// Returns the set of item values stored in the list control. /// </summary> public TsCHdaItemValueCollection GetValues() { TsCHdaItemValueCollection values = new TsCHdaItemValueCollection(); foreach (ListViewItem listItem in valuesLv_.Items) { if (typeof(TsCHdaItemValue).IsInstanceOfType(listItem.Tag)) { values.Add(listItem.Tag); } } return(values); }
/// <summary> /// Unmarshals and deallocates an OPCHDA_ITEM structure. /// </summary> internal static TsCHdaItemValueCollection GetItemValueCollection(IntPtr pInput, bool deallocate) { TsCHdaItemValueCollection output = null; if (pInput != IntPtr.Zero) { object item = Marshal.PtrToStructure(pInput, typeof(OpcRcw.Hda.OPCHDA_ITEM)); output = GetItemValueCollection((OpcRcw.Hda.OPCHDA_ITEM)item, deallocate); if (deallocate) { Marshal.DestroyStructure(pInput, typeof(OpcRcw.Hda.OPCHDA_ITEM)); } } return(output); }
/// <summary> /// Called when new data arrives for a subscription. /// </summary> public void OnDataChange( int dwTransactionID, int hrStatus, int dwNumItems, OPCHDA_ITEM[] pItemValues, int[] phrErrors) { try { lock (this) { // lookup request transaction. Request request = (Request)m_requests[dwTransactionID]; if (request == null) { return; } // unmarshal results. TsCHdaItemValueCollection[] results = new TsCHdaItemValueCollection[pItemValues.Length]; for (int ii = 0; ii < pItemValues.Length; ii++) { results[ii] = Interop.GetItemValueCollection(pItemValues[ii], false); results[ii].ServerHandle = results[ii].ClientHandle; results[ii].ClientHandle = null; results[ii].Result = Technosoftware.DaAeHdaClient.Utilities.Interop.GetResultID(phrErrors[ii]); } // invoke callback - remove request if unexpected error occured. if (request.InvokeCallback(results)) { m_requests.Remove(request.RequestID); } } } catch (Exception exception) { HandleException(dwTransactionID, exception); } }
/// <summary> /// Reads the expected results for a test case from the dataset. /// </summary> private TsCHdaItemValueCollection GetExpectedResults(DataSet.TestCase testcase) { // create item value collection. TsCHdaItemValueCollection values = new TsCHdaItemValueCollection(); try { // set expected result. values.Result = new OpcResult(testcase.ResultId, ""); // get the item values. DataRow[] rows = testcase.GetChildRows(mDataset_.TestCases.ChildRelations[0]); // read the expected values. if (rows != null) { foreach (DataSet.TsCHdaItemValue row in rows) { // create item value. TsCHdaItemValue value = new TsCHdaItemValue(); if (!typeof(DBNull).IsInstanceOfType(row["Value"])) { value.Value = row.Value; } value.Timestamp = Basetime.AddSeconds((double)row.Timestamp); value.Quality = new TsCDaQuality((short)(row.Quality & 0x000FFFF)); value.HistorianQuality = (Technosoftware.DaAeHdaClient.Hda.TsCHdaQuality)Enum.ToObject(typeof(Technosoftware.DaAeHdaClient.Hda.TsCHdaQuality), (int)(row.Quality & 0xFFFF0000)); // add to list. values.Add(value); } } } catch (Exception) { // ignore exceptions - return at whatever was read correctly. } // return set of values. return(values); }
/// <summary> /// Creates a set of points from an item value collection. /// </summary> private ArrayAdapter CreateAdapter( TsCHdaItemValueCollection values, int qualityMask, DateTime startTime, double units) { // select only those values with the specified quality. ArrayList points = new ArrayList(); foreach (TsCHdaItemValue value in values) { int qualityBits = (int)value.Quality.QualityBits & 0xC0; if (qualityBits == qualityMask) { points.Add(value); } } // no values meet quality criteria. if (points.Count == 0) { return(null); } // create array. double[] xs = new double[points.Count]; double[] ys = new double[points.Count]; for (int ii = 0; ii < points.Count; ii++) { TsCHdaItemValue value = (TsCHdaItemValue)points[ii]; // calculate the difference between the start time and the current timestamp. long delta = ((TimeSpan)(value.Timestamp - startTime)).Ticks; xs[ii] = ((double)delta) / units; ys[ii] = System.Convert.ToDouble(value.Value); } // return points. return(new ArrayAdapter(xs, ys)); }
/// <summary> /// Called when an asynchronous read request completes. /// </summary> public void OnReadComplete( int dwTransactionID, int hrStatus, int dwNumItems, OPCHDA_ITEM[] pItemValues, int[] phrErrors) { try { lock (this) { // lookup request transaction. Request request = (Request)m_requests[dwTransactionID]; if (request == null) { return; } // unmarshal results. TsCHdaItemValueCollection[] results = new TsCHdaItemValueCollection[pItemValues.Length]; for (int ii = 0; ii < pItemValues.Length; ii++) { results[ii] = Interop.GetItemValueCollection(pItemValues[ii], false); results[ii].ServerHandle = pItemValues[ii].hClient; results[ii].Result = Utilities.Interop.GetResultId(phrErrors[ii]); } // invoke callback - remove request if all results arrived. if (request.InvokeCallback(results)) { m_requests.Remove(request.RequestID); } } } catch (Exception exception) { HandleException(dwTransactionID, exception); } }
/// <summary> /// Initializes an item value collection by reading data from another item. /// </summary> private void CopyDataMI_Click(object sender, System.EventArgs e) { try { // check for valid selection. if (ItemsLV.SelectedItems.Count != 1) { return; } // must be an item value collection. object item = ItemsLV.SelectedItems[0].Tag; if (!typeof(TsCHdaItemValueCollection).IsInstanceOfType(item)) { return; } // prompt user to select a collection to copy. TsCHdaItemValueCollection values = new ReadValuesDlg().ShowDialog(m_trend.Server, RequestType.ReadRaw, true); if (values != null) { // replace item identifier information. TsCHdaItemValueCollection existing = (TsCHdaItemValueCollection)item; values.ItemName = existing.ItemName; values.ItemPath = existing.ItemPath; values.ServerHandle = existing.ServerHandle; values.ClientHandle = existing.ClientHandle; // update list item. UpdateListItem(ItemsLV.SelectedItems[0], values); } } catch (Exception exception) { MessageBox.Show(exception.Message); } }
/// <summary> /// Initializes the control with a set of items. /// </summary> public void Initialize(TsCHdaServer server, TsCHdaItemValueCollection values) { mServer_ = server; mItem_ = values; valuesLv_.Items.Clear(); plotCtrl_.Clear(); if (values != null) { // add item values to list. foreach (TsCHdaItemValue value in values) { AddListItem(value, -1); } // adjust the list view columns to fit the data. AdjustColumns(); } // update control state. SetState(graphMi_.Checked); }
/// <summary> /// Initializes the control with a set of items. /// </summary> public void Initialize(TsCHdaServer server, TsCHdaItemValueCollection values) { m_server = server; m_item = values; ValuesLV.Items.Clear(); PlotCTRL.Clear(); if (values != null) { // add item values to list. foreach (TsCHdaItemValue value in values) { AddListItem(value, -1); } // adjust the list view columns to fit the data. AdjustColumns(); } // update control state. SetState(GraphMI.Checked); }
/// <summary> /// Draws a graph for the current set of values. /// </summary> private void DrawGraph() { // clear existing plot. plotCtrl_.Clear(); // update title. if (mItem_ != null && mItem_.ItemName != null && mItem_.ItemName != "") { plotCtrl_.Title = mItem_.ItemName; } // get current set of values. TsCHdaItemValueCollection values = GetValues(); if (values == null || (values.Count == 0 && (values.StartTime == DateTime.MinValue || values.EndTime == DateTime.MinValue))) { plotCtrl_.Add(new PointPlot(new ArrayAdapter(new double[] { 0, 100 }, new double[] { 0, 100 }))); plotCtrl_.XAxis1.Label = "No Data Available"; plotCtrl_.Refresh(); return; } // determine the best set of units. double units = CalculateUnits(values); // the first timestamp is the reference point for the plot. DateTime startTime = (values.Count > 0)?values[0].Timestamp:values.StartTime; // display empty set by plotting the time axis. if (values.Count == 0) { // create array. double[] xs = new double[2]; double[] ys = new double[2]; xs[0] = 0; ys[0] = 0; xs[1] = ((double)(((TimeSpan)(values.EndTime - startTime)).Ticks)) / units; ys[1] = 100; plotCtrl_.Add(new PointPlot(new ArrayAdapter(xs, ys))); plotCtrl_.XAxis1.Label = CreateLabel(startTime, units); plotCtrl_.Refresh(); return; } // create seperate plots for each quality of data. int[] qualityMasks = new int[] { 0xC0, 0x40, 0x00 }; // create different icons for each type of data. Marker[] markers = new Marker[] { new Marker(MarkerType.Circle, 4, new Pen(Color.Black)), new Marker(MarkerType.Square, 4, new Pen(Color.Blue)), new Marker(MarkerType.Cross1, 4, new Pen(Color.Red)) }; // add plots to control. for (int ii = 0; ii < qualityMasks.Length; ii++) { ArrayAdapter adpater = CreateAdapter(values, qualityMasks[ii], startTime, units); if (adpater != null) { if (adpater.Count < 40) { plotCtrl_.Add(new PointPlot(adpater, markers[ii])); } else { plotCtrl_.Add(new LinePlot(adpater)); } } } // update the label. plotCtrl_.XAxis1.Label = CreateLabel(startTime, units); // display the data. plotCtrl_.Refresh(); }
/// <summary> /// Updates the cached values for the items. /// </summary> private void TrendsCTRL_TrendChanged(TsCHdaTrend trend, TsCHdaItemValueCollection[] values, bool replace) { // add new values to cache. if (values != null && values.Length > 0) { foreach (TsCHdaItemValueCollection value in values) { // ignore results without a client handle. if (value.ClientHandle == null) { continue; } // check if results for the item already exist. TsCHdaItemValueCollection existingValues = (TsCHdaItemValueCollection)m_cache[value.ClientHandle]; if (!replace && existingValues != null) { existingValues.AddRange(value); } // replace existing or insert new results for the item. else { m_cache[value.ClientHandle] = value; } } // update values display if nothing is selected. if (m_selectedItem == null) { m_selectedItem = values[0].ClientHandle; ValuesCTRL.Initialize(m_server, (TsCHdaItemValueCollection)m_cache[m_selectedItem]); } // onluy update values display if current selection changed. else { foreach (OpcItem item in values) { if (m_selectedItem.Equals(item.ClientHandle)) { ValuesCTRL.Initialize(m_server, (TsCHdaItemValueCollection)m_cache[m_selectedItem]); } } } } // clear items from the cache. else if (replace) { foreach (TsCHdaItem item in trend.Items) { if (item.ClientHandle != null) { if (item.ClientHandle.Equals(m_selectedItem)) { ValuesCTRL.Initialize(m_server, null); m_selectedItem = null; } m_cache.Remove(item.ClientHandle); } } } }