public void OnDescriptorRequested(DescriptorRequestedEventArgs e)
        {
            switch ((e.wValue >> 8) & 0xFF)
              {
            case 0x01: //Device descriptor
              {
            e.DescriptorData = new byte[] { 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x03, 0x04, 0x01, 0x60, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01 };
            break;
              }
            case 0x02: //Configuration descriptor
              {
            e.DescriptorData = new byte[] { 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xA0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x00,
                                    0x07, 0x05, 0x83, 0x03, 0x0A, 0x00, 0x01, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00 };

            break;
              }
            default:
              {
            //Uh?
            break;
              }
              }
        }
        private void _reader_DataReceived(object sender, EndpointDataEventArgs e)
        {
            char cmd = (char)e.Buffer[2];

            switch (cmd)
            {
            case 'E':
            {
                Logger.WriteLine("Raw: Received error/busy response: " +
                                 BitConverter.ToString(e.Buffer, 0, e.Count), Logger.LoggingLevel.VeryVerbose);

                //Need to find the first (oldest) message matching this command and mark it as ready to send
                //HACK: This really should use a sequence ID or something, but this works well enough
                lock (_messages)
                {
                    for (int i = 0; i < _messages.Count; i++)
                    {
                        if (_messages[i].Data[2] == e.Buffer[4])
                        {
                            _messages[i].Status = MessageStatus.ReadyToSend;
                            break;
                        }
                    }
                }

                break;
            }

            case 'A':
            {
                Logger.WriteLine("Raw: Received acknowledgement response: " +
                                 BitConverter.ToString(e.Buffer, 0, e.Count), Logger.LoggingLevel.VeryVerbose);

                //Need to find the first (oldest) message matching this command and delete it
                //HACK: This really should use a sequence ID or something, but this works well enough
                //  There's also the potential for this to fill up all available memory...don't care for now...
                lock (_messages)
                {
                    for (int i = 0; i < _messages.Count; i++)
                    {
                        if (_messages[i].Data[2] == e.Buffer[3])
                        {
                            _messages.RemoveAt(i);
                            break;
                        }
                    }
                }

                break;
            }

            case 'U':
            {
                Logger.WriteLine("Raw: Received control request: " +
                                 BitConverter.ToString(e.Buffer, 0, e.Count), Logger.LoggingLevel.Verbose);

                //Received control request
                int bmRequestType = e.Buffer[3];
                int bRequest      = e.Buffer[4];
                int wValue        = e.Buffer[5] | (e.Buffer[6] << 8);
                int wIndex        = e.Buffer[7] | (e.Buffer[8] << 8);
                int wLength       = e.Buffer[9] | (e.Buffer[10] << 8);
                var attachedData  = new byte[wLength];
                Array.Copy(e.Buffer, 11, attachedData, 0, wLength);

                var arg = new ControlRequestEventArgs(bmRequestType, bRequest, wValue, wIndex, wLength, attachedData);

                _currentDevice.OnControlRequestReceived(arg);

                if (arg.CanIgnore && arg.Ignore)
                {
                    _Write(new byte[] { (byte)'U', 0x00 });
                }
                else if (arg.Stall)
                {
                    _Write(new byte[] { (byte)'U', 0x02 });
                }
                else
                {
                    var ret = new byte[2 + (arg.ReturnData != null ? arg.ReturnData.Length : 0)];

                    ret[0] = (byte)'U';
                    ret[1] = 0x01;
                    if (arg.ReturnData != null)
                    {
                        Array.Copy(arg.ReturnData, 0, ret, 2, arg.ReturnData.Length);
                    }

                    _Write(ret);
                }

                break;
            }

            case 'F':
            {
                //If e.Buffer[3] is non-zero, USB is connected, otherwise disconnected. Apparently.
                Logger.WriteLine("Raw: Received event: " +
                                 BitConverter.ToString(e.Buffer, 0, e.Count), Logger.LoggingLevel.Verbose);

                break;
            }

            case 'D':
            {
                Logger.WriteLine("Raw: Received descriptor request: " +
                                 BitConverter.ToString(e.Buffer, 0, e.Count), Logger.LoggingLevel.Verbose);

                //Received descriptor request
                int wValue = e.Buffer[3] | (e.Buffer[4] << 8);
                int wIndex = e.Buffer[5] | (e.Buffer[6] << 8);

                var arg = new DescriptorRequestedEventArgs(wValue, wIndex);

                _currentDevice.OnDescriptorRequested(arg);

                //HACK: We tacked on the endpoint configuration stuff to the device descriptor,
                //  so if that's what we're returning, generate and tack it on here
                byte[] ret;
                if (((wValue >> 8) & 0xFF) == 0x01)
                {
                    ret    = new byte[1 + arg.DescriptorData.Length + 1 + (_currentDevice.Endpoints.Count * 4)];
                    ret[0] = (byte)'D';
                    Array.Copy(arg.DescriptorData, 0, ret, 1, arg.DescriptorData.Length);

                    ret[1 + arg.DescriptorData.Length] = (byte)_currentDevice.Endpoints.Count;
                    for (int i = 0; i < _currentDevice.Endpoints.Count; i++)
                    {
                        ret[1 + arg.DescriptorData.Length + 1 + (i * 4) + 0] =
                            (byte)(_currentDevice.Endpoints[i].Endpoint | (byte)_currentDevice.Endpoints[i].Direction);
                        ret[1 + arg.DescriptorData.Length + 1 + (i * 4) + 1] = (byte)_currentDevice.Endpoints[i].Type;
                        ret[1 + arg.DescriptorData.Length + 1 + (i * 4) + 2] = (byte)(_currentDevice.Endpoints[i].MaximumPacketSize & 0xFF);
                        ret[1 + arg.DescriptorData.Length + 1 + (i * 4) + 3] = (byte)((_currentDevice.Endpoints[i].MaximumPacketSize >> 8) & 0xFF);
                    }
                }
                else
                {
                    ret    = new byte[1 + (arg.DescriptorData != null ? arg.DescriptorData.Length : 0)];
                    ret[0] = (byte)'D';
                    if (arg.DescriptorData != null)
                    {
                        Array.Copy(arg.DescriptorData, 0, ret, 1, arg.DescriptorData.Length);
                    }
                }

                _Write(ret);

                break;
            }

            case 'I':
            {
                Logger.WriteLine("Raw: Received incoming data: " +
                                 BitConverter.ToString(e.Buffer, 0, e.Count), Logger.LoggingLevel.Verbose);

                //Incoming endpoint data received
                int count = (e.Buffer[0] | (e.Buffer[1] << 8));
                if (count > 0)
                {
                    var data = new byte[count - 2];
                    Array.Copy(e.Buffer, 4, data, 0, data.Length);
                    _currentDevice.OnIncomingDataReceived(new IncomingDataEventArgs(e.Buffer[3], data));
                }

                break;
            }

            default:
            {
                Logger.WriteLine("Raw: Received unknown data: " +
                                 BitConverter.ToString(e.Buffer, 0, e.Count), Logger.LoggingLevel.Verbose);
                break;
            }
            }
        }
        private void _reader_DataReceived(object sender, EndpointDataEventArgs e)
        {
            char cmd = (char)e.Buffer[2];

              switch (cmd)
              {
            case 'E':
              {
            Logger.WriteLine("Raw: Received error/busy response: " +
              BitConverter.ToString(e.Buffer, 0, e.Count), Logger.LoggingLevel.VeryVerbose);

            //Need to find the first (oldest) message matching this command and mark it as ready to send
            //HACK: This really should use a sequence ID or something, but this works well enough
            lock (_messages)
            {
              for (int i = 0; i < _messages.Count; i++)
              {
                if (_messages[i].Data[2] == e.Buffer[4])
                {
                  _messages[i].Status = MessageStatus.ReadyToSend;
                  break;
                }
              }
            }

            break;
              }
            case 'A':
              {
            Logger.WriteLine("Raw: Received acknowledgement response: " +
              BitConverter.ToString(e.Buffer, 0, e.Count), Logger.LoggingLevel.VeryVerbose);

            //Need to find the first (oldest) message matching this command and delete it
            //HACK: This really should use a sequence ID or something, but this works well enough
            //  There's also the potential for this to fill up all available memory...don't care for now...
            lock (_messages)
            {
              for (int i = 0; i < _messages.Count; i++)
              {
                if (_messages[i].Data[2] == e.Buffer[3])
                {
                  _messages.RemoveAt(i);
                  break;
                }
              }
            }

            break;
              }
            case 'U':
              {
            Logger.WriteLine("Raw: Received control request: " +
              BitConverter.ToString(e.Buffer, 0, e.Count), Logger.LoggingLevel.Verbose);

            //Received control request
            int bmRequestType = e.Buffer[3];
            int bRequest = e.Buffer[4];
            int wValue = e.Buffer[5] | (e.Buffer[6] << 8);
            int wIndex = e.Buffer[7] | (e.Buffer[8] << 8);
            int wLength = e.Buffer[9] | (e.Buffer[10] << 8);
            var attachedData = new byte[wLength];
            Array.Copy(e.Buffer, 11, attachedData, 0, wLength);

            var arg = new ControlRequestEventArgs(bmRequestType, bRequest, wValue, wIndex, wLength, attachedData);

            _currentDevice.OnControlRequestReceived(arg);

            if (arg.CanIgnore && arg.Ignore)
            {
              _Write(new byte[] { (byte)'U', 0x00 });
            }
            else if (arg.Stall)
            {
              _Write(new byte[] { (byte)'U', 0x02 });
            }
            else
            {
              var ret = new byte[2 + (arg.ReturnData != null ? arg.ReturnData.Length : 0)];

              ret[0] = (byte)'U';
              ret[1] = 0x01;
              if (arg.ReturnData != null)
                Array.Copy(arg.ReturnData, 0, ret, 2, arg.ReturnData.Length);

              _Write(ret);
            }

            break;
              }
            case 'F':
              {
            //If e.Buffer[3] is non-zero, USB is connected, otherwise disconnected. Apparently.
            Logger.WriteLine("Raw: Received event: " +
              BitConverter.ToString(e.Buffer, 0, e.Count), Logger.LoggingLevel.Verbose);

            break;
              }
            case 'D':
              {
            Logger.WriteLine("Raw: Received descriptor request: " +
              BitConverter.ToString(e.Buffer, 0, e.Count), Logger.LoggingLevel.Verbose);

            //Received descriptor request
            int wValue = e.Buffer[3] | (e.Buffer[4] << 8);
            int wIndex = e.Buffer[5] | (e.Buffer[6] << 8);

            var arg = new DescriptorRequestedEventArgs(wValue, wIndex);

            _currentDevice.OnDescriptorRequested(arg);

            //HACK: We tacked on the endpoint configuration stuff to the device descriptor,
            //  so if that's what we're returning, generate and tack it on here
            byte[] ret;
            if (((wValue >> 8) & 0xFF) == 0x01)
            {
              ret = new byte[1 + arg.DescriptorData.Length + 1 + (_currentDevice.Endpoints.Count * 4)];
              ret[0] = (byte)'D';
              Array.Copy(arg.DescriptorData, 0, ret, 1, arg.DescriptorData.Length);

              ret[1 + arg.DescriptorData.Length] = (byte)_currentDevice.Endpoints.Count;
              for (int i = 0; i < _currentDevice.Endpoints.Count; i++)
              {
                ret[1 + arg.DescriptorData.Length + 1 + (i * 4) + 0] =
                  (byte)(_currentDevice.Endpoints[i].Endpoint | (byte)_currentDevice.Endpoints[i].Direction);
                ret[1 + arg.DescriptorData.Length + 1 + (i * 4) + 1] = (byte)_currentDevice.Endpoints[i].Type;
                ret[1 + arg.DescriptorData.Length + 1 + (i * 4) + 2] = (byte)(_currentDevice.Endpoints[i].MaximumPacketSize & 0xFF);
                ret[1 + arg.DescriptorData.Length + 1 + (i * 4) + 3] = (byte)((_currentDevice.Endpoints[i].MaximumPacketSize >> 8) & 0xFF);
              }
            }
            else
            {
              ret = new byte[1 + (arg.DescriptorData != null ? arg.DescriptorData.Length : 0)];
              ret[0] = (byte)'D';
              if (arg.DescriptorData != null)
                Array.Copy(arg.DescriptorData, 0, ret, 1, arg.DescriptorData.Length);
            }

            _Write(ret);

            break;
              }
            case 'I':
              {
            Logger.WriteLine("Raw: Received incoming data: " +
              BitConverter.ToString(e.Buffer, 0, e.Count), Logger.LoggingLevel.Verbose);

            //Incoming endpoint data received
            int count = (e.Buffer[0] | (e.Buffer[1] << 8));
            if (count > 0)
            {
              var data = new byte[count - 2];
              Array.Copy(e.Buffer, 4, data, 0, data.Length);
              _currentDevice.OnIncomingDataReceived(new IncomingDataEventArgs(e.Buffer[3], data));
            }

            break;
              }
            default:
              {
            Logger.WriteLine("Raw: Received unknown data: " +
              BitConverter.ToString(e.Buffer, 0, e.Count), Logger.LoggingLevel.Verbose);
            break;
              }
              }
        }