2013-11-24 21:55:15 +01:00
/* Copyright (C) 2013 Kristian Lauszus, TKJ Electronics. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 ( GPL2 ) as published by the Free Software
Foundation and appearing in the file GPL2 . TXT included in the packaging of
this file . Please note that GPL2 Section 2 [ b ] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ( " Copyleft " ) .
Contact information
- - - - - - - - - - - - - - - - - - -
Kristian Lauszus , TKJ Electronics
Web : http : //www.tkjelectronics.com
e - mail : kristianl @ tkjelectronics . com
*/
# include "BTHID.h"
// To enable serial debugging see "settings.h"
2020-11-15 17:29:54 +01:00
//#define EXTRADEBUG // Uncomment to get even more debugging data
2013-11-24 23:51:45 +01:00
//#define PRINTREPORT // Uncomment to print the report send by the HID device
2013-11-24 21:55:15 +01:00
BTHID : : BTHID ( BTD * p , bool pair , const char * pin ) :
2014-09-02 11:02:17 +02:00
BluetoothService ( p ) , // Pointer to USB class instance - mandatory
2016-01-16 20:01:11 +01:00
protocolMode ( USB_HID_BOOT_PROTOCOL ) {
2013-12-25 11:09:57 +01:00
for ( uint8_t i = 0 ; i < NUM_PARSERS ; i + + )
2013-11-24 23:51:45 +01:00
pRptParser [ i ] = NULL ;
2013-11-24 21:55:15 +01:00
pBtd - > pairWithHIDDevice = pair ;
2013-12-25 11:09:57 +01:00
pBtd - > btdPin = pin ;
2013-11-24 21:55:15 +01:00
/* Set device cid for the control and intterrupt channelse - LSB */
2019-08-31 18:22:21 +02:00
sdp_dcid [ 0 ] = 0x50 ; // 0x0050
sdp_dcid [ 1 ] = 0x00 ;
2013-11-24 21:55:15 +01:00
control_dcid [ 0 ] = 0x70 ; // 0x0070
control_dcid [ 1 ] = 0x00 ;
interrupt_dcid [ 0 ] = 0x71 ; // 0x0071
interrupt_dcid [ 1 ] = 0x00 ;
Reset ( ) ;
}
void BTHID : : Reset ( ) {
connected = false ;
activeConnection = false ;
2019-07-03 00:30:18 +02:00
SDPConnected = false ;
2013-11-24 21:55:15 +01:00
l2cap_event_flag = 0 ; // Reset flags
2019-07-03 00:30:18 +02:00
l2cap_sdp_state = L2CAP_SDP_WAIT ;
2013-11-24 21:55:15 +01:00
l2cap_state = L2CAP_WAIT ;
2014-01-18 22:36:01 +01:00
ResetBTHID ( ) ;
2013-11-24 21:55:15 +01:00
}
2013-12-30 16:11:19 +01:00
void BTHID : : disconnect ( ) { // Use this void to disconnect the device
2019-07-03 00:30:18 +02:00
if ( SDPConnected )
pBtd - > l2cap_disconnection_request ( hci_handle , + + identifier , sdp_scid , sdp_dcid ) ;
2013-11-24 21:55:15 +01:00
// First the HID interrupt channel has to be disconnected, then the HID control channel and finally the HCI connection
2013-12-13 10:38:41 +01:00
pBtd - > l2cap_disconnection_request ( hci_handle , + + identifier , interrupt_scid , interrupt_dcid ) ;
2013-11-24 21:55:15 +01:00
Reset ( ) ;
2019-07-03 00:30:18 +02:00
l2cap_sdp_state = L2CAP_DISCONNECT_RESPONSE ;
2013-11-24 21:55:15 +01:00
l2cap_state = L2CAP_INTERRUPT_DISCONNECT ;
}
void BTHID : : ACLData ( uint8_t * l2capinbuf ) {
2019-07-03 00:30:18 +02:00
if ( ! connected ) {
if ( l2capinbuf [ 8 ] = = L2CAP_CMD_CONNECTION_REQUEST ) {
if ( ( l2capinbuf [ 12 ] | ( l2capinbuf [ 13 ] < < 8 ) ) = = SDP_PSM & & ! pBtd - > sdpConnectionClaimed ) {
pBtd - > sdpConnectionClaimed = true ;
hci_handle = pBtd - > hci_handle ; // Store the HCI Handle for the connection
l2cap_sdp_state = L2CAP_SDP_WAIT ; // Reset state
}
}
}
2013-12-25 11:09:57 +01:00
if ( ! pBtd - > l2capConnectionClaimed & & pBtd - > incomingHIDDevice & & ! connected & & ! activeConnection ) {
if ( l2capinbuf [ 8 ] = = L2CAP_CMD_CONNECTION_REQUEST ) {
if ( ( l2capinbuf [ 12 ] | ( l2capinbuf [ 13 ] < < 8 ) ) = = HID_CTRL_PSM ) {
2013-11-24 21:55:15 +01:00
pBtd - > incomingHIDDevice = false ;
pBtd - > l2capConnectionClaimed = true ; // Claim that the incoming connection belongs to this service
activeConnection = true ;
hci_handle = pBtd - > hci_handle ; // Store the HCI Handle for the connection
l2cap_state = L2CAP_WAIT ;
}
}
}
2014-09-10 01:38:42 +02:00
if ( checkHciHandle ( l2capinbuf , hci_handle ) ) { // acl_handle_ok
2013-12-25 11:09:57 +01:00
if ( ( l2capinbuf [ 6 ] | ( l2capinbuf [ 7 ] < < 8 ) ) = = 0x0001U ) { // l2cap_control - Channel ID for ACL-U
if ( l2capinbuf [ 8 ] = = L2CAP_CMD_COMMAND_REJECT ) {
2013-11-24 21:55:15 +01:00
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n L2CAP Command Rejected - Reason: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 13 ] , 0x80 ) ;
Notify ( PSTR ( " " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 12 ] , 0x80 ) ;
Notify ( PSTR ( " " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 17 ] , 0x80 ) ;
Notify ( PSTR ( " " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 16 ] , 0x80 ) ;
Notify ( PSTR ( " " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 15 ] , 0x80 ) ;
Notify ( PSTR ( " " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 14 ] , 0x80 ) ;
# endif
2013-12-25 11:09:57 +01:00
} else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_CONNECTION_RESPONSE ) {
if ( ( ( l2capinbuf [ 16 ] | ( l2capinbuf [ 17 ] < < 8 ) ) = = 0x0000 ) & & ( ( l2capinbuf [ 18 ] | ( l2capinbuf [ 19 ] < < 8 ) ) = = SUCCESSFUL ) ) { // Success
2019-08-31 18:22:21 +02:00
if ( l2capinbuf [ 14 ] = = sdp_dcid [ 0 ] & & l2capinbuf [ 15 ] = = sdp_dcid [ 1 ] ) {
2020-11-15 17:29:54 +01:00
# ifdef EXTRADEBUG
2019-08-31 18:22:21 +02:00
Notify ( PSTR ( " \r \n SDP Connection Complete " ) , 0x80 ) ;
2020-11-15 17:29:54 +01:00
# endif
2019-08-31 18:22:21 +02:00
identifier = l2capinbuf [ 9 ] ;
sdp_scid [ 0 ] = l2capinbuf [ 12 ] ;
sdp_scid [ 1 ] = l2capinbuf [ 13 ] ;
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Send SDP Config Request " ) , 0x80 ) ;
# endif
identifier + + ;
pBtd - > l2cap_config_request ( hci_handle , identifier , sdp_scid ) ;
} else if ( l2capinbuf [ 14 ] = = control_dcid [ 0 ] & & l2capinbuf [ 15 ] = = control_dcid [ 1 ] ) {
2020-11-15 17:29:54 +01:00
# ifdef EXTRADEBUG
2019-08-31 18:22:21 +02:00
Notify ( PSTR ( " \r \n HID Control Connection Complete " ) , 0x80 ) ;
2020-11-15 17:29:54 +01:00
# endif
2013-11-24 21:55:15 +01:00
identifier = l2capinbuf [ 9 ] ;
control_scid [ 0 ] = l2capinbuf [ 12 ] ;
control_scid [ 1 ] = l2capinbuf [ 13 ] ;
2013-12-11 09:59:58 +01:00
l2cap_set_flag ( L2CAP_FLAG_CONTROL_CONNECTED ) ;
2013-12-25 11:09:57 +01:00
} else if ( l2capinbuf [ 14 ] = = interrupt_dcid [ 0 ] & & l2capinbuf [ 15 ] = = interrupt_dcid [ 1 ] ) {
2020-11-15 17:29:54 +01:00
# ifdef EXTRADEBUG
2019-08-31 18:22:21 +02:00
Notify ( PSTR ( " \r \n HID Interrupt Connection Complete " ) , 0x80 ) ;
2020-11-15 17:29:54 +01:00
# endif
2013-11-24 21:55:15 +01:00
identifier = l2capinbuf [ 9 ] ;
interrupt_scid [ 0 ] = l2capinbuf [ 12 ] ;
interrupt_scid [ 1 ] = l2capinbuf [ 13 ] ;
2013-12-11 09:59:58 +01:00
l2cap_set_flag ( L2CAP_FLAG_INTERRUPT_CONNECTED ) ;
2013-11-24 21:55:15 +01:00
}
}
2013-12-25 11:09:57 +01:00
} else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_CONNECTION_REQUEST ) {
2013-11-24 21:55:15 +01:00
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n L2CAP Connection Request - PSM: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 13 ] , 0x80 ) ;
Notify ( PSTR ( " " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 12 ] , 0x80 ) ;
Notify ( PSTR ( " SCID: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 15 ] , 0x80 ) ;
Notify ( PSTR ( " " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 14 ] , 0x80 ) ;
Notify ( PSTR ( " Identifier: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 9 ] , 0x80 ) ;
# endif
2019-07-03 00:30:18 +02:00
if ( ( l2capinbuf [ 12 ] | ( l2capinbuf [ 13 ] < < 8 ) ) = = SDP_PSM ) {
identifier = l2capinbuf [ 9 ] ;
sdp_scid [ 0 ] = l2capinbuf [ 14 ] ;
sdp_scid [ 1 ] = l2capinbuf [ 15 ] ;
l2cap_set_flag ( L2CAP_FLAG_CONNECTION_SDP_REQUEST ) ;
} else if ( ( l2capinbuf [ 12 ] | ( l2capinbuf [ 13 ] < < 8 ) ) = = HID_CTRL_PSM ) {
2013-11-24 21:55:15 +01:00
identifier = l2capinbuf [ 9 ] ;
control_scid [ 0 ] = l2capinbuf [ 14 ] ;
control_scid [ 1 ] = l2capinbuf [ 15 ] ;
2013-12-11 09:59:58 +01:00
l2cap_set_flag ( L2CAP_FLAG_CONNECTION_CONTROL_REQUEST ) ;
2013-12-25 11:09:57 +01:00
} else if ( ( l2capinbuf [ 12 ] | ( l2capinbuf [ 13 ] < < 8 ) ) = = HID_INTR_PSM ) {
2013-11-24 21:55:15 +01:00
identifier = l2capinbuf [ 9 ] ;
interrupt_scid [ 0 ] = l2capinbuf [ 14 ] ;
interrupt_scid [ 1 ] = l2capinbuf [ 15 ] ;
2013-12-11 09:59:58 +01:00
l2cap_set_flag ( L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST ) ;
2013-11-24 21:55:15 +01:00
}
2013-12-25 11:09:57 +01:00
} else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_CONFIG_RESPONSE ) {
if ( ( l2capinbuf [ 16 ] | ( l2capinbuf [ 17 ] < < 8 ) ) = = 0x0000 ) { // Success
2019-07-03 00:30:18 +02:00
if ( l2capinbuf [ 12 ] = = sdp_dcid [ 0 ] & & l2capinbuf [ 13 ] = = sdp_dcid [ 1 ] ) {
2020-11-15 17:29:54 +01:00
# ifdef EXTRADEBUG
2019-08-31 18:22:21 +02:00
Notify ( PSTR ( " \r \n SDP Configuration Complete " ) , 0x80 ) ;
2020-11-15 17:29:54 +01:00
# endif
2019-07-03 00:30:18 +02:00
identifier = l2capinbuf [ 9 ] ;
l2cap_set_flag ( L2CAP_FLAG_CONFIG_SDP_SUCCESS ) ;
} else if ( l2capinbuf [ 12 ] = = control_dcid [ 0 ] & & l2capinbuf [ 13 ] = = control_dcid [ 1 ] ) {
2020-11-15 17:29:54 +01:00
# ifdef EXTRADEBUG
2019-08-31 18:22:21 +02:00
Notify ( PSTR ( " \r \n HID Control Configuration Complete " ) , 0x80 ) ;
2020-11-15 17:29:54 +01:00
# endif
2013-11-24 21:55:15 +01:00
identifier = l2capinbuf [ 9 ] ;
2013-12-11 09:59:58 +01:00
l2cap_set_flag ( L2CAP_FLAG_CONFIG_CONTROL_SUCCESS ) ;
2013-12-25 11:09:57 +01:00
} else if ( l2capinbuf [ 12 ] = = interrupt_dcid [ 0 ] & & l2capinbuf [ 13 ] = = interrupt_dcid [ 1 ] ) {
2020-11-15 17:29:54 +01:00
# ifdef EXTRADEBUG
2019-08-31 18:22:21 +02:00
Notify ( PSTR ( " \r \n HID Interrupt Configuration Complete " ) , 0x80 ) ;
2020-11-15 17:29:54 +01:00
# endif
2013-11-24 21:55:15 +01:00
identifier = l2capinbuf [ 9 ] ;
2013-12-11 09:59:58 +01:00
l2cap_set_flag ( L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS ) ;
2013-11-24 21:55:15 +01:00
}
}
2013-12-25 11:09:57 +01:00
} else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_CONFIG_REQUEST ) {
2019-07-03 00:30:18 +02:00
if ( l2capinbuf [ 12 ] = = sdp_dcid [ 0 ] & & l2capinbuf [ 13 ] = = sdp_dcid [ 1 ] ) {
2020-11-15 17:29:54 +01:00
# ifdef EXTRADEBUG
2019-08-31 18:22:21 +02:00
Notify ( PSTR ( " \r \n SDP Configuration Request " ) , 0x80 ) ;
2020-11-15 17:29:54 +01:00
# endif
2019-07-03 00:30:18 +02:00
pBtd - > l2cap_config_response ( hci_handle , l2capinbuf [ 9 ] , sdp_scid ) ;
} else if ( l2capinbuf [ 12 ] = = control_dcid [ 0 ] & & l2capinbuf [ 13 ] = = control_dcid [ 1 ] ) {
2020-11-15 17:29:54 +01:00
# ifdef EXTRADEBUG
2019-08-31 18:22:21 +02:00
Notify ( PSTR ( " \r \n HID Control Configuration Request " ) , 0x80 ) ;
2020-11-15 17:29:54 +01:00
# endif
2013-11-24 21:55:15 +01:00
pBtd - > l2cap_config_response ( hci_handle , l2capinbuf [ 9 ] , control_scid ) ;
2013-12-25 11:09:57 +01:00
} else if ( l2capinbuf [ 12 ] = = interrupt_dcid [ 0 ] & & l2capinbuf [ 13 ] = = interrupt_dcid [ 1 ] ) {
2020-11-15 17:29:54 +01:00
# ifdef EXTRADEBUG
2019-08-31 18:22:21 +02:00
Notify ( PSTR ( " \r \n HID Interrupt Configuration Request " ) , 0x80 ) ;
2020-11-15 17:29:54 +01:00
# endif
2013-11-24 21:55:15 +01:00
pBtd - > l2cap_config_response ( hci_handle , l2capinbuf [ 9 ] , interrupt_scid ) ;
}
2013-12-25 11:09:57 +01:00
} else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_DISCONNECT_REQUEST ) {
2019-07-03 00:30:18 +02:00
if ( l2capinbuf [ 12 ] = = sdp_dcid [ 0 ] & & l2capinbuf [ 13 ] = = sdp_dcid [ 1 ] ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Disconnect Request: SDP Channel " ) , 0x80 ) ;
# endif
identifier = l2capinbuf [ 9 ] ;
l2cap_set_flag ( L2CAP_FLAG_DISCONNECT_SDP_REQUEST ) ;
} else if ( l2capinbuf [ 12 ] = = control_dcid [ 0 ] & & l2capinbuf [ 13 ] = = control_dcid [ 1 ] ) {
2013-11-24 21:55:15 +01:00
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Disconnect Request: Control Channel " ) , 0x80 ) ;
# endif
identifier = l2capinbuf [ 9 ] ;
pBtd - > l2cap_disconnection_response ( hci_handle , identifier , control_dcid , control_scid ) ;
Reset ( ) ;
2013-12-25 11:09:57 +01:00
} else if ( l2capinbuf [ 12 ] = = interrupt_dcid [ 0 ] & & l2capinbuf [ 13 ] = = interrupt_dcid [ 1 ] ) {
2013-11-24 21:55:15 +01:00
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Disconnect Request: Interrupt Channel " ) , 0x80 ) ;
# endif
identifier = l2capinbuf [ 9 ] ;
pBtd - > l2cap_disconnection_response ( hci_handle , identifier , interrupt_dcid , interrupt_scid ) ;
Reset ( ) ;
}
2013-12-25 11:09:57 +01:00
} else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_DISCONNECT_RESPONSE ) {
2019-07-03 00:30:18 +02:00
if ( l2capinbuf [ 12 ] = = sdp_scid [ 0 ] & & l2capinbuf [ 13 ] = = sdp_scid [ 1 ] ) {
2020-11-15 17:29:54 +01:00
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n Disconnect Response: SDP Channel " ) , 0x80 ) ;
# endif
2019-07-03 00:30:18 +02:00
identifier = l2capinbuf [ 9 ] ;
l2cap_set_flag ( L2CAP_FLAG_DISCONNECT_RESPONSE ) ;
} else if ( l2capinbuf [ 12 ] = = control_scid [ 0 ] & & l2capinbuf [ 13 ] = = control_scid [ 1 ] ) {
2020-11-15 17:29:54 +01:00
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n Disconnect Response: Control Channel " ) , 0x80 ) ;
# endif
2013-11-24 21:55:15 +01:00
identifier = l2capinbuf [ 9 ] ;
2013-12-11 09:59:58 +01:00
l2cap_set_flag ( L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE ) ;
2013-12-25 11:09:57 +01:00
} else if ( l2capinbuf [ 12 ] = = interrupt_scid [ 0 ] & & l2capinbuf [ 13 ] = = interrupt_scid [ 1 ] ) {
2020-11-15 17:29:54 +01:00
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n Disconnect Response: Interrupt Channel " ) , 0x80 ) ;
# endif
2013-11-24 21:55:15 +01:00
identifier = l2capinbuf [ 9 ] ;
2013-12-11 09:59:58 +01:00
l2cap_set_flag ( L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE ) ;
2013-11-24 21:55:15 +01:00
}
2019-07-03 00:30:18 +02:00
} else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_INFORMATION_REQUEST ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Information request " ) , 0x80 ) ;
# endif
identifier = l2capinbuf [ 9 ] ;
pBtd - > l2cap_information_response ( hci_handle , identifier , l2capinbuf [ 12 ] , l2capinbuf [ 13 ] ) ;
2013-11-24 21:55:15 +01:00
}
# ifdef EXTRADEBUG
else {
identifier = l2capinbuf [ 9 ] ;
Notify ( PSTR ( " \r \n L2CAP Unknown Signaling Command: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 8 ] , 0x80 ) ;
}
2019-07-03 00:30:18 +02:00
# endif
} else if ( l2capinbuf [ 6 ] = = sdp_dcid [ 0 ] & & l2capinbuf [ 7 ] = = sdp_dcid [ 1 ] ) { // SDP
if ( l2capinbuf [ 8 ] = = SDP_SERVICE_SEARCH_REQUEST ) {
2020-11-15 19:02:54 +01:00
# ifdef EXTRADEBUG
2019-07-03 00:30:18 +02:00
Notify ( PSTR ( " \r \n SDP_SERVICE_SEARCH_REQUEST " ) , 0x80 ) ;
2020-11-15 19:02:54 +01:00
# endif
2019-07-03 00:30:18 +02:00
// Send response
l2capoutbuf [ 0 ] = SDP_SERVICE_SEARCH_RESPONSE ;
l2capoutbuf [ 1 ] = l2capinbuf [ 9 ] ; //transactionIDHigh;
l2capoutbuf [ 2 ] = l2capinbuf [ 10 ] ; //transactionIDLow;
2020-11-15 17:29:54 +01:00
2019-07-03 00:30:18 +02:00
l2capoutbuf [ 3 ] = 0x00 ; // MSB Parameter Length
l2capoutbuf [ 4 ] = 0x05 ; // LSB Parameter Length = 5
l2capoutbuf [ 5 ] = 0x00 ; // MSB TotalServiceRecordCount
l2capoutbuf [ 6 ] = 0x00 ; // LSB TotalServiceRecordCount = 0
l2capoutbuf [ 7 ] = 0x00 ; // MSB CurrentServiceRecordCount
l2capoutbuf [ 8 ] = 0x00 ; // LSB CurrentServiceRecordCount = 0
l2capoutbuf [ 9 ] = 0x00 ; // No continuation state
SDP_Command ( l2capoutbuf , 10 ) ;
} else if ( l2capinbuf [ 8 ] = = SDP_SERVICE_ATTRIBUTE_REQUEST ) {
2020-11-15 19:02:54 +01:00
# ifdef EXTRADEBUG
2019-07-03 00:30:18 +02:00
Notify ( PSTR ( " \r \n SDP_SERVICE_ATTRIBUTE_REQUEST " ) , 0x80 ) ;
2020-11-15 19:02:54 +01:00
# endif
2019-07-03 00:30:18 +02:00
// Send response
l2capoutbuf [ 0 ] = SDP_SERVICE_ATTRIBUTE_RESPONSE ;
l2capoutbuf [ 1 ] = l2capinbuf [ 9 ] ; //transactionIDHigh;
l2capoutbuf [ 2 ] = l2capinbuf [ 10 ] ; //transactionIDLow;
l2capoutbuf [ 3 ] = 0x00 ; // MSB Parameter Length
l2capoutbuf [ 4 ] = 0x05 ; // LSB Parameter Length = 5
l2capoutbuf [ 5 ] = 0x00 ; // MSB AttributeListByteCount
l2capoutbuf [ 6 ] = 0x02 ; // LSB AttributeListByteCount = 2
// TODO: What to send?
l2capoutbuf [ 7 ] = 0x35 ; // Data element sequence - length in next byte
l2capoutbuf [ 8 ] = 0x00 ; // Length = 0
l2capoutbuf [ 9 ] = 0x00 ; // No continuation state
SDP_Command ( l2capoutbuf , 10 ) ;
2019-08-31 18:22:21 +02:00
} else if ( l2capinbuf [ 8 ] = = SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST ) {
2019-07-03 00:30:18 +02:00
# ifdef EXTRADEBUG
2020-11-15 17:29:54 +01:00
Notify ( PSTR ( " \r \n SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST " ) , 0x80 ) ;
2019-07-03 00:30:18 +02:00
Notify ( PSTR ( " \r \n UUID: " ) , 0x80 ) ;
uint16_t uuid ;
if ( ( l2capinbuf [ 16 ] < < 8 | l2capinbuf [ 17 ] ) = = 0x0000 ) // Check if it's sending the UUID as a 128-bit UUID
uuid = ( l2capinbuf [ 18 ] < < 8 | l2capinbuf [ 19 ] ) ;
else // Short UUID
uuid = ( l2capinbuf [ 16 ] < < 8 | l2capinbuf [ 17 ] ) ;
D_PrintHex < uint16_t > ( uuid , 0x80 ) ;
Notify ( PSTR ( " \r \n Length: " ) , 0x80 ) ;
uint16_t length = l2capinbuf [ 11 ] < < 8 | l2capinbuf [ 12 ] ;
D_PrintHex < uint16_t > ( length , 0x80 ) ;
Notify ( PSTR ( " \r \n Data: " ) , 0x80 ) ;
for ( uint8_t i = 0 ; i < length ; i + + ) {
D_PrintHex < uint8_t > ( l2capinbuf [ 13 + i ] , 0x80 ) ;
Notify ( PSTR ( " " ) , 0x80 ) ;
}
# endif
serviceNotSupported ( l2capinbuf [ 9 ] , l2capinbuf [ 10 ] ) ; // The service is not supported
}
# ifdef EXTRADEBUG
else {
Notify ( PSTR ( " \r \n Unknown PDU: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 8 ] , 0x80 ) ;
}
2013-11-24 21:55:15 +01:00
# endif
2013-12-25 11:09:57 +01:00
} else if ( l2capinbuf [ 6 ] = = interrupt_dcid [ 0 ] & & l2capinbuf [ 7 ] = = interrupt_dcid [ 1 ] ) { // l2cap_interrupt
2013-11-24 21:55:15 +01:00
# ifdef PRINTREPORT
2013-11-25 02:58:33 +01:00
Notify ( PSTR ( " \r \n L2CAP Interrupt: " ) , 0x80 ) ;
2013-12-25 11:09:57 +01:00
for ( uint16_t i = 0 ; i < ( ( uint16_t ) l2capinbuf [ 5 ] < < 8 | l2capinbuf [ 4 ] ) ; i + + ) {
2013-11-24 21:55:15 +01:00
D_PrintHex < uint8_t > ( l2capinbuf [ i + 8 ] , 0x80 ) ;
2013-11-25 18:46:10 +01:00
Notify ( PSTR ( " " ) , 0x80 ) ;
2013-11-24 21:55:15 +01:00
}
# endif
2021-01-19 10:57:14 +01:00
if ( l2capinbuf [ 8 ] = = 0xA1 ) { // HID BT DATA (0xA0) | Report Type (Input 0x01)
2014-01-18 22:36:01 +01:00
uint16_t length = ( ( uint16_t ) l2capinbuf [ 5 ] < < 8 | l2capinbuf [ 4 ] ) ;
2021-01-19 10:57:14 +01:00
ParseBTHIDData ( ( uint8_t ) ( length - 1 ) , & l2capinbuf [ 9 ] ) ; // First byte will be the report ID
2014-01-18 22:36:01 +01:00
2021-01-19 10:57:14 +01:00
switch ( l2capinbuf [ 9 ] ) { // Report ID
2014-01-18 22:36:01 +01:00
case 0x01 : // Keyboard or Joystick events
if ( pRptParser [ KEYBOARD_PARSER_ID ] )
2016-01-16 20:01:11 +01:00
pRptParser [ KEYBOARD_PARSER_ID ] - > Parse ( reinterpret_cast < USBHID * > ( this ) , 0 , ( uint8_t ) ( length - 2 ) , & l2capinbuf [ 10 ] ) ; // Use reinterpret_cast again to extract the instance
2013-11-24 21:55:15 +01:00
break ;
case 0x02 : // Mouse events
2014-01-18 22:36:01 +01:00
if ( pRptParser [ MOUSE_PARSER_ID ] )
2016-01-16 20:01:11 +01:00
pRptParser [ MOUSE_PARSER_ID ] - > Parse ( reinterpret_cast < USBHID * > ( this ) , 0 , ( uint8_t ) ( length - 2 ) , & l2capinbuf [ 10 ] ) ; // Use reinterpret_cast again to extract the instance
2013-11-24 21:55:15 +01:00
break ;
2014-01-22 05:13:49 +01:00
# ifdef EXTRADEBUG
2013-11-24 21:55:15 +01:00
default :
Notify ( PSTR ( " \r \n Unknown Report type: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 9 ] , 0x80 ) ;
break ;
# endif
}
2021-01-19 10:57:14 +01:00
} else {
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n Unhandled L2CAP interrupt report: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 8 ] , 0x80 ) ;
# endif
2013-11-24 21:55:15 +01:00
}
2013-12-25 11:09:57 +01:00
} else if ( l2capinbuf [ 6 ] = = control_dcid [ 0 ] & & l2capinbuf [ 7 ] = = control_dcid [ 1 ] ) { // l2cap_control
2013-11-25 02:58:33 +01:00
# ifdef PRINTREPORT
Notify ( PSTR ( " \r \n L2CAP Control: " ) , 0x80 ) ;
2013-12-25 11:09:57 +01:00
for ( uint16_t i = 0 ; i < ( ( uint16_t ) l2capinbuf [ 5 ] < < 8 | l2capinbuf [ 4 ] ) ; i + + ) {
2013-11-25 02:58:33 +01:00
D_PrintHex < uint8_t > ( l2capinbuf [ i + 8 ] , 0x80 ) ;
2013-11-25 18:46:10 +01:00
Notify ( PSTR ( " " ) , 0x80 ) ;
2013-11-25 02:58:33 +01:00
}
# endif
2021-01-19 10:57:14 +01:00
if ( l2capinbuf [ 8 ] = = 0xA3 ) { // HID BT DATA (0xA0) | Report Type (Feature 0x03)
2020-02-28 18:03:16 +01:00
uint16_t length = ( ( uint16_t ) l2capinbuf [ 5 ] < < 8 | l2capinbuf [ 4 ] ) ;
2021-01-19 10:57:14 +01:00
ParseBTHIDControlData ( ( uint8_t ) ( length - 1 ) , & l2capinbuf [ 9 ] ) ; // First byte will be the report ID
} else {
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n Unhandled L2CAP control report: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 8 ] , 0x80 ) ;
# endif
2020-02-28 18:03:16 +01:00
}
2013-11-24 21:55:15 +01:00
}
# ifdef EXTRADEBUG
else {
Notify ( PSTR ( " \r \n Unsupported L2CAP Data - Channel ID: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 7 ] , 0x80 ) ;
Notify ( PSTR ( " " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 6 ] , 0x80 ) ;
Notify ( PSTR ( " \r \n Data: " ) , 0x80 ) ;
Notify ( PSTR ( " \r \n " ) , 0x80 ) ;
2013-12-25 11:09:57 +01:00
for ( uint16_t i = 0 ; i < ( ( uint16_t ) l2capinbuf [ 5 ] < < 8 | l2capinbuf [ 4 ] ) ; i + + ) {
2013-11-24 21:55:15 +01:00
D_PrintHex < uint8_t > ( l2capinbuf [ i + 8 ] , 0x80 ) ;
2013-11-27 00:07:58 +01:00
Notify ( PSTR ( " " ) , 0x80 ) ;
2013-11-24 21:55:15 +01:00
}
}
# endif
2019-07-03 00:30:18 +02:00
SDP_task ( ) ;
2013-11-24 21:55:15 +01:00
L2CAP_task ( ) ;
}
}
2019-07-03 00:30:18 +02:00
void BTHID : : SDP_task ( ) {
switch ( l2cap_sdp_state ) {
case L2CAP_SDP_WAIT :
if ( l2cap_check_flag ( L2CAP_FLAG_CONNECTION_SDP_REQUEST ) ) {
l2cap_clear_flag ( L2CAP_FLAG_CONNECTION_SDP_REQUEST ) ; // Clear flag
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n SDP Incoming Connection Request " ) , 0x80 ) ;
# endif
pBtd - > l2cap_connection_response ( hci_handle , identifier , sdp_dcid , sdp_scid , PENDING ) ;
delay ( 1 ) ;
pBtd - > l2cap_connection_response ( hci_handle , identifier , sdp_dcid , sdp_scid , SUCCESSFUL ) ;
identifier + + ;
delay ( 1 ) ;
pBtd - > l2cap_config_request ( hci_handle , identifier , sdp_scid ) ;
l2cap_sdp_state = L2CAP_SDP_SUCCESS ;
} else if ( l2cap_check_flag ( L2CAP_FLAG_DISCONNECT_SDP_REQUEST ) ) {
l2cap_clear_flag ( L2CAP_FLAG_DISCONNECT_SDP_REQUEST ) ; // Clear flag
SDPConnected = false ;
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Disconnected SDP Channel " ) , 0x80 ) ;
# endif
pBtd - > l2cap_disconnection_response ( hci_handle , identifier , sdp_dcid , sdp_scid ) ;
}
break ;
case L2CAP_SDP_SUCCESS :
if ( l2cap_check_flag ( L2CAP_FLAG_CONFIG_SDP_SUCCESS ) ) {
l2cap_clear_flag ( L2CAP_FLAG_CONFIG_SDP_SUCCESS ) ; // Clear flag
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n SDP Successfully Configured " ) , 0x80 ) ;
# endif
SDPConnected = true ;
l2cap_sdp_state = L2CAP_SDP_WAIT ;
}
break ;
case L2CAP_DISCONNECT_RESPONSE : // This is for both disconnection response from the RFCOMM and SDP channel if they were connected
if ( l2cap_check_flag ( L2CAP_FLAG_DISCONNECT_RESPONSE ) ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Disconnected L2CAP Connection " ) , 0x80 ) ;
# endif
pBtd - > hci_disconnect ( hci_handle ) ;
hci_handle = - 1 ; // Reset handle
Reset ( ) ;
}
break ;
}
}
2013-11-24 21:55:15 +01:00
void BTHID : : L2CAP_task ( ) {
2013-12-25 11:09:57 +01:00
switch ( l2cap_state ) {
2013-11-24 23:51:45 +01:00
/* These states are used if the HID device is the host */
2013-11-24 21:55:15 +01:00
case L2CAP_CONTROL_SUCCESS :
2013-12-25 11:09:57 +01:00
if ( l2cap_check_flag ( L2CAP_FLAG_CONFIG_CONTROL_SUCCESS ) ) {
2013-11-24 21:55:15 +01:00
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n HID Control Successfully Configured " ) , 0x80 ) ;
# endif
2013-11-25 19:01:20 +01:00
setProtocol ( ) ; // Set protocol before establishing HID interrupt channel
2013-11-24 21:55:15 +01:00
l2cap_state = L2CAP_INTERRUPT_SETUP ;
}
break ;
case L2CAP_INTERRUPT_SETUP :
2013-12-25 11:09:57 +01:00
if ( l2cap_check_flag ( L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST ) ) {
2013-11-24 21:55:15 +01:00
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n HID Interrupt Incoming Connection Request " ) , 0x80 ) ;
# endif
pBtd - > l2cap_connection_response ( hci_handle , identifier , interrupt_dcid , interrupt_scid , PENDING ) ;
delay ( 1 ) ;
pBtd - > l2cap_connection_response ( hci_handle , identifier , interrupt_dcid , interrupt_scid , SUCCESSFUL ) ;
identifier + + ;
delay ( 1 ) ;
pBtd - > l2cap_config_request ( hci_handle , identifier , interrupt_scid ) ;
l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST ;
}
break ;
/* These states are used if the Arduino is the host */
case L2CAP_CONTROL_CONNECT_REQUEST :
2013-12-25 11:09:57 +01:00
if ( l2cap_check_flag ( L2CAP_FLAG_CONTROL_CONNECTED ) ) {
2013-11-24 21:55:15 +01:00
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Send HID Control Config Request " ) , 0x80 ) ;
# endif
identifier + + ;
pBtd - > l2cap_config_request ( hci_handle , identifier , control_scid ) ;
l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST ;
}
break ;
case L2CAP_CONTROL_CONFIG_REQUEST :
2013-12-25 11:09:57 +01:00
if ( l2cap_check_flag ( L2CAP_FLAG_CONFIG_CONTROL_SUCCESS ) ) {
2013-11-25 19:01:20 +01:00
setProtocol ( ) ; // Set protocol before establishing HID interrupt channel
delay ( 1 ) ; // Short delay between commands - just to be sure
2013-11-24 21:55:15 +01:00
# ifdef DEBUG_USB_HOST
2013-11-25 19:01:20 +01:00
Notify ( PSTR ( " \r \n Send HID Interrupt Connection Request " ) , 0x80 ) ;
2013-11-24 21:55:15 +01:00
# endif
2013-11-25 19:01:20 +01:00
identifier + + ;
pBtd - > l2cap_connection_request ( hci_handle , identifier , interrupt_dcid , HID_INTR_PSM ) ;
l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST ;
}
2013-11-24 21:55:15 +01:00
break ;
case L2CAP_INTERRUPT_CONNECT_REQUEST :
2013-12-25 11:09:57 +01:00
if ( l2cap_check_flag ( L2CAP_FLAG_INTERRUPT_CONNECTED ) ) {
2013-11-24 21:55:15 +01:00
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Send HID Interrupt Config Request " ) , 0x80 ) ;
# endif
identifier + + ;
pBtd - > l2cap_config_request ( hci_handle , identifier , interrupt_scid ) ;
l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST ;
}
break ;
case L2CAP_INTERRUPT_CONFIG_REQUEST :
2013-12-25 11:09:57 +01:00
if ( l2cap_check_flag ( L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS ) ) { // Now the HID channels is established
2013-11-24 21:55:15 +01:00
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n HID Channels Established " ) , 0x80 ) ;
# endif
pBtd - > connectToHIDDevice = false ;
pBtd - > pairWithHIDDevice = false ;
connected = true ;
onInit ( ) ;
l2cap_state = L2CAP_DONE ;
}
break ;
case L2CAP_DONE :
break ;
case L2CAP_INTERRUPT_DISCONNECT :
2013-12-25 11:09:57 +01:00
if ( l2cap_check_flag ( L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE ) ) {
2013-11-24 21:55:15 +01:00
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Disconnected Interrupt Channel " ) , 0x80 ) ;
# endif
identifier + + ;
pBtd - > l2cap_disconnection_request ( hci_handle , identifier , control_scid , control_dcid ) ;
l2cap_state = L2CAP_CONTROL_DISCONNECT ;
}
break ;
case L2CAP_CONTROL_DISCONNECT :
2013-12-25 11:09:57 +01:00
if ( l2cap_check_flag ( L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE ) ) {
2013-11-24 21:55:15 +01:00
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Disconnected Control Channel " ) , 0x80 ) ;
# endif
pBtd - > hci_disconnect ( hci_handle ) ;
hci_handle = - 1 ; // Reset handle
l2cap_event_flag = 0 ; // Reset flags
l2cap_state = L2CAP_WAIT ;
}
break ;
}
}
void BTHID : : Run ( ) {
2013-12-25 11:09:57 +01:00
switch ( l2cap_state ) {
2013-11-24 21:55:15 +01:00
case L2CAP_WAIT :
2013-12-25 11:09:57 +01:00
if ( pBtd - > connectToHIDDevice & & ! pBtd - > l2capConnectionClaimed & & ! connected & & ! activeConnection ) {
2013-11-24 21:55:15 +01:00
pBtd - > l2capConnectionClaimed = true ;
activeConnection = true ;
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Send HID Control Connection Request " ) , 0x80 ) ;
# endif
hci_handle = pBtd - > hci_handle ; // Store the HCI Handle for the connection
l2cap_event_flag = 0 ; // Reset flags
identifier = 0 ;
pBtd - > l2cap_connection_request ( hci_handle , identifier , control_dcid , HID_CTRL_PSM ) ;
l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST ;
2013-12-25 11:09:57 +01:00
} else if ( l2cap_check_flag ( L2CAP_FLAG_CONNECTION_CONTROL_REQUEST ) ) {
2013-11-24 21:55:15 +01:00
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n HID Control Incoming Connection Request " ) , 0x80 ) ;
# endif
pBtd - > l2cap_connection_response ( hci_handle , identifier , control_dcid , control_scid , PENDING ) ;
delay ( 1 ) ;
pBtd - > l2cap_connection_response ( hci_handle , identifier , control_dcid , control_scid , SUCCESSFUL ) ;
identifier + + ;
delay ( 1 ) ;
pBtd - > l2cap_config_request ( hci_handle , identifier , control_scid ) ;
l2cap_state = L2CAP_CONTROL_SUCCESS ;
}
break ;
}
}
2019-07-03 00:30:18 +02:00
void BTHID : : SDP_Command ( uint8_t * data , uint8_t nbytes ) { // See page 223 in the Bluetooth specs
pBtd - > L2CAP_Command ( hci_handle , data , nbytes , sdp_scid [ 0 ] , sdp_scid [ 1 ] ) ;
}
void BTHID : : serviceNotSupported ( uint8_t transactionIDHigh , uint8_t transactionIDLow ) { // See page 235 in the Bluetooth specs
2019-08-31 18:22:21 +02:00
l2capoutbuf [ 0 ] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE ;
2019-07-03 00:30:18 +02:00
l2capoutbuf [ 1 ] = transactionIDHigh ;
l2capoutbuf [ 2 ] = transactionIDLow ;
l2capoutbuf [ 3 ] = 0x00 ; // MSB Parameter Length
l2capoutbuf [ 4 ] = 0x05 ; // LSB Parameter Length = 5
l2capoutbuf [ 5 ] = 0x00 ; // MSB AttributeListsByteCount
l2capoutbuf [ 6 ] = 0x02 ; // LSB AttributeListsByteCount = 2
/* Attribute ID/Value Sequence: */
l2capoutbuf [ 7 ] = 0x35 ; // Data element sequence - length in next byte
l2capoutbuf [ 8 ] = 0x00 ; // Length = 0
l2capoutbuf [ 9 ] = 0x00 ; // No continuation state
SDP_Command ( l2capoutbuf , 10 ) ;
}
2013-11-24 21:55:15 +01:00
/************************************************************/
/* HID Commands */
2013-12-25 11:09:57 +01:00
2013-11-24 21:55:15 +01:00
/************************************************************/
void BTHID : : setProtocol ( ) {
2013-11-25 02:15:33 +01:00
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Set protocol mode: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( protocolMode , 0x80 ) ;
# endif
2016-01-16 20:01:11 +01:00
if ( protocolMode ! = USB_HID_BOOT_PROTOCOL & & protocolMode ! = HID_RPT_PROTOCOL ) {
2013-12-30 16:11:19 +01:00
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Not a valid protocol mode. Using Boot protocol instead. " ) , 0x80 ) ;
# endif
2016-01-16 20:01:11 +01:00
protocolMode = USB_HID_BOOT_PROTOCOL ; // Use Boot Protocol by default
2013-12-30 16:11:19 +01:00
}
uint8_t command = 0x70 | protocolMode ; // Set Protocol, see Bluetooth HID specs page 33
2013-11-24 21:55:15 +01:00
pBtd - > L2CAP_Command ( hci_handle , & command , 1 , control_scid [ 0 ] , control_scid [ 1 ] ) ;
2013-11-25 01:45:24 +01:00
}
void BTHID : : setLeds ( uint8_t data ) {
uint8_t buf [ 3 ] ;
buf [ 0 ] = 0xA2 ; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
buf [ 1 ] = 0x01 ; // Report ID
buf [ 2 ] = data ;
pBtd - > L2CAP_Command ( hci_handle , buf , 3 , interrupt_scid [ 0 ] , interrupt_scid [ 1 ] ) ;
2013-12-25 11:09:57 +01:00
}