/// <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); } }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// #region IOPCItemIO Members /// <summary> /// IOPCItemIO::WriteVQT - Writes one or more values, qualities and timestamps for the items specified. /// This is functionally similar to the IOPCSyncIO2::WriteVQT except that there is no associated group. /// </summary> public void WriteVQT( int dwCount, string[] pszItemIDs, OPCITEMVQT[] pItemVQT, out System.IntPtr ppErrors) { lock (m_lock) { if (m_session == null) throw ComUtils.CreateComException(ResultIds.E_FAIL); // validate arguments. if (dwCount == 0 || pszItemIDs == null || pItemVQT == null || dwCount != pszItemIDs.Length || dwCount != pItemVQT.Length) { throw ComUtils.CreateComException(ResultIds.E_INVALIDARG); } try { int[] errors = new int[dwCount]; // build list of values to write. WriteValueCollection valuesToWrite = new WriteValueCollection(); for (int ii = 0; ii < dwCount; ii++) { NodeId nodeId = ItemIdToNodeId(pszItemIDs[ii]); if (nodeId == null) { errors[ii] = ResultIds.E_INVALIDITEMID; continue; } VariableNode variable = m_session.NodeCache.Find(nodeId) as VariableNode; if (variable == null) { errors[ii] = ResultIds.E_UNKNOWNITEMID; continue; } WriteValue valueToWrite = new WriteValue(); valueToWrite.NodeId = nodeId; valueToWrite.IndexRange = null; valueToWrite.AttributeId = Attributes.Value; DataValue value = new DataValue(); int error = 0; value.Value = VariantValueToValue(variable, pItemVQT[ii].vDataValue, out error); if (error != ResultIds.S_OK) { errors[ii] = error; continue; } if (pItemVQT[ii].bQualitySpecified != 0) { value.StatusCode = ComUtils.GetQualityCode(pItemVQT[ii].wQuality); } if (pItemVQT[ii].bTimeStampSpecified != 0) { value.SourceTimestamp = ComUtils.GetDateTime(pItemVQT[ii].ftTimeStamp); } valueToWrite.Value = value; // needed to correlate results to input. valueToWrite.Handle = ii; valuesToWrite.Add(valueToWrite); } // write values from server. StatusCodeCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; if (valuesToWrite.Count > 0) { m_session.Write( null, valuesToWrite, out results, out diagnosticInfos); // validate response from the UA server. ClientBase.ValidateResponse(results, valuesToWrite); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, valuesToWrite); } for (int ii = 0; ii < valuesToWrite.Count; ii++) { // get index in original array. int index = (int)valuesToWrite[ii].Handle; // map UA code to DA code. errors[index] = MapWriteStatusToErrorCode(results[ii]); } // marshal error codes. ppErrors = ComUtils.GetInt32s(errors); } catch (Exception e) { throw ComUtils.CreateComException(e); } } }
/// <summary> /// Writes the values using the DA3 interfaces. /// </summary> /// <param name="requests">The requests.</param> private void Da30WriteItemValues(List<WriteRequest> requests) { int count = 0; string[] itemIDs = new string[requests.Count]; OpcRcw.Da.OPCITEMVQT[] values = new OpcRcw.Da.OPCITEMVQT[requests.Count]; WriteRequest[] writeRequests = new WriteRequest[requests.Count]; for (int ii = 0; ii < requests.Count; ii++) { WriteRequest request = requests[ii]; if (request == null) { continue; } // convert to a DA compatible type. object convertedValue = null; request.Error = ComDaClientNodeManager.LocalToRemoteValue(request.Value.WrappedValue, out convertedValue); if (request.Error < 0) { continue; } itemIDs[count] = request.ItemId; values[count].vDataValue = convertedValue; values[count].bQualitySpecified = 0; values[count].bTimeStampSpecified = 0; // check for quality. values[count].wQuality = ComUtils.GetQualityCode(request.Value.StatusCode); if (values[count].wQuality != Qualities.OPC_QUALITY_GOOD) { values[count].bQualitySpecified = 1; } // check for server timestamp. if (request.Value.ServerTimestamp != DateTime.MinValue) { values[count].ftTimeStamp = ComUtils.GetFILETIME(request.Value.ServerTimestamp); values[count].bTimeStampSpecified = 1; } // ignore server timestamp if source timestamp is provided. if (request.Value.SourceTimestamp != DateTime.MinValue) { values[count].ftTimeStamp = ComUtils.GetFILETIME(request.Value.SourceTimestamp); values[count].bTimeStampSpecified = 1; } writeRequests[count] = request; count++; } IntPtr ppErrors = IntPtr.Zero; string methodName = "IOPCItemIO.WriteVQT"; try { IOPCItemIO server = BeginComCall<IOPCItemIO>(methodName, true); server.WriteVQT( count, itemIDs, values, out ppErrors); } catch (Exception e) { ComUtils.TraceComError(e, methodName); return; } finally { EndComCall(methodName); } int[] errors = ComUtils.GetInt32s(ref ppErrors, count, true); for (int ii = 0; ii < count; ii++) { writeRequests[ii].Error = errors[ii]; } }