Example #1
0
 private BthDevice GetConnection(L2CapDataPacket packet)
 {
     lock (_connected)
     {
         return((!_connected.Any() | !_connected.ContainsKey(packet.Handle)) ? null : _connected[packet.Handle]);
     }
 }
Example #2
0
        /// <summary>
        ///     Main task listening for incoming L2CAP data on the bulk pipe.
        /// </summary>
        /// <param name="o">Cancellation token to abort the tasks inner loop.</param>
        private void L2CapWorker(object o)
        {
            var token  = (CancellationToken)o;
            var buffer = new byte[512];

            var transfered = 0;

            Log.DebugFormat("-- Bluetooth  : L2CAP_Worker_Thread Starting (IN: {0:X2}, OUT: {1:X2})", BulkIn, BulkOut);

            // poll device buffer until cancellation requested
            while (!token.IsCancellationRequested)
            {
                try
                {
                    // communication channels use the bulk pipe
                    if (!ReadBulkPipe(buffer, buffer.Length, ref transfered) || transfered <= 0)
                    {
                        continue;
                    }

                    var packet = new L2CapDataPacket(buffer);

                    var connection = GetConnection(packet);
                    if (LmpMajor >= 6 && connection == null || LmpMajor < 6 && !AnyConnections())
                    {
                        Log.Info("Waiting 250ms for connection...");
                        Thread.Sleep(250);
                    }

                    if (connection == null && !_connectionPendingEvent.WaitOne(TimeSpan.FromSeconds(2)))
                    {
                        Log.WarnFormat("Couldn't get connection handle [{0:X2}, {1:X2}]", buffer[0], buffer[1]);
                        continue;
                    }

                    connection = GetConnection(packet);

                    if (connection == null)
                    {
                        continue;
                    }

                    if (connection.Model == DsModel.DS4)
                    {
                        ParseBufferDs4(connection, buffer, transfered);
                    }
                    else
                    {
                        ParseBufferDs3(connection, packet);
                    }
                }
                catch (Exception ex)
                {
                    Log.ErrorFormat("Unexpected error in L2CAP_Worker_Thread: {0}", ex);
                }
            }

            Log.Debug("-- Bluetooth  : L2CAP_Worker_Thread Exiting");
        }
Example #3
0
        /// <summary>
        ///     Main task listening for incoming L2CAP data on the bulk pipe.
        /// </summary>
        /// <param name="o">Cancellation token to abort the tasks inner loop.</param>
        private void L2CapWorker(object o)
        {
            var token  = (CancellationToken)o;
            var buffer = new byte[512];

            var transfered = 0;

            Log.InfoFormat("-- Bluetooth  : L2CAP_Worker_Thread Starting (IN: {0:X2}, OUT: {1:X2})", BulkIn, BulkOut);

            // poll device buffer until cancellation requested
            while (!token.IsCancellationRequested)
            {
                try
                {
                    // communication channels use the bulk pipe
                    if (ReadBulkPipe(buffer, buffer.Length, ref transfered) && transfered > 0)
                    {
                        // this prevents a race condition where the connection could be null
                        // TODO: causes a short hickup on all connections, improve
                        _waitForConnectionComplete.WaitOne();

                        var packet = new L2CapDataPacket(buffer);

                        var connection = GetConnection(packet);

                        if (connection == null)
                        {
                            Log.WarnFormat("Couldn't get connection handle [{0:X2}, {1:X2}]", buffer[0], buffer[1]);
                            continue;
                        }

                        if (connection.Model == DsModel.DS4)
                        {
                            ParseBufferDs4(connection, buffer, transfered);
                        }
                        else
                        {
                            ParseBufferDs3(connection, packet);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.ErrorFormat("Unexpected error in L2CAP_Worker_Thread: {0}", ex);
                }
            }

            Log.Info("-- Bluetooth  : L2CAP_Worker_Thread Exiting");
        }
Example #4
0
        /// <summary>
        ///     Main task listening for incoming L2CAP data on the bulk pipe.
        /// </summary>
        /// <param name="o">Cancellation token to abort the tasks inner loop.</param>
        private void L2CapWorker(object o)
        {
            var token = (CancellationToken) o;
            var buffer = new byte[512];

            var transfered = 0;

            Log.DebugFormat("-- Bluetooth  : L2CAP_Worker_Thread Starting (IN: {0:X2}, OUT: {1:X2})", BulkIn, BulkOut);

            // poll device buffer until cancellation requested
            while (!token.IsCancellationRequested)
            {
                try
                {
                    // communication channels use the bulk pipe
                    if (!ReadBulkPipe(buffer, buffer.Length, ref transfered) || transfered <= 0) continue;

                    var packet = new L2CapDataPacket(buffer);

                    var connection = GetConnection(packet);

                    if (connection == null && !_connectionPendingEvent.WaitOne(TimeSpan.FromSeconds(2)))
                    {
                        Log.WarnFormat("Couldn't get connection handle [{0:X2}, {1:X2}]", buffer[0], buffer[1]);
                        continue;
                    }

                    connection = GetConnection(packet);

                    if (connection == null) continue;

                    if (connection.Model == DsModel.DS4)
                    {
                        ParseBufferDs4(connection, buffer, transfered);
                    }
                    else
                    {
                        ParseBufferDs3(connection, packet);
                    }
                }
                catch (Exception ex)
                {
                    Log.ErrorFormat("Unexpected error in L2CAP_Worker_Thread: {0}", ex);
                }
            }

            Log.Debug("-- Bluetooth  : L2CAP_Worker_Thread Exiting");
        }
        /// <summary>
        ///     Parses an incoming DualShock 3 HID report.
        /// </summary>
        /// <param name="connection">The device handle the input buffer was received for.</param>
        /// <param name="packet">The L2CAP data packet.</param>
        private void ParseBufferDs3(BthDevice connection, L2CapDataPacket packet)
        {
            byte[] L2_DCID;
            byte[] L2_SCID;

            if (packet.IsControlChannel) // Control Channel
            {
                if (packet.IsValidSignallingCommandCode)
                {
                    var Event = packet.SignallingCommandCode;

                    switch (Event)
                    {
                            #region L2CAP_Command_Reject

                        case L2CAP.Code.L2CAP_Command_Reject:

                            Log.DebugFormat(">> {0}", Event);
                            break;

                            #endregion

                            #region L2CAP_Connection_Request

                        case L2CAP.Code.L2CAP_Connection_Request:

                            Log.DebugFormat(">> {0} with PSM [{1}] [CID: {2}]", Event,
                                packet.ProtocolServiceMultiplexer,
                                packet.ChannelId);

                            L2_SCID = packet.SourceChannelIdentifier;

                            // set HID command channel for current connection
                            L2_DCID = connection.SetConnectionType(packet.ProtocolServiceMultiplexer, L2_SCID);

                            // send response with connection pending
                            L2CAP_Connection_Response(connection.HciHandle.Bytes,
                                packet.ChannelId, L2_SCID, L2_DCID,
                                L2CAP.ConnectionResponseResult.ConnectionPending,
                                L2CAP.ConnectionResponseStatus.AuthorisationPending);

                            Log.DebugFormat("<< {0} [CID: {1}]", L2CAP.Code.L2CAP_Connection_Response,
                                packet.ChannelId);

                            // send response with connection successful
                            L2CAP_Connection_Response(connection.HciHandle.Bytes,
                                packet.ChannelId, L2_SCID, L2_DCID,
                                L2CAP.ConnectionResponseResult.ConnectionSuccessful);

                            Log.DebugFormat("<< {0} [CID: {1}]", L2CAP.Code.L2CAP_Connection_Response,
                                packet.ChannelId);

                            // send configuration request
                            L2CAP_Configuration_Request(connection.HciHandle.Bytes, _l2CapDataIdentifier++, L2_SCID);

                            Log.DebugFormat("<< {0} [CID: {1}]", L2CAP.Code.L2CAP_Configuration_Request,
                                _l2CapDataIdentifier - 1);
                            break;

                            #endregion

                            #region L2CAP_Connection_Response

                        case L2CAP.Code.L2CAP_Connection_Response:

                            Log.DebugFormat(">> {0} [Result: {1}] [CID: {2}]", Event, packet.Result, packet.ChannelId);

                            var result = packet.Result;

                            L2_SCID = packet.SourceChannelIdentifier;
                            Log.DebugFormat("-- L2_SCID = [{0:X2}, {1:X2}]", L2_SCID[0], L2_SCID[1]);

                            L2_DCID = packet.DestinationChannelIdentifier;
                            Log.DebugFormat("-- L2_DCID = [{0:X2}, {1:X2}]", L2_DCID[0], L2_DCID[1]);

                            // interpret result
                            switch ((L2CAP.ConnectionResponseResult) result)
                            {
                                case L2CAP.ConnectionResponseResult.ConnectionSuccessful:

                                    // destination channel identifier
                                    var DCID = packet.DestinationChannelIdentifierUInt16;
                                    Log.DebugFormat("-- DCID (shifted) = {0:X4}", DCID);

                                    // set HID service channel for current connection
                                    connection.SetConnectionType(L2CAP.PSM.HID_Service, L2_SCID[0], L2_SCID[1], DCID);

                                    // send configuration request
                                    L2CAP_Configuration_Request(connection.HciHandle.Bytes, _l2CapDataIdentifier++,
                                        L2_SCID);

                                    Log.DebugFormat("<< {0} [CID: {1}]",
                                        L2CAP.Code.L2CAP_Configuration_Request,
                                        packet.ChannelId);
                                    break;
                                case L2CAP.ConnectionResponseResult.ConnectionPending:

                                    Log.InfoFormat("-- Connection pending for pad {0}",
                                        connection.PadId.ToString().ToLower());
                                    break;
                                case L2CAP.ConnectionResponseResult.ConnectionRefusedPsmNotNupported:

                                    Log.ErrorFormat(
                                        "Requested Protocol Service Multiplexer not supported on device {0}",
                                        connection.Remote);
                                    break;
                                case L2CAP.ConnectionResponseResult.ConnectionRefusedSecurityBlock:

                                    Log.ErrorFormat("Connection refused for security reasons on device {0}",
                                        connection.Remote);
                                    break;
                                case L2CAP.ConnectionResponseResult.ConnectionRefusedNoResourcesAvailable:

                                    Log.ErrorFormat("Connection failed for device {0}: no resources available",
                                        connection.Remote);
                                    break;

                                default:
                                    Log.WarnFormat("Unknown result: {0}", result);
                                    break;
                            }

                            break;

                            #endregion

                            #region L2CAP_Configuration_Request

                        case L2CAP.Code.L2CAP_Configuration_Request:

                            Log.DebugFormat(">> {0} [CID: {1}]", Event, packet.ChannelId);

                            L2_SCID = connection.Get_SCID(packet.SourceChannelIdentifier);

                            L2CAP_Configuration_Response(connection.HciHandle.Bytes,
                                packet.ChannelId, L2_SCID);
                            Log.DebugFormat("<< {0} [CID: {1}]", L2CAP.Code.L2CAP_Configuration_Response,
                                packet.ChannelId);

                            if (connection.IsServiceStarted)
                            {
                                connection.CanStartHid = true;
                                connection.InitHidReport(packet.RawBytes);
                            }
                            break;

                            #endregion

                            #region L2CAP_Configuration_Response

                        case L2CAP.Code.L2CAP_Configuration_Response:

                            Log.DebugFormat(">> {0} [CID: {1}]", Event, packet.ChannelId);

                            Log.DebugFormat("-- MTU = {0}", packet.MaximumTransmissionUnit);

                            if (connection.CanStartService)
                            {
                                L2_DCID = L2CapDataPacket.UInt16ToBytes(BthConnection.Dcid++);

                                if (!connection.IsFake)
                                {
                                    L2CAP_Connection_Request(connection.HciHandle.Bytes, _l2CapDataIdentifier++, L2_DCID,
                                        L2CAP.PSM.HID_Service);
                                    Log.DebugFormat("<< {0} with PSM [{1}] [CID: {2}]",
                                        L2CAP.Code.L2CAP_Connection_Request,
                                        L2CAP.PSM.HID_Service,
                                        _l2CapDataIdentifier - 1);
                                }
                                else
                                {
                                    connection.SetConnectionType(L2CAP.PSM.HID_Service, L2_DCID);
                                    connection.CanStartService = false;
                                    OnInitialised(connection);
                                }
                            }
                            break;

                            #endregion

                            #region L2CAP_Disconnection_Request

                        case L2CAP.Code.L2CAP_Disconnection_Request:

                            Log.DebugFormat(">> {0} Handle [{1}]", Event, packet.SourceChannelIdentifier);

                            L2_SCID = packet.SourceChannelIdentifier;

                            L2CAP_Disconnection_Response(connection.HciHandle.Bytes,
                                packet.ChannelId, L2_SCID, L2_SCID);

                            Log.DebugFormat("<< {0}", L2CAP.Code.L2CAP_Disconnection_Response);
                            break;

                            #endregion

                            #region L2CAP_Disconnection_Response

                        case L2CAP.Code.L2CAP_Disconnection_Response:

                            Log.DebugFormat(">> {0}", Event);

                            if (connection.CanStartHid)
                            {
                                connection.IsServiceStarted = false;
                                OnInitialised(connection);
                            }
                            break;

                            #endregion

                            #region L2CAP_Echo_Request

                        case L2CAP.Code.L2CAP_Echo_Request:

                            Log.DebugFormat(">> {0}", Event);
                            break;

                            #endregion

                            #region L2CAP_Echo_Response

                        case L2CAP.Code.L2CAP_Echo_Response:

                            Log.DebugFormat(">> {0}", Event);
                            break;

                            #endregion

                            #region L2CAP_Information_Request

                        case L2CAP.Code.L2CAP_Information_Request:

                            Log.DebugFormat(">> {0}", Event);
                            break;

                            #endregion

                            #region L2CAP_Information_Response

                        case L2CAP.Code.L2CAP_Information_Response:

                            Log.DebugFormat(">> {0}", Event);
                            break;

                            #endregion
                    }
                }
            }
            else if (packet.IsHidInputReport)
            {
                // HID report received, parse content and extract gamepad data
                connection.ParseHidReport(packet.RawBytes);
            }
            else if (connection.InitHidReport(packet.RawBytes))
            {
                connection.CanStartHid = true;

                L2_DCID = connection.Get_DCID(L2CAP.PSM.HID_Service);
                L2_SCID = connection.Get_SCID(L2CAP.PSM.HID_Service);

                L2CAP_Disconnection_Request(connection.HciHandle.Bytes, _l2CapDataIdentifier++, L2_SCID, L2_DCID);

                Log.DebugFormat("<< {0}", L2CAP.Code.L2CAP_Disconnection_Request);
            }
        }
        /// <summary>
        ///     Main task listening for incoming L2CAP data on the bulk pipe.
        /// </summary>
        /// <param name="o">Cancellation token to abort the tasks inner loop.</param>
        private void L2CapWorker(object o)
        {
            var token = (CancellationToken) o;
            var buffer = new byte[512];

            var transfered = 0;

            Log.InfoFormat("-- Bluetooth  : L2CAP_Worker_Thread Starting (IN: {0:X2}, OUT: {1:X2})", BulkIn, BulkOut);

            // poll device buffer until cancellation requested
            while (!token.IsCancellationRequested)
            {
                try
                {
                    // communication channels use the bulk pipe
                    if (ReadBulkPipe(buffer, buffer.Length, ref transfered) && transfered > 0)
                    {
                        // this prevents a race condition where the connection could be null
                        // TODO: causes a short hickup on all connections, improve
                        _waitForConnectionComplete.WaitOne();

                        var packet = new L2CapDataPacket(buffer);

                        var connection = GetConnection(packet);

                        if (connection == null)
                        {
                            Log.WarnFormat("Couldn't get connection handle [{0:X2}, {1:X2}]", buffer[0], buffer[1]);
                            continue;
                        }

                        if (connection.Model == DsModel.DS4)
                        {
                            ParseBufferDs4(connection, buffer, transfered);
                        }
                        else
                        {
                            ParseBufferDs3(connection, packet);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.ErrorFormat("Unexpected error in L2CAP_Worker_Thread: {0}", ex);
                }
            }

            Log.Info("-- Bluetooth  : L2CAP_Worker_Thread Exiting");
        }
Example #7
0
        private BthDevice GetConnection(L2CapDataPacket packet)
        {
            var raw = packet.RawBytes;

            return(GetConnection(raw[0], raw[1]));
        }
Example #8
0
        /// <summary>
        ///     Parses an incoming DualShock 3 HID report.
        /// </summary>
        /// <param name="connection">The device handle the input buffer was received for.</param>
        /// <param name="packet">The L2CAP data packet.</param>
        private void ParseBufferDs3(BthDevice connection, L2CapDataPacket packet)
        {
            byte[] L2_DCID;
            byte[] L2_SCID;

            if (packet.IsControlChannel) // Control Channel
            {
                if (packet.IsValidSignallingCommandCode)
                {
                    var Event = packet.SignallingCommandCode;

                    switch (Event)
                    {
                        #region L2CAP_Command_Reject

                    case L2CAP.Code.L2CAP_Command_Reject:

                        Log.DebugFormat(">> {0}", Event);
                        break;

                        #endregion

                        #region L2CAP_Connection_Request

                    case L2CAP.Code.L2CAP_Connection_Request:

                        Log.DebugFormat(">> {0} with PSM [{1}] [CID: {2}]", Event,
                                        packet.ProtocolServiceMultiplexer,
                                        packet.ChannelId);

                        L2_SCID = packet.SourceChannelIdentifier;

                        // set HID command channel for current connection
                        L2_DCID = connection.SetConnectionType(packet.ProtocolServiceMultiplexer, L2_SCID);

                        // send response with connection pending
                        L2CAP_Connection_Response(connection.HciHandle.Bytes,
                                                  packet.ChannelId, L2_SCID, L2_DCID,
                                                  L2CAP.ConnectionResponseResult.ConnectionPending,
                                                  L2CAP.ConnectionResponseStatus.AuthorisationPending);

                        Log.DebugFormat("<< {0} [CID: {1}]", L2CAP.Code.L2CAP_Connection_Response,
                                        packet.ChannelId);

                        // send response with connection successful
                        L2CAP_Connection_Response(connection.HciHandle.Bytes,
                                                  packet.ChannelId, L2_SCID, L2_DCID,
                                                  L2CAP.ConnectionResponseResult.ConnectionSuccessful);

                        Log.DebugFormat("<< {0} [CID: {1}]", L2CAP.Code.L2CAP_Connection_Response,
                                        packet.ChannelId);

                        // send configuration request
                        L2CAP_Configuration_Request(connection.HciHandle.Bytes, _l2CapDataIdentifier++, L2_SCID);

                        Log.DebugFormat("<< {0} [CID: {1}]", L2CAP.Code.L2CAP_Configuration_Request,
                                        _l2CapDataIdentifier - 1);
                        break;

                        #endregion

                        #region L2CAP_Connection_Response

                    case L2CAP.Code.L2CAP_Connection_Response:

                        Log.DebugFormat(">> {0} [Result: {1}] [CID: {2}]", Event, packet.Result, packet.ChannelId);

                        var result = packet.Result;

                        L2_SCID = packet.SourceChannelIdentifier;
                        Log.DebugFormat("-- L2_SCID = [{0:X2}, {1:X2}]", L2_SCID[0], L2_SCID[1]);

                        L2_DCID = packet.DestinationChannelIdentifier;
                        Log.DebugFormat("-- L2_DCID = [{0:X2}, {1:X2}]", L2_DCID[0], L2_DCID[1]);

                        // interpret result
                        switch ((L2CAP.ConnectionResponseResult)result)
                        {
                        case L2CAP.ConnectionResponseResult.ConnectionSuccessful:

                            // destination channel identifier
                            var DCID = packet.DestinationChannelIdentifierUInt16;
                            Log.DebugFormat("-- DCID (shifted) = {0:X4}", DCID);

                            // set HID service channel for current connection
                            connection.SetConnectionType(L2CAP.PSM.HID_Service, L2_SCID[0], L2_SCID[1], DCID);

                            // send configuration request
                            L2CAP_Configuration_Request(connection.HciHandle.Bytes, _l2CapDataIdentifier++,
                                                        L2_SCID);

                            Log.DebugFormat("<< {0} [CID: {1}]",
                                            L2CAP.Code.L2CAP_Configuration_Request,
                                            packet.ChannelId);
                            break;

                        case L2CAP.ConnectionResponseResult.ConnectionPending:

                            Log.DebugFormat("-- Connection pending for pad {0}",
                                            connection.PadId.ToString().ToLower());
                            break;

                        case L2CAP.ConnectionResponseResult.ConnectionRefusedPsmNotNupported:

                            Log.ErrorFormat(
                                "Requested Protocol Service Multiplexer not supported on device {0}",
                                connection.HostAddress);
                            break;

                        case L2CAP.ConnectionResponseResult.ConnectionRefusedSecurityBlock:

                            Log.ErrorFormat("Connection refused for security reasons on device {0}",
                                            connection.HostAddress);
                            break;

                        case L2CAP.ConnectionResponseResult.ConnectionRefusedNoResourcesAvailable:

                            Log.ErrorFormat("Connection failed for device {0}: no resources available",
                                            connection.HostAddress);
                            break;

                        default:
                            Log.WarnFormat("Unknown result: {0}", result);
                            break;
                        }

                        break;

                        #endregion

                        #region L2CAP_Configuration_Request

                    case L2CAP.Code.L2CAP_Configuration_Request:

                        Log.DebugFormat(">> {0} [CID: {1}]", Event, packet.ChannelId);

                        L2_SCID = connection.Get_SCID(packet.SourceChannelIdentifier);

                        L2CAP_Configuration_Response(connection.HciHandle.Bytes,
                                                     packet.ChannelId, L2_SCID);
                        Log.DebugFormat("<< {0} [CID: {1}]", L2CAP.Code.L2CAP_Configuration_Response,
                                        packet.ChannelId);

                        if (connection.IsServiceStarted)
                        {
                            connection.CanStartHid = true;
                            connection.InitHidReport(packet.RawBytes);
                        }
                        break;

                        #endregion

                        #region L2CAP_Configuration_Response

                    case L2CAP.Code.L2CAP_Configuration_Response:

                        Log.DebugFormat(">> {0} [CID: {1}]", Event, packet.ChannelId);

                        Log.DebugFormat("-- MTU = {0}", packet.MaximumTransmissionUnit);

                        if (connection.CanStartService)
                        {
                            L2_DCID = L2CapDataPacket.UInt16ToBytes(BthConnection.Dcid++);

                            if (!connection.IsFake)
                            {
                                L2CAP_Connection_Request(connection.HciHandle.Bytes, _l2CapDataIdentifier++, L2_DCID,
                                                         L2CAP.PSM.HID_Service);
                                Log.DebugFormat("<< {0} with PSM [{1}] [CID: {2}]",
                                                L2CAP.Code.L2CAP_Connection_Request,
                                                L2CAP.PSM.HID_Service,
                                                _l2CapDataIdentifier - 1);
                            }
                            else
                            {
                                connection.SetConnectionType(L2CAP.PSM.HID_Service, L2_DCID);
                                connection.CanStartService = false;
                                OnInitialised(connection);
                            }
                        }
                        break;

                        #endregion

                        #region L2CAP_Disconnection_Request

                    case L2CAP.Code.L2CAP_Disconnection_Request:

                        Log.DebugFormat(">> {0} Handle [{1}]", Event, packet.SourceChannelIdentifier);

                        L2_SCID = packet.SourceChannelIdentifier;

                        L2CAP_Disconnection_Response(connection.HciHandle.Bytes,
                                                     packet.ChannelId, L2_SCID, L2_SCID);

                        Log.DebugFormat("<< {0}", L2CAP.Code.L2CAP_Disconnection_Response);
                        break;

                        #endregion

                        #region L2CAP_Disconnection_Response

                    case L2CAP.Code.L2CAP_Disconnection_Response:

                        Log.DebugFormat(">> {0}", Event);

                        if (connection.CanStartHid)
                        {
                            connection.IsServiceStarted = false;
                            OnInitialised(connection);
                        }
                        break;

                        #endregion

                        #region L2CAP_Echo_Request

                    case L2CAP.Code.L2CAP_Echo_Request:

                        Log.DebugFormat(">> {0}", Event);
                        break;

                        #endregion

                        #region L2CAP_Echo_Response

                    case L2CAP.Code.L2CAP_Echo_Response:

                        Log.DebugFormat(">> {0}", Event);
                        break;

                        #endregion

                        #region L2CAP_Information_Request

                    case L2CAP.Code.L2CAP_Information_Request:

                        Log.DebugFormat(">> {0}", Event);
                        break;

                        #endregion

                        #region L2CAP_Information_Response

                    case L2CAP.Code.L2CAP_Information_Response:

                        Log.DebugFormat(">> {0}", Event);
                        break;

                        #endregion
                    }
                }
            }
            else if (packet.IsHidInputReport)
            {
                // HID report received, parse content and extract gamepad data
                connection.ParseHidReport(packet.RawBytes);
            }
            else if (connection.InitHidReport(packet.RawBytes))
            {
                connection.CanStartHid = true;

                L2_DCID = connection.Get_DCID(L2CAP.PSM.HID_Service);
                L2_SCID = connection.Get_SCID(L2CAP.PSM.HID_Service);

                L2CAP_Disconnection_Request(connection.HciHandle.Bytes, _l2CapDataIdentifier++, L2_SCID, L2_DCID);

                Log.DebugFormat("<< {0}", L2CAP.Code.L2CAP_Disconnection_Request);
            }
        }