private ErrorCode WriteReadBytesCommand(UsbEndpointBase endpoint)
        {
            UsbPacket   usbPacket = CreateReadBytesCommandPacket();
            UsbTransfer transfer  = null;

            try
            {
                ErrorCode errorCode = endpoint.SubmitAsyncTransfer(usbPacket, 0, (int)(_usbPacketSizeWithoutData + usbPacket.uiDataLen), _transferTimeoutInMilliseconds, out transfer);

                if (errorCode != ErrorCode.None)
                {
                    return(errorCode);
                }

                WaitHandle.WaitAll(new[] { transfer.AsyncWaitHandle }, _waitTimeout, false);

                if (!transfer.IsCompleted)
                {
                    transfer.Cancel();
                }

                int bytesTransferred;

                return(transfer.Wait(out bytesTransferred));
            }
            finally
            {
                transfer?.Dispose();
            }
        }
        private unsafe ReadUsbPacketResult ReadUsbPacket(UsbEndpointBase endpoint)
        {
            UsbTransfer transfer = null;

            try
            {
                var       usbPacketBuffer = new byte[_usbPacketSize];
                ErrorCode errorCode       = endpoint.SubmitAsyncTransfer(usbPacketBuffer, 0, usbPacketBuffer.Length, _transferTimeoutInMilliseconds, out transfer);

                if (errorCode != ErrorCode.None)
                {
                    _error.OnNext(errorCode);

                    return(new ReadUsbPacketResult(errorCode));
                }

                WaitHandle.WaitAll(new[] { transfer.AsyncWaitHandle }, _waitTimeout, false);

                if (!transfer.IsCompleted)
                {
                    transfer.Cancel();
                }

                int bytesTransferred;

                errorCode = transfer.Wait(out bytesTransferred);

                if (bytesTransferred == 0)
                {
                    return(new ReadUsbPacketResult(errorCode));
                }

                GCHandle gcHandle  = GCHandle.Alloc(usbPacketBuffer, GCHandleType.Pinned);
                var      usbPacket = Marshal.PtrToStructure <UsbPacket>(gcHandle.AddrOfPinnedObject());

                if (usbPacket.uiSeqNum != _sequenceNumber)
                {
                    _incorrectSequenceNumberReceived.OnNext(new IncorrectSequenceNumberReceivedArgs(_sequenceNumber, usbPacket.uiSeqNum));

                    return(new ReadUsbPacketResult(errorCode));
                }

                _sequenceNumber++;

                if (bytesTransferred < _usbPacketSizeWithoutData)
                {
                    _incorrectNumberOfBytesReceived.OnNext(bytesTransferred);

                    return(new ReadUsbPacketResult(errorCode));
                }
                if (errorCode != ErrorCode.None)
                {
                    return(new ReadUsbPacketResult(errorCode));
                }
                if (usbPacket.uiDataLen == 0)
                {
                    _noData.OnNext(Unit.Default);

                    return(new ReadUsbPacketResult(errorCode));
                }

                _fileOffset += usbPacket.uiDataLen;

                var strokes    = new List <Stroke>();
                var dataBuffer = new byte[usbPacket.uiDataLen];
                Marshal.Copy(new IntPtr(usbPacket.pData), dataBuffer, 0, dataBuffer.Length);

                for (var i = 0; i < dataBuffer.Length; i += 8)
                {
                    strokes.Add(new Stroke(dataBuffer[i], dataBuffer[i + 1], dataBuffer[i + 2], dataBuffer[i + 3]));
                }

                return(new ReadUsbPacketResult(errorCode, strokes));
            }
            finally
            {
                transfer?.Dispose();
            }
        }