/// <summary>Initiates an asynchronous read operation on the pipe. </summary> /// <param name="buffer">Buffer that will receive the data read from the pipe.</param> /// <param name="offset">Byte offset within the buffer at which to begin writing the data received.</param> /// <param name="length">Length of the data to transfer.</param> /// <param name="userCallback">An optional asynchronous callback, to be called when the operation is complete. Can be null if no callback is required.</param> /// <param name="stateObject">A user-provided object that distinguishes this particular asynchronous operation. Can be null if not required.</param> /// <returns>An <see cref="IAsyncResult"/> object repesenting the asynchronous operation, which could still be pending.</returns> /// <remarks>This method always completes immediately even if the operation is still pending. The <see cref="IAsyncResult"/> object returned represents the operation /// and must be passed to <see cref="EndRead"/> to retrieve the result of the operation. For every call to this method a matching call to /// <see cref="EndRead"/> must be made. When <paramref name="userCallback"/> specifies a callback function, this function will be called when the operation is completed. The optional /// <paramref name="stateObject"/> parameter can be used to pass user-defined information to this callback or the <see cref="IAsyncResult"/>. The <see cref="IAsyncResult"/> /// also provides an event handle (<see cref="IAsyncResult.AsyncWaitHandle" />) that will be triggered when the operation is complete as well. /// </remarks> public IAsyncResult BeginRead(byte[] buffer, int offset, int length, AsyncCallback userCallback, object stateObject) { CheckReadParams(buffer, offset, length); USBAsyncResult result = new USBAsyncResult(userCallback, stateObject); try { _device.InternalDevice.ReadPipeOverlapped(Interface.InterfaceIndex, _pipeInfo.PipeId, buffer, offset, length, result); } catch (API.APIException e) { if (result != null) { result.Dispose(); } // throw new USBException("Failed to read from pipe.", e); LogAndThrowException(new USBException("Failed to read from pipe.", e)); } catch (Exception e) { if (result != null) { result.Dispose(); } // throw; LogException(e); throw; } return(result); }
/// <summary>Initiates an asynchronous write operation on the pipe. </summary> /// <param name="buffer">Buffer that contains the data to write to the pipe.</param> /// <param name="offset">Byte offset within the buffer from which to begin writing.</param> /// <param name="length">Length of the data to transfer.</param> /// <param name="userCallback">An optional asynchronous callback, to be called when the operation is complete. Can be null if no callback is required.</param> /// <param name="stateObject">A user-provided object that distinguishes this particular asynchronous operation. Can be null if not required.</param> /// <returns>An <see cref="IAsyncResult"/> object repesenting the asynchronous operation, which could still be pending.</returns> /// <remarks>This method always completes immediately even if the operation is still pending. The <see cref="IAsyncResult"/> object returned represents the operation /// and must be passed to <see cref="EndWrite"/> to retrieve the result of the operation. For every call to this method a matching call to /// <see cref="EndWrite"/> must be made. When <paramref name="userCallback"/> specifies a callback function, this function will be called when the operation is completed. The optional /// <paramref name="stateObject"/> parameter can be used to pass user-defined information to this callback or the <see cref="IAsyncResult"/>. The <see cref="IAsyncResult"/> /// also provides an event handle (<see cref="IAsyncResult.AsyncWaitHandle" />) that will be triggered when the operation is complete as well. /// </remarks> public IAsyncResult BeginWrite(byte[] buffer, int offset, int length, AsyncCallback userCallback, object stateObject) { CheckWriteParams(buffer, offset, length); USBAsyncResult result = new USBAsyncResult(userCallback, stateObject); try { _device.InternalDevice.WriteOverlapped(Interface.InterfaceIndex, _pipeInfo.PipeId, buffer, offset, length, result); } catch (API.APIException e) { if (result != null) { result.Dispose(); } throw new USBException("Failed to write to pipe.", e); } catch (Exception) { if (result != null) { result.Dispose(); } throw; } return(result); }
/// <summary> /// Waits for a pending asynchronous write operation to complete. /// </summary> /// <param name="asyncResult">The <see cref="IAsyncResult"/> object representing the asynchonous operation, /// as returned by <see cref="BeginWrite"/>.</param> /// <returns>The number of bytes transfered during the operation.</returns> /// <remarks>Every call to <see cref="BeginWrite"/> must have a matching call to <see cref="EndWrite"/> to dispose /// of any resources used and to retrieve the result of the operation. When the operation was successful the method returns the number /// of bytes that were transfered. If an error occurred during the operation this method will throw the exceptions that would /// otherwise have ocurred during the operation. If the operation is not yet finished EndWrite will wait for the /// operation to finish before returning.</remarks> public void EndWrite(IAsyncResult asyncResult) { if (asyncResult == null) { // throw new NullReferenceException("asyncResult cannot be null"); LogAndThrowException(new NullReferenceException("asyncResult cannot be null")); } if (!(asyncResult is USBAsyncResult)) { // throw new ArgumentException("AsyncResult object was not created by calling BeginWrite on this class."); LogAndThrowException(new ArgumentException("AsyncResult object was not created by calling BeginWrite on this class.")); } USBAsyncResult result = (USBAsyncResult)asyncResult; try { // todo: check duplicate end writes? if (!result.IsCompleted) { result.AsyncWaitHandle.WaitOne(); } if (result.Error != null) { // throw new USBException("Asynchronous write to pipe has failed.", result.Error); LogAndThrowException(new USBException("Asynchronous write to pipe has failed.", result.Error)); } } finally { result.Dispose(); } }
/// <summary> /// Waits for a pending asynchronous read operation to complete. /// </summary> /// <param name="asyncResult">The <see cref="IAsyncResult"/> object representing the asynchonous operation, /// as returned by <see cref="BeginRead"/>.</param> /// <returns>The number of bytes transfered during the operation.</returns> /// <remarks>Every call to <see cref="BeginRead"/> must have a matching call to <see cref="EndRead"/> to dispose /// of any resources used and to retrieve the result of the operation. When the operation was successful the method returns the number /// of bytes that were transfered. If an error occurred during the operation this method will throw the exceptions that would /// otherwise have ocurred during the operation. If the operation is not yet finished EndWrite will wait for the /// operation to finish before returning.</remarks> public int EndRead(IAsyncResult asyncResult) { if (asyncResult == null) { throw new NullReferenceException("asyncResult cannot be null"); } if (!(asyncResult is USBAsyncResult)) { throw new ArgumentException("AsyncResult object was not created by calling BeginRead on this class."); } // todo: check duplicate end reads? USBAsyncResult result = (USBAsyncResult)asyncResult; try { if (!result.IsCompleted) { result.AsyncWaitHandle.WaitOne(); } if (result.Error != null) { throw new USBException("Asynchronous read from pipe has failed.", result.Error); } return(result.BytesTransfered); } finally { result.Dispose(); } }
/// <summary>Initiates an asynchronous write operation on the pipe. </summary> /// <param name="buffer">Buffer that contains the data to write to the pipe.</param> /// <param name="offset">Byte offset within the buffer from which to begin writing.</param> /// <param name="length">Length of the data to transfer.</param> /// <param name="userCallback">An optional asynchronous callback, to be called when the operation is complete. Can be null if no callback is required.</param> /// <param name="stateObject">A user-provided object that distinguishes this particular asynchronous operation. Can be null if not required.</param> /// <returns>An <see cref="IAsyncResult"/> object repesenting the asynchronous operation, which could still be pending.</returns> /// <remarks>This method always completes immediately even if the operation is still pending. The <see cref="IAsyncResult"/> object returned represents the operation /// and must be passed to <see cref="EndWrite"/> to retrieve the result of the operation. For every call to this method a matching call to /// <see cref="EndWrite"/> must be made. When <paramref name="userCallback"/> specifies a callback function, this function will be called when the operation is completed. The optional /// <paramref name="stateObject"/> parameter can be used to pass user-defined information to this callback or the <see cref="IAsyncResult"/>. The <see cref="IAsyncResult"/> /// also provides an event handle (<see cref="IAsyncResult.AsyncWaitHandle" />) that will be triggered when the operation is complete as well. /// </remarks> public IAsyncResult BeginWrite(byte[] buffer, int offset, int length, AsyncCallback userCallback, object stateObject) { CheckWriteParams(buffer, offset, length); LogLastWrite(buffer, offset, length); USBAsyncResult result = new USBAsyncResult(userCallback, stateObject); try { _device.InternalDevice.WriteOverlapped(Interface.InterfaceIndex, _pipeInfo.PipeId, buffer, offset, length, result); } catch (API.APIException e) { if (result != null) { result.Dispose(); } byte[] SubBuffer = new byte[(length < 16 ? length : 16)]; Array.Copy(buffer, offset, SubBuffer, 0, (length < 16 ? length : 16)); // throw new USBException("Failed to write to pipe: " + WPinternals.Converter.ConvertHexToString(SubBuffer, ""), e); LogAndThrowException(new USBException("Failed to write to pipe: " + WPinternals.Converter.ConvertHexToString(SubBuffer, ""), e)); } catch (Exception e) { if (result != null) { result.Dispose(); } // throw; LogException(e); throw; } return(result); }
/// <summary>Initiates an asynchronous write operation on the pipe. </summary> /// <param name="buffer">Buffer that contains the data to write to the pipe.</param> /// <param name="offset">Byte offset within the buffer from which to begin writing.</param> /// <param name="length">Length of the data to transfer.</param> /// <param name="userCallback">An optional asynchronous callback, to be called when the operation is complete. Can be null if no callback is required.</param> /// <param name="stateObject">A user-provided object that distinguishes this particular asynchronous operation. Can be null if not required.</param> /// <returns>An <see cref="IAsyncResult"/> object repesenting the asynchronous operation, which could still be pending.</returns> /// <remarks>This method always completes immediately even if the operation is still pending. The <see cref="IAsyncResult"/> object returned represents the operation /// and must be passed to <see cref="EndWrite"/> to retrieve the result of the operation. For every call to this method a matching call to /// <see cref="EndWrite"/> must be made. When <paramref name="userCallback"/> specifies a callback function, this function will be called when the operation is completed. The optional /// <paramref name="stateObject"/> parameter can be used to pass user-defined information to this callback or the <see cref="IAsyncResult"/>. The <see cref="IAsyncResult"/> /// also provides an event handle (<see cref="IAsyncResult.AsyncWaitHandle" />) that will be triggered when the operation is complete as well. /// </remarks> public IAsyncResult BeginWrite(byte[] buffer, int offset, int length, AsyncCallback userCallback, object stateObject) { CheckWriteParams(buffer, offset, length); USBAsyncResult result = new USBAsyncResult(userCallback, stateObject); try { _device.InternalDevice.WriteOverlapped(Interface.InterfaceIndex, _pipeInfo.PipeId, buffer, offset, length, result); } catch (API.APIException e) { if (result != null) result.Dispose(); throw new USBException("Failed to write to pipe.", e); } catch (Exception) { if (result != null) result.Dispose(); throw; } return result; }
/// <summary> /// Initiates an asynchronous control transfer over the default control endpoint. This method allows both IN and OUT direction transfers, depending /// on the highest bit of the <paramref name="requestType"/> parameter. Alternatively, <see cref="BeginControlIn(byte,byte,int,int,byte[],int,AsyncCallback,object)"/> and /// <see cref="BeginControlIn(byte,byte,int,int,byte[],int,AsyncCallback,object)"/> can be used for asynchronous control transfers in a specific direction, which is /// the recommended way because it prevents using the wrong direction accidentally. Use the BeginControlTransfer method when the direction is not /// known at compile time. </summary> /// <param name="requestType">The setup packet request type.</param> /// <param name="request">The setup packet device request.</param> /// <param name="value">The value member in the setup packet. Its meaning depends on the request. Value should be between zero and 65535 (0xFFFF).</param> /// <param name="index">The index member in the setup packet. Its meaning depends on the request. Index should be between zero and 65535 (0xFFFF).</param> /// <param name="buffer">The data to transfer in the data stage of the control. When the transfer is in the IN direction the data received will be /// written to this buffer. For an OUT direction transfer the contents of the buffer are written sent through the pipe. Note: This buffer is not allowed /// to change for the duration of the asynchronous operation.</param> /// <param name="length">Length of the data to transfer. Must be equal to or less than the length of <paramref name="buffer"/>. The setup packet's length member will be set to this length.</param> /// <param name="userCallback">An optional asynchronous callback, to be called when the control transfer is complete. Can be null if no callback is required.</param> /// <param name="stateObject">A user-provided object that distinguishes this particular asynchronous operation. Can be null if not required.</param> /// <returns>An <see cref="IAsyncResult"/> object repesenting the asynchronous control transfer, which could still be pending.</returns> /// <remarks>This method always completes immediately even if the operation is still pending. The <see cref="IAsyncResult"/> object returned represents the operation /// and must be passed to <see cref="EndControlTransfer"/> to retrieve the result of the operation. For every call to this method a matching call to /// <see cref="EndControlTransfer"/> must be made. When <paramref name="userCallback"/> specifies a callback function, this function will be called when the operation is completed. The optional /// <paramref name="stateObject"/> parameter can be used to pass user-defined information to this callback or the <see cref="IAsyncResult"/>. The <see cref="IAsyncResult"/> /// also provides an event handle (<see cref="IAsyncResult.AsyncWaitHandle" />) that will be triggered when the operation is complete as well. /// </remarks> public IAsyncResult BeginControlTransfer(byte requestType, byte request, int value, int index, byte[] buffer, int length, AsyncCallback userCallback, object stateObject) { // Parameters are int and not ushort because ushort is not CLS compliant. CheckNotDisposed(); CheckControlParams(value, index, buffer, length); USBAsyncResult result = new USBAsyncResult(userCallback, stateObject); try { _wuDevice.ControlTransferOverlapped(requestType, request, (ushort)value, (ushort)index, (ushort)length, buffer, result); } catch (API.APIException e) { if (result != null) result.Dispose(); throw new USBException("Asynchronous control transfer failed", e); } catch (Exception) { if (result != null) result.Dispose(); throw; } return result; }