/// <summary> /// Parses an incoming DualShock 4 HID report . /// </summary> /// <param name="connection">The device handle the input buffer was received for.</param> /// <param name="buffer">The HID report in bytes.</param> /// <param name="transfered">The transfered bytes count.</param> private void ParseBufferDs4(BthDevice connection, byte[] buffer, int transfered) { byte[] L2_DCID, L2_SCID; if (buffer[6] == 0x01 && buffer[7] == 0x00) // Control Channel { if (Enum.IsDefined(typeof(L2CAP.Code), buffer[8])) { var Event = (L2CAP.Code)buffer[8]; switch (Event) { case L2CAP.Code.L2CAP_Command_Reject: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); break; case L2CAP.Code.L2CAP_Connection_Request: Log.DebugFormat(">> {0} [{1:X2}] PSM [{2:X2}]", Event, buffer[8], buffer[12]); L2_SCID = new byte[2] { buffer[14], buffer[15] }; L2_DCID = connection.SetConnectionType((L2CAP.PSM)buffer[12], L2_SCID); if (L2CAP.PSM.HID_Interrupt == (L2CAP.PSM)buffer[12]) { connection.IsStarted = true; } L2CAP_Connection_Response(connection.HciHandle.Bytes, buffer[9], L2_SCID, L2_DCID, 0x00); Log.DebugFormat("<< {0} [{1:X2}]", L2CAP.Code.L2CAP_Connection_Response, (byte)L2CAP.Code.L2CAP_Connection_Response); L2CAP_Configuration_Request(connection.HciHandle.Bytes, _hidReportId++, L2_SCID); Log.DebugFormat("<< {0} [{1:X2}]", L2CAP.Code.L2CAP_Configuration_Request, (byte)L2CAP.Code.L2CAP_Configuration_Request); break; case L2CAP.Code.L2CAP_Connection_Response: Log.DebugFormat(">> {0} [{1:X2}] [{2:X2}]", Event, buffer[8], buffer[16]); break; case L2CAP.Code.L2CAP_Configuration_Request: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); L2_SCID = connection.Get_SCID(buffer[12], buffer[13]); L2CAP_Configuration_Response(connection.HciHandle.Bytes, buffer[9], L2_SCID); Log.DebugFormat("<< {0} [{1:X2}]", L2CAP.Code.L2CAP_Configuration_Response, (byte)L2CAP.Code.L2CAP_Configuration_Response); if (connection.IsServiceStarted) { connection.CanStartHid = true; } break; case L2CAP.Code.L2CAP_Configuration_Response: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); if (connection.IsStarted) { OnInitialised(connection); } break; case L2CAP.Code.L2CAP_Disconnection_Request: Log.DebugFormat(">> {0} [{1:X2}] Handle [{2:X2}{3:X2}]", Event, buffer[8], buffer[15], buffer[14]); L2_SCID = new byte[2] { buffer[14], buffer[15] }; L2CAP_Disconnection_Response(connection.HciHandle.Bytes, buffer[9], L2_SCID, L2_SCID); Log.DebugFormat("<< {0} [{1:X2}]", L2CAP.Code.L2CAP_Disconnection_Response, (byte)L2CAP.Code.L2CAP_Disconnection_Response); break; case L2CAP.Code.L2CAP_Disconnection_Response: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); break; case L2CAP.Code.L2CAP_Echo_Request: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); break; case L2CAP.Code.L2CAP_Echo_Response: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); break; case L2CAP.Code.L2CAP_Information_Request: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); break; case L2CAP.Code.L2CAP_Information_Response: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); break; } } } else if (buffer[8] == 0xA1 && buffer[9] == 0x11 && transfered == 87) { // HID report received, parse content and extract gamepad data connection.ParseHidReport(buffer); } else if (connection.InitHidReport(buffer)) { connection.CanStartHid = true; } }
/// <summary> /// Parses an incoming DualShock 3 HID report . /// </summary> /// <param name="connection">The device handle the input buffer was received for.</param> /// <param name="buffer">The HID report in bytes.</param> /// <param name="transfered">The transfered bytes count.</param> private void ParseBufferDs3(BthDevice connection, byte[] buffer, int transfered) { byte[] L2_DCID; byte[] L2_SCID; if (buffer[6] == 0x01 && buffer[7] == 0x00) // Control Channel { if (Enum.IsDefined(typeof (L2CAP.Code), buffer[8])) { var Event = (L2CAP.Code) buffer[8]; switch (Event) { case L2CAP.Code.L2CAP_Command_Reject: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); break; case L2CAP.Code.L2CAP_Connection_Request: Log.DebugFormat(">> {0} [{1:X2}] PSM [{2:X2}]", Event, buffer[8], buffer[12]); L2_SCID = new byte[2] {buffer[14], buffer[15]}; L2_DCID = connection.SetConnectionType((L2CAP.PSM) buffer[12], L2_SCID); L2CAP_Connection_Response(connection.HciHandle.Bytes, buffer[9], L2_SCID, L2_DCID, 0x00); Log.DebugFormat("<< {0} [{1:X2}]", L2CAP.Code.L2CAP_Connection_Response, (byte) L2CAP.Code.L2CAP_Connection_Response); L2CAP_Configuration_Request(connection.HciHandle.Bytes, _hidReportId++, L2_SCID); Log.DebugFormat("<< {0} [{1:X2}]", L2CAP.Code.L2CAP_Configuration_Request, (byte) L2CAP.Code.L2CAP_Configuration_Request); break; case L2CAP.Code.L2CAP_Connection_Response: Log.DebugFormat(">> {0} [{1:X2}] [{2:X2}]", Event, buffer[8], buffer[16]); if (buffer[16] == 0) // Success { L2_SCID = new byte[2] {buffer[12], buffer[13]}; L2_DCID = new byte[2] {buffer[14], buffer[15]}; var DCID = (ushort) (buffer[15] << 8 | buffer[14]); connection.SetConnectionType(L2CAP.PSM.HID_Service, L2_SCID[0], L2_SCID[1], DCID); L2CAP_Configuration_Request(connection.HciHandle.Bytes, _hidReportId++, L2_SCID); Log.DebugFormat("<< {0} [{1:X2}]", L2CAP.Code.L2CAP_Configuration_Request, (byte) L2CAP.Code.L2CAP_Configuration_Request); } break; case L2CAP.Code.L2CAP_Configuration_Request: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); L2_SCID = connection.Get_SCID(buffer[12], buffer[13]); L2CAP_Configuration_Response(connection.HciHandle.Bytes, buffer[9], L2_SCID); Log.DebugFormat("<< {0} [{1:X2}]", L2CAP.Code.L2CAP_Configuration_Response, (byte) L2CAP.Code.L2CAP_Configuration_Response); if (connection.IsServiceStarted) { connection.CanStartHid = true; connection.InitHidReport(buffer); } break; case L2CAP.Code.L2CAP_Configuration_Response: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); if (connection.CanStartService) { if (connection.ServiceByPass) { Log.DebugFormat(">> ServiceByPass [{0} - {1}]", connection.Local, connection.RemoteName); connection.CanStartService = false; OnInitialised(connection); } else { var DCID = BthConnection.Dcid++; Log.DebugFormat("DCID = {0}", DCID); L2_DCID = new byte[2] {(byte) ((DCID >> 0) & 0xFF), (byte) ((DCID >> 8) & 0xFF)}; if (!connection.IsFake) { L2CAP_Connection_Request(connection.HciHandle.Bytes, _hidReportId++, L2_DCID, L2CAP.PSM.HID_Service); Log.DebugFormat("<< {0} [{1:X2}] PSM [{2:X2}]", L2CAP.Code.L2CAP_Connection_Request, (byte) L2CAP.Code.L2CAP_Connection_Request, (byte) L2CAP.PSM.HID_Service); } else { connection.CanStartService = false; OnInitialised(connection); } } } break; case L2CAP.Code.L2CAP_Disconnection_Request: Log.DebugFormat(">> {0} [{1:X2}] Handle [{2:X2}{3:X2}]", Event, buffer[8], buffer[15], buffer[14]); L2_SCID = new byte[2] {buffer[14], buffer[15]}; L2CAP_Disconnection_Response(connection.HciHandle.Bytes, buffer[9], L2_SCID, L2_SCID); Log.DebugFormat("<< {0} [{1:X2}]", L2CAP.Code.L2CAP_Disconnection_Response, (byte) L2CAP.Code.L2CAP_Disconnection_Response); break; case L2CAP.Code.L2CAP_Disconnection_Response: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); if (connection.CanStartHid) { connection.IsServiceStarted = false; OnInitialised(connection); } break; case L2CAP.Code.L2CAP_Echo_Request: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); break; case L2CAP.Code.L2CAP_Echo_Response: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); break; case L2CAP.Code.L2CAP_Information_Request: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); break; case L2CAP.Code.L2CAP_Information_Response: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); break; } } } else if (buffer[8] == 0xA1 && buffer[9] == 0x01 && transfered == 58) { // HID report received, parse content and extract gamepad data connection.ParseHidReport(buffer); } else if (connection.InitHidReport(buffer)) { 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, _hidReportId++, L2_SCID, L2_DCID); Log.DebugFormat("<< {0} [{1:X2}]", L2CAP.Code.L2CAP_Disconnection_Request, (byte) L2CAP.Code.L2CAP_Disconnection_Request); } }
/// <summary> /// Parses an incoming DualShock 4 HID report. /// </summary> /// <param name="connection">The device handle the input buffer was received for.</param> /// <param name="buffer">The HID report in bytes.</param> /// <param name="transfered">The transfered bytes count.</param> private void ParseBufferDs4(BthDevice connection, byte[] buffer, int transfered) { byte[] L2_DCID, L2_SCID; if (buffer[6] == 0x01 && buffer[7] == 0x00) // Control Channel { if (Enum.IsDefined(typeof(L2CAP.Code), buffer[8])) { var Event = (L2CAP.Code)buffer[8]; switch (Event) { #region L2CAP_Command_Reject case L2CAP.Code.L2CAP_Command_Reject: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); break; #endregion #region L2CAP_Connection_Request case L2CAP.Code.L2CAP_Connection_Request: Log.DebugFormat(">> {0} [{1:X2}] PSM [{2:X2}]", Event, buffer[8], buffer[12]); L2_SCID = new byte[2] { buffer[14], buffer[15] }; L2_DCID = connection.SetConnectionType((L2CAP.PSM)buffer[12], L2_SCID); if (L2CAP.PSM.HID_Interrupt == (L2CAP.PSM)buffer[12]) { connection.IsStarted = true; } L2CAP_Connection_Response(connection.HciHandle.Bytes, buffer[9], L2_SCID, L2_DCID, L2CAP.ConnectionResponseResult.ConnectionSuccessful); Log.DebugFormat("<< {0} [{1:X2}]", L2CAP.Code.L2CAP_Connection_Response, (byte)L2CAP.Code.L2CAP_Connection_Response); L2CAP_Configuration_Request(connection.HciHandle.Bytes, _l2CapDataIdentifier++, L2_SCID); Log.DebugFormat("<< {0} [{1:X2}]", L2CAP.Code.L2CAP_Configuration_Request, (byte)L2CAP.Code.L2CAP_Configuration_Request); break; #endregion #region L2CAP_Connection_Response case L2CAP.Code.L2CAP_Connection_Response: Log.DebugFormat(">> {0} [{1:X2}] [{2:X2}]", Event, buffer[8], buffer[16]); break; #endregion #region L2CAP_Configuration_Request case L2CAP.Code.L2CAP_Configuration_Request: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); L2_SCID = connection.Get_SCID(buffer[12], buffer[13]); L2CAP_Configuration_Response(connection.HciHandle.Bytes, buffer[9], L2_SCID); Log.DebugFormat("<< {0} [{1:X2}]", L2CAP.Code.L2CAP_Configuration_Response, (byte)L2CAP.Code.L2CAP_Configuration_Response); if (connection.IsServiceStarted) { connection.CanStartHid = true; } break; #endregion #region L2CAP_Configuration_Response case L2CAP.Code.L2CAP_Configuration_Response: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); if (connection.IsStarted) { OnInitialised(connection); } break; #endregion #region L2CAP_Disconnection_Request case L2CAP.Code.L2CAP_Disconnection_Request: Log.DebugFormat(">> {0} [{1:X2}] Handle [{2:X2}{3:X2}]", Event, buffer[8], buffer[15], buffer[14]); L2_SCID = new byte[2] { buffer[14], buffer[15] }; L2CAP_Disconnection_Response(connection.HciHandle.Bytes, buffer[9], L2_SCID, L2_SCID); Log.DebugFormat("<< {0} [{1:X2}]", L2CAP.Code.L2CAP_Disconnection_Response, (byte)L2CAP.Code.L2CAP_Disconnection_Response); break; #endregion #region L2CAP_Disconnection_Response case L2CAP.Code.L2CAP_Disconnection_Response: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); break; #endregion #region L2CAP_Echo_Request case L2CAP.Code.L2CAP_Echo_Request: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); break; #endregion #region L2CAP_Echo_Response case L2CAP.Code.L2CAP_Echo_Response: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); break; #endregion #region L2CAP_Information_Request case L2CAP.Code.L2CAP_Information_Request: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); break; #endregion #region L2CAP_Information_Response case L2CAP.Code.L2CAP_Information_Response: Log.DebugFormat(">> {0} [{1:X2}]", Event, buffer[8]); break; #endregion } } } else if (buffer[8] == 0xA1 && buffer[9] == 0x11 && transfered == 87) { // HID report received, parse content and extract gamepad data connection.ParseHidReport(buffer); } else if (buffer[8] == 0xA3 && buffer[9] == 0x5) //calibration feature report { // calibration report received, extract the words and start normal output reports connection.ParseHidReport(buffer); } else if (connection.InitHidReport(buffer)) { connection.CanStartHid = true; } }
/// <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> /// 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); } }