/// <summary> /// IOPCAsyncIO3::WriteVQT - Writes one or more values, qualities and timestamps for the items specified. /// The results are returned via the client�s IOPCDataCallback connection established /// through the server�s IConnectionPointContainer. /// </summary> public void WriteVQT( int dwCount, int[] phServer, OPCITEMVQT[] pItemVQT, int dwTransactionID, out int pdwCancelID, out System.IntPtr ppErrors) { pdwCancelID = 0; // validate arguments. if (dwCount == 0 || phServer == null || pItemVQT == null || dwCount != phServer.Length || dwCount != pItemVQT.Length) { throw ComUtils.CreateComException(ResultIds.E_INVALIDARG); } // get callback object - nothing more to do if missing. IOPCDataCallback callback = (IOPCDataCallback)GetCallback(typeof(IOPCDataCallback).GUID); if (callback == null) { throw ComUtils.CreateComException(ResultIds.CONNECT_E_NOCONNECTION); } try { int[] errors = new int[dwCount]; // build list of values to write. WriteValueCollection valuesToWrite = new WriteValueCollection(); lock (m_lock) { if (m_subscription == null) throw ComUtils.CreateComException(ResultIds.E_FAIL); CallbackValue[] conversionErrors = null; for (int ii = 0; ii < dwCount; ii++) { Item itemToWrite = null; if (!m_items.TryGetValue(phServer[ii], out itemToWrite)) { errors[ii] = ResultIds.E_INVALIDHANDLE; continue; } VariableNode variable = itemToWrite.Variable; WriteValue valueToWrite = new WriteValue(); valueToWrite.NodeId = variable.NodeId; valueToWrite.IndexRange = null; valueToWrite.AttributeId = Attributes.Value; DataValue value = new DataValue(); int error = 0; value.Value = m_server.VariantValueToValue(variable, pItemVQT[ii].vDataValue, out error); if (error != ResultIds.S_OK) { // only allocate this array when it is needed. if (conversionErrors == null) { conversionErrors = new CallbackValue[dwCount]; } // create the callback item. CallbackValue conversionError = new CallbackValue(); conversionError.ClientHandle = itemToWrite.ClientHandle; conversionError.Error = error; conversionErrors[ii] = conversionError; errors[ii] = error; continue; } valueToWrite.Value = value; if (pItemVQT[ii].bQualitySpecified != 0) { value.StatusCode = ComUtils.GetQualityCode(pItemVQT[ii].wQuality); } if (pItemVQT[ii].bTimeStampSpecified != 0) { value.SourceTimestamp = ComUtils.GetDateTime(pItemVQT[ii].ftTimeStamp); } // needed to correlate results to input. valueToWrite.Handle = itemToWrite; valuesToWrite.Add(valueToWrite); } // create transaction. if (valuesToWrite.Count > 0 || conversionErrors != null) { pdwCancelID = Utils.IncrementIdentifier(ref m_nextHandle); m_transactions[pdwCancelID] = new AsyncWriteTransaction(dwTransactionID, valuesToWrite); } // send conversion errors in the callback if no valid items available (CTT bug workaround). if (valuesToWrite.Count == 0 && conversionErrors != null) { // must return S_OK from this function if sending the errors in the callback. List<CallbackValue> errorsToSend = new List<CallbackValue>(); for (int ii = 0; ii < conversionErrors.Length; ii++) { if (conversionErrors[ii] != null) { errors[ii] = ResultIds.S_OK; errorsToSend.Add(conversionErrors[ii]); } } // queue the request. CallbackRequest request = new CallbackRequest(); request.CallbackType = CallbackType.Write; request.Callback = callback; request.TransactionId = dwTransactionID; request.GroupHandle = m_clientHandle; request.ServerHandle = m_serverHandle; request.Values = errorsToSend; QueueCallbackRequest(request); } } // write values from server. if (valuesToWrite.Count > 0) { m_session.BeginWrite( null, valuesToWrite, new AsyncCallback(OnWriteComplete), pdwCancelID); } // marshal error codes. ppErrors = ComUtils.GetInt32s(errors); } catch (Exception e) { Utils.Trace(e, "Error writing items."); throw ComUtils.CreateComException(e); } }
/// <summary> /// Called when an asynchronous write operation completes. /// </summary> private void OnWriteComplete(IAsyncResult result) { AsyncWriteTransaction transaction = null; lock (m_lock) { // complete the write operation. StatusCodeCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; int serviceError = ResultIds.S_OK; try { m_session.EndWrite( result, out results, out diagnosticInfos); } catch (Exception) { serviceError = ResultIds.E_FAIL; } try { // check if transaction has been cancelled. int cancelId = (int)result.AsyncState; Transaction transaction2 = null; if (!m_transactions.TryGetValue(cancelId, out transaction2)) { return; } transaction = (AsyncWriteTransaction)transaction2; m_transactions.Remove(cancelId); // get callback object - nothing more to do if missing. IOPCDataCallback callback = (IOPCDataCallback)GetCallback(typeof(IOPCDataCallback).GUID); if (callback == null) { return; } // process results. WriteValueCollection valuesToWrite = transaction.ValuesToWrite; List<CallbackValue> callbackValues = new List<CallbackValue>(); for (int ii = 0; ii < valuesToWrite.Count; ii++) { // get item originally written. Item itemToWrite = (Item)valuesToWrite[ii].Handle; int error = serviceError; // get for operation level error. if (serviceError >= 0) { error = Server.MapWriteStatusToErrorCode(results[ii]); } CallbackValue callbackValue = new CallbackValue(); callbackValue.ClientHandle = itemToWrite.ClientHandle; callbackValue.Error = error; callbackValues.Add(callbackValue); } // queue the callback. CallbackRequest request = new CallbackRequest(); request.CallbackType = CallbackType.Write; request.Callback = callback; request.TransactionId = transaction.TransactionId; request.GroupHandle = m_clientHandle; request.ServerHandle = m_serverHandle; request.Values = callbackValues; QueueCallbackRequest(request); } catch (Exception e) { Utils.Trace(e, "Unexpected error processing asynchronous write callback."); } } }
/// <summary> /// Queues a datachange. /// </summary> private void QueueDataChange(bool sendAll) { // dequeue values from monitored item caches. List<CallbackValue> changes = new List<CallbackValue>(); foreach (Item item in this.m_items.Values) { IList<DataValue> values = item.MonitoredItem.DequeueValues(); // send the cached value if an update must be sent. if (sendAll && values.Count == 0) { values = new DataValue[1]; // look of value in the publishing cache. DataValue dataValue = ReadCachedValue(item, Int32.MaxValue); // create a dummy value if nothing in the cache. if (dataValue == null) { dataValue = new DataValue(); dataValue.ServerTimestamp = DateTime.UtcNow; dataValue.StatusCode = StatusCodes.BadWaitingForInitialData; } values[0] = dataValue; } //Utils.Trace( // "Values Found: Group={0}, Changes={1}", // m_clientHandle, // values.Count); for (int ii = 0; ii < values.Count; ii++) { // apply any type conversions. object value; short quality; DateTime timestamp; int error = ProcessReadResult( item.ServerHandle, item.ReqType, values[ii], out value, out quality, out timestamp); item.LastValueSent = value; item.LastQualitySent = quality; item.LastTimestampSent = timestamp; // update value in cache. UpdateCachedValue(item, values[ii]); // create callback value for active items if (item.Active && m_active && m_enabled) { CallbackValue change = new CallbackValue(); change.ServerHandle = item.ServerHandle; change.ClientHandle = item.ClientHandle; change.Value = value; change.Quality = quality; change.Timestamp = timestamp; change.Error = error; changes.Add(change); } } } // get callback object - do nothing if missing. IOPCDataCallback callback = (IOPCDataCallback)GetCallback(typeof(IOPCDataCallback).GUID); if (callback == null) { return; } // check if there are changes to send. if (changes.Count > 0) { CallbackRequest request = new CallbackRequest(); request.CallbackType = CallbackType.DataChange; request.Callback = callback; request.GroupHandle = m_clientHandle; request.ServerHandle = m_serverHandle; request.Values = changes; //Utils.Trace( // "Callback Queued: Group={0}, Changes={1}, Value[0]={2}", // m_clientHandle, // changes.Count, // changes[0].Value); QueueCallbackRequest(request); } }
/// <summary> /// Called when an asynchronous read operation completes. /// </summary> private void OnReadComplete(IAsyncResult result) { AsyncReadTransaction transaction = null; lock (m_lock) { // complete the operation. DataValueCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; int serviceError = ResultIds.S_OK; try { m_session.EndRead( result, out results, out diagnosticInfos); } catch (Exception) { serviceError = ResultIds.E_FAIL; } try { // check if transaction has been cancelled. int cancelId = (int)result.AsyncState; Transaction transaction2 = null; if (!m_transactions.TryGetValue(cancelId, out transaction2)) { return; } transaction = (AsyncReadTransaction)transaction2; m_transactions.Remove(cancelId); // get callback object - nothing more to do if missing. IOPCDataCallback callback = (IOPCDataCallback)GetCallback(typeof(IOPCDataCallback).GUID); if (callback == null) { return; } // process results. ReadValueIdCollection nodesToRead = transaction.NodesToRead; List<CallbackValue> callbackValues = new List<CallbackValue>(); for (int ii = 0; ii < nodesToRead.Count; ii++) { // get item in originally read. Item itemToRead = (Item)nodesToRead[ii].Handle; // process the read result. object value = null; short quality = Qualities.OPC_QUALITY_BAD; DateTime timestamp = DateTime.MinValue; int error = serviceError; if (serviceError >= 0) { error = ProcessReadResult( itemToRead.ServerHandle, itemToRead.ReqType, results[ii], out value, out quality, out timestamp); // update the cache. UpdateCachedValue(itemToRead, results[ii]); } CallbackValue callbackValue = new CallbackValue(); callbackValue.ClientHandle = itemToRead.ClientHandle; callbackValue.Value = value; callbackValue.Quality = quality; callbackValue.Timestamp = timestamp; callbackValue.Error = error; callbackValues.Add(callbackValue); } // queue the callback. CallbackRequest request = new CallbackRequest(); request.CallbackType = (transaction.IsRefresh)?CallbackType.DataChange:CallbackType.Read; request.Callback = callback; request.TransactionId = transaction.TransactionId; request.GroupHandle = m_clientHandle; request.ServerHandle = m_serverHandle; request.Values = callbackValues; QueueCallbackRequest(request); } catch (Exception e) { Utils.Trace(e, "Unexpected error processing asynchronous read callback."); } } }