2014-04-21 18:27:04 +02:00
/* Copyright (C) 2012 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
Enhanced by Dmitry Pakhomenko to initiate connection with remote SPP - aware device
04.04 .2014 , Magictale Electronics
*/
2014-04-21 18:41:39 +02:00
# include "SPPClient.h"
2014-04-21 18:27:04 +02:00
// To enable serial debugging see "settings.h"
//#define EXTRADEBUG // Uncomment to get even more debugging data
//#define PRINTREPORT // Uncomment to print the report sent to the Arduino
/*
* " RFCOMM UUID " signature , a channel number comes immediately after it
*/
const uint8_t rfcomm_uuid_sign [ 6 ] PROGMEM = { 0x35 , 0x05 , 0x19 , 0x00 , 0x03 , 0x08 } ;
2014-04-21 18:41:39 +02:00
SPPClient : : SPPClient ( BTD * p , const char * name , const char * pin , bool pair , uint8_t * addr ) :
2014-04-21 18:27:04 +02:00
SPPBase ( p )
{
if ( pBtd )
pBtd - > registerServiceClass ( this ) ; // Register it as a Bluetooth service
pBtd - > btdName = name ;
pBtd - > btdPin = pin ;
if ( addr ) // Make sure address is set
pBtd - > pairWithOtherDevice = pair ;
for ( uint8_t i = 0 ; i < 6 ; i + + )
pBtd - > remote_bdaddr [ i ] = addr [ i ] ;
/* Set device cid for the SDP and RFCOMM channels */
sdp_scid [ 0 ] = 0x50 ; // 0x0050
sdp_scid [ 1 ] = 0x00 ;
rfcomm_scid [ 0 ] = 0x51 ; // 0x0051
rfcomm_scid [ 1 ] = 0x00 ;
Reset ( ) ;
}
2014-04-21 18:41:39 +02:00
void SPPClient : : Reset ( ) {
2014-04-21 18:27:04 +02:00
connected = false ;
RFCOMMConnected = false ;
SDPConnected = false ;
l2cap_sdp_state = L2CAP_SDP_WAIT ;
l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT ;
sppIndex = 0 ;
rfcomm_uuid_sign_idx = 0 ;
rfcomm_found = false ;
}
2014-04-21 18:41:39 +02:00
void SPPClient : : ACLData ( uint8_t * l2capinbuf ) {
2014-04-21 18:27:04 +02:00
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n Incoming Packet: " ) , 0x80 ) ;
for ( uint8_t i = 0 ; i < ( l2capinbuf [ 2 ] + 4 ) ; i + + ) {
D_PrintHex < uint8_t > ( l2capinbuf [ i ] , 0x80 ) ;
Notify ( PSTR ( " " ) , 0x80 ) ;
}
Notify ( PSTR ( " \r \n " ) , 0x80 ) ;
# endif
//if((l2capinbuf[0] | (uint16_t)l2capinbuf[1] << 8) == (hci_handle | 0x2000U)) { // acl_handle_ok
if ( UHS_ACL_HANDLE_OK ( l2capinbuf , hci_handle ) ) { // acl_handle_ok
if ( ( l2capinbuf [ 6 ] | ( l2capinbuf [ 7 ] < < 8 ) ) = = 0x0001U ) { // l2cap_control - Channel ID for ACL-U
if ( l2capinbuf [ 8 ] = = L2CAP_CMD_COMMAND_REJECT ) {
# 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 ( " Data: " ) , 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
} else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_CONNECTION_RESPONSE ) {
if ( ( ( l2capinbuf [ 16 ] | ( l2capinbuf [ 17 ] < < 8 ) ) = = 0x0000 ) & & ( ( l2capinbuf [ 18 ] | ( l2capinbuf [ 19 ] < < 8 ) ) = = SUCCESSFUL ) ) { // Success
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n L2CAP Connection Response " ) , 0x80 ) ;
# endif
if ( l2capinbuf [ 14 ] = = sdp_scid [ 0 ] & & l2capinbuf [ 15 ] = = sdp_scid [ 1 ] ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n SDP Connection Response " ) , 0x80 ) ;
# endif
sdp_dcid [ 0 ] = l2capinbuf [ 12 ] ;
sdp_dcid [ 1 ] = l2capinbuf [ 13 ] ;
identifier + + ;
l2cap_sdp_state = L2CAP_SDP_CONN_RESPONSE ;
} else if ( l2capinbuf [ 14 ] = = rfcomm_scid [ 0 ] & & l2capinbuf [ 15 ] = = rfcomm_scid [ 1 ] ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n RFComm Connection Response " ) , 0x80 ) ;
# endif
rfcomm_dcid [ 0 ] = l2capinbuf [ 12 ] ;
rfcomm_dcid [ 1 ] = l2capinbuf [ 13 ] ;
identifier + + ;
l2cap_rfcomm_state = L2CAP_RFCOMM_CONN_RESPONSE ;
}
}
} else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_CONFIG_RESPONSE ) {
if ( ( l2capinbuf [ 16 ] | ( l2capinbuf [ 17 ] < < 8 ) ) = = 0x0000 ) { // Success
if ( l2capinbuf [ 12 ] = = sdp_scid [ 0 ] & & l2capinbuf [ 13 ] = = sdp_scid [ 1 ] ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n SDP Configuration Response Received " ) , 0x80 ) ;
Notify ( PSTR ( " \r \n SDP Successfully Configured " ) , 0x80 ) ;
# endif
l2cap_sdp_state = L2CAP_SDP_SERVICE_SEARCH_ATTR1 ;
identifier + + ;
SDP_Service_Search_Attr ( 0 , identifier ) ;
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n SDP Service Search Attribute Request 1 Sent " ) , 0x80 ) ;
# endif
} else if ( l2capinbuf [ 12 ] = = rfcomm_scid [ 0 ] & & l2capinbuf [ 13 ] = = rfcomm_scid [ 1 ] ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n RFComm Configuration Response Received " ) , 0x80 ) ;
Notify ( PSTR ( " \r \n RFComm Successfully Configured " ) , 0x80 ) ;
# endif
l2cap_sdp_state = L2CAP_RFCOMM_DONE ;
identifier + + ;
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n RFComm SABM Sent " ) , 0x80 ) ;
# endif
rfcommAvailable = 0 ; // Reset number of bytes available
bytesRead = 0 ; // Reset number of bytes received
RFCOMMConnected = true ;
// channel direction, CR,channelType, pfBit, data, length
sendRfcomm ( 0 , 0 , ( 1 < < 1 ) , RFCOMM_SABM , ( 1 < < 4 ) , rfcommbuf , 0 ) ;
}
}
} else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_CONFIG_REQUEST ) {
if ( l2capinbuf [ 12 ] = = sdp_scid [ 0 ] & & l2capinbuf [ 13 ] = = sdp_scid [ 1 ] ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n SDP Configuration Request Received " ) , 0x80 ) ;
# endif
identifier = l2capinbuf [ 9 ] ;
pBtd - > l2cap_config_response ( hci_handle , identifier , sdp_dcid ) ;
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n SDP Configuration Response Sent " ) , 0x80 ) ;
# endif
l2cap_sdp_state = L2CAP_SDP_CONFIG_REQUEST ;
identifier + + ;
delay ( 1 ) ;
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n SDP Configuration Request Sent " ) , 0x80 ) ;
# endif
pBtd - > l2cap_config_request ( hci_handle , identifier , sdp_dcid ) ;
} else if ( l2capinbuf [ 12 ] = = rfcomm_scid [ 0 ] & & l2capinbuf [ 13 ] = = rfcomm_scid [ 1 ] ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n RFComm Configuration Request Received " ) , 0x80 ) ;
# endif
identifier = l2capinbuf [ 9 ] ;
pBtd - > l2cap_config_response ( hci_handle , identifier , rfcomm_dcid ) ;
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n RFComm Configuration Response Sent " ) , 0x80 ) ;
# endif
l2cap_rfcomm_state = L2CAP_RFCOMM_CONFIG_REQUEST ;
identifier + + ;
delay ( 1 ) ;
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n RFComm Configuration Request Sent " ) , 0x80 ) ;
# endif
pBtd - > l2cap_config_request ( hci_handle , identifier , rfcomm_dcid ) ;
}
} else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_DISCONNECT_REQUEST ) {
if ( l2capinbuf [ 12 ] = = sdp_scid [ 0 ] & & l2capinbuf [ 13 ] = = sdp_scid [ 1 ] ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Disconnect Request: SDP Channel " ) , 0x80 ) ;
# endif
identifier = l2capinbuf [ 9 ] ;
SDPConnected = false ;
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Disconnected SDP Channel " ) , 0x80 ) ;
# endif
pBtd - > l2cap_disconnection_response ( hci_handle , identifier , sdp_scid , sdp_dcid ) ;
l2cap_sdp_state = L2CAP_SDP_WAIT ;
} else if ( l2capinbuf [ 12 ] = = rfcomm_scid [ 0 ] & & l2capinbuf [ 13 ] = = rfcomm_scid [ 1 ] ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Disconnect Request: RFComm Channel " ) , 0x80 ) ;
# endif
identifier = l2capinbuf [ 9 ] ;
RFCOMMConnected = false ;
connected = false ;
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Disconnected RFComm Channel " ) , 0x80 ) ;
# endif
pBtd - > l2cap_disconnection_response ( hci_handle , identifier , rfcomm_dcid , rfcomm_scid ) ;
l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT ;
}
} else if ( l2capinbuf [ 8 ] = = L2CAP_CMD_DISCONNECT_RESPONSE ) {
if ( l2capinbuf [ 12 ] = = sdp_dcid [ 0 ] & & l2capinbuf [ 13 ] = = sdp_dcid [ 1 ] ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Disconnect Response: SDP Channel " ) , 0x80 ) ;
# endif
SDPConnected = false ;
l2cap_sdp_state = L2CAP_SDP_WAIT ;
} else if ( l2capinbuf [ 12 ] = = rfcomm_dcid [ 0 ] & & l2capinbuf [ 13 ] = = rfcomm_dcid [ 1 ] ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Disconnect Response: RFComm Channel " ) , 0x80 ) ;
Notify ( PSTR ( " \r \n Disconnected L2CAP Connection " ) , 0x80 ) ;
# endif
RFCOMMConnected = false ;
pBtd - > hci_disconnect ( hci_handle ) ;
hci_handle = - 1 ; // Reset handle
l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT ;
}
} 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 ] ) ;
}
else {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n L2CAP Unknown Signaling Command: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 8 ] , 0x80 ) ;
# endif
}
} else if ( l2capinbuf [ 6 ] = = sdp_scid [ 0 ] & & l2capinbuf [ 7 ] = = sdp_scid [ 1 ] ) { // SDP
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n SDP data: " ) , 0x80 ) ;
# endif
if ( l2capinbuf [ 8 ] = = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU ) {
if ( l2cap_sdp_state = = L2CAP_SDP_SERVICE_SEARCH_ATTR1 ) {
# ifdef EXTRADEBUG
Notify ( PSTR ( " - SDP Service Search Attribute Response 1: " ) , 0x80 ) ;
# endif
remainingBytes = l2capinbuf [ l2capinbuf [ 2 ] + 3 ] ;
parseAttrReply ( l2capinbuf ) ;
l2cap_sdp_state = L2CAP_SDP_SERVICE_SEARCH_ATTR2 ;
identifier + + ;
if ( remainingBytes ) {
SDP_Service_Search_Attr ( 0 , identifier , remainingBytes ) ;
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n SDP Service Search Attribute Request 2 Sent " ) , 0x80 ) ;
# endif
} else {
l2cap_sdp_state = L2CAP_SDP_DONE ;
if ( rfcomm_found ) {
pBtd - > l2cap_connection_request ( hci_handle , identifier , rfcomm_scid , RFCOMM_PSM ) ;
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n RFComm Connection Request Sent " ) , 0x80 ) ;
# endif
l2cap_rfcomm_state = L2CAP_RFCOMM_REQUEST ;
} else {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n RFComm Channel Number not found " ) , 0x80 ) ;
# endif
}
}
} else if ( l2cap_sdp_state = = L2CAP_SDP_SERVICE_SEARCH_ATTR2 ) {
# ifdef EXTRADEBUG
Notify ( PSTR ( " - SDP Service Search Attribute Response 2: " ) , 0x80 ) ;
# endif
parseAttrReply ( l2capinbuf ) ;
l2cap_sdp_state = L2CAP_SDP_DONE ;
identifier + + ;
if ( rfcomm_found ) {
pBtd - > l2cap_connection_request ( hci_handle , identifier , rfcomm_scid , RFCOMM_PSM ) ;
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n RFComm Connection Request Sent " ) , 0x80 ) ;
# endif
l2cap_rfcomm_state = L2CAP_RFCOMM_REQUEST ;
} else {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n RFComm Channel Number not found " ) , 0x80 ) ;
# endif
}
}
}
else {
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n Unknown PDU: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 8 ] , 0x80 ) ;
# endif
}
} else if ( l2capinbuf [ 6 ] = = rfcomm_scid [ 0 ] & & l2capinbuf [ 7 ] = = rfcomm_scid [ 1 ] ) { // RFCOMM
rfcommChannel = l2capinbuf [ 8 ] & 0xF8 ;
rfcommDirection = l2capinbuf [ 8 ] & 0x04 ;
rfcommCommandResponse = l2capinbuf [ 8 ] & 0x02 ;
rfcommChannelType = l2capinbuf [ 9 ] & 0xEF ;
rfcommPfBit = l2capinbuf [ 9 ] & 0x10 ;
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n RFComm Channel: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( rfcommChannel > > 3 , 0x80 ) ;
Notify ( PSTR ( " Direction: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( rfcommDirection > > 2 , 0x80 ) ;
Notify ( PSTR ( " CommandResponse: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( rfcommCommandResponse > > 1 , 0x80 ) ;
Notify ( PSTR ( " ChannelType: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( rfcommChannelType , 0x80 ) ;
Notify ( PSTR ( " PF_BIT: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( rfcommPfBit > > 4 , 0x80 ) ;
# endif
if ( rfcommChannelType = = RFCOMM_DISC ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Received Disconnect RFComm Command on channel: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( rfcommChannel , 0x80 ) ;
# endif
connected = false ;
// sendRfcomm(rfcommChannel, rfcommDirection, rfcommCommandResponse, RFCOMM_UA, rfcommPfBit, rfcommbuf, 0x00); // UA Command
}
if ( connected )
{
/* Read the incoming message */
if ( rfcommChannelType = = RFCOMM_UIH & & rfcommChannel = = ( rfcommChannelConnection < < 3 ) ) {
uint8_t length = l2capinbuf [ 10 ] > > 1 ; // Get length
uint8_t offset = l2capinbuf [ 4 ] - length - 4 ; // Check if there is credit
if ( checkFcs ( & l2capinbuf [ 8 ] , l2capinbuf [ 11 + length + offset ] ) ) {
uint8_t i = 0 ;
for ( ; i < length ; i + + ) {
if ( rfcommAvailable + i > = sizeof ( rfcommDataBuffer ) ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Warning: Buffer is full! " ) , 0x80 ) ;
# endif
break ;
}
rfcommDataBuffer [ rfcommAvailable + i ] = l2capinbuf [ 11 + i + offset ] ;
}
rfcommAvailable + = i ;
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n RFCOMM Data Available: " ) , 0x80 ) ;
Notify ( rfcommAvailable , 0x80 ) ;
if ( offset ) {
Notify ( PSTR ( " - Credit: 0x " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 11 ] , 0x80 ) ;
}
# endif
}
# ifdef DEBUG_USB_HOST
else
Notify ( PSTR ( " \r \n Error in FCS checksum! " ) , 0x80 ) ;
# endif
# ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send to the Arduino via Bluetooth
for ( uint8_t i = 0 ; i < length ; i + + )
Notifyc ( l2capinbuf [ i + 11 + offset ] , 0x80 ) ;
# endif
} else if ( rfcommChannelType = = RFCOMM_UIH & & l2capinbuf [ 11 ] = = BT_RFCOMM_RPN_CMD ) { // UIH Remote Port Negotiation Command
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Received UIH Remote Port Negotiation Command " ) , 0x80 ) ;
# endif
/* rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command
rfcommbuf [ 1 ] = l2capinbuf [ 12 ] ; // Length and shiftet like so: length << 1 | 1
rfcommbuf [ 2 ] = l2capinbuf [ 13 ] ; // Channel: channel << 1 | 1
rfcommbuf [ 3 ] = l2capinbuf [ 14 ] ; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
rfcommbuf [ 4 ] = l2capinbuf [ 15 ] ; // Priority
rfcommbuf [ 5 ] = l2capinbuf [ 16 ] ; // Timer
rfcommbuf [ 6 ] = l2capinbuf [ 17 ] ; // Max Fram Size LSB
rfcommbuf [ 7 ] = l2capinbuf [ 18 ] ; // Max Fram Size MSB
rfcommbuf [ 8 ] = l2capinbuf [ 19 ] ; // MaxRatransm.
rfcommbuf [ 9 ] = l2capinbuf [ 20 ] ; // Number of Frames
sendRfcomm ( rfcommChannel , rfcommDirection , 0 , RFCOMM_UIH , rfcommPfBit , rfcommbuf , 0x0A ) ; // UIH Remote Port Negotiation Response*/
} else if ( rfcommChannelType = = RFCOMM_UIH & & l2capinbuf [ 11 ] = = BT_RFCOMM_MSC_CMD ) { // UIH Modem Status Command
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Send UIH Modem Status Response " ) , 0x80 ) ;
# endif
/*rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response
rfcommbuf [ 1 ] = 2 < < 1 | 1 ; // Length and shiftet like so: length << 1 | 1
rfcommbuf [ 2 ] = l2capinbuf [ 13 ] ; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
rfcommbuf [ 3 ] = l2capinbuf [ 14 ] ;
sendRfcomm ( rfcommChannel , rfcommDirection , 0 , RFCOMM_UIH , rfcommPfBit , rfcommbuf , 0x04 ) ; */
}
} else {
if ( rfcommChannelType = = RFCOMM_SABM ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Received SAMB RFComm Packet on channel: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( rfcommChannel > > 3 , 0x80 ) ;
# endif
} else if ( rfcommChannelType = = RFCOMM_UA ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Received UA RFComm Packet on channel: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( rfcommChannel > > 3 , 0x80 ) ;
# endif
if ( ( rfcommChannel > > 3 ) = = 0 )
{
//Reply on 1-st SAMB command on channel 0
rfcommbuf [ 0 ] = BT_RFCOMM_PN_CMD ; // UIH Parameter Negotiation Request
rfcommbuf [ 1 ] = ( ( 8 < < 1 ) | 1 ) ; // Length and shiftet like so: length << 1 | 1
rfcommbuf [ 2 ] = ( ( 0x10 < < 1 ) ) ; // Channel: channel << 1 | 1 TODO: replace channel with variable
rfcommbuf [ 3 ] = 0xE0 ; // Pre defined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
rfcommbuf [ 4 ] = 0x00 ; // Priority
rfcommbuf [ 5 ] = 0x00 ; // Timer
rfcommbuf [ 6 ] = BULK_MAXPKTSIZE - 14 ; // Max Fram Size LSB - set to the size of received data (50)
rfcommbuf [ 7 ] = 0x00 ; // Max Fram Size MSB
rfcommbuf [ 8 ] = 0x00 ; // MaxRetransm.
rfcommbuf [ 9 ] = 0x00 ; // Number of Frames
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Sent UAH RFComm Cmd BT_RFCOMM_PN_CMD (Parameter Negotiation Request) on channel: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( rfcommChannel > > 3 , 0x80 ) ;
# endif
// channel direction, CR,channelType,pfBit, data, length
sendRfcomm ( 0 , 0 , ( 1 < < 1 ) , RFCOMM_UIH , 0 , rfcommbuf , 0x0A ) ;
} else {
//Reply on 2-nd SAMB command on channel 0
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Send UIH RFComm Cmd BT_RFCOMM_MSC_CMD (Modem Status Command) " ) , 0x80 ) ;
# endif
rfcommbuf [ 0 ] = BT_RFCOMM_MSC_CMD ; // UIH Modem Status Command
rfcommbuf [ 1 ] = 2 < < 1 | 1 ; // Length and shiftet like so: length << 1 | 1
rfcommbuf [ 2 ] = ( 1 < < 0 ) | ( 1 < < 1 ) | ( 0 < < 2 ) | ( rfcommChannelConnection < < 3 ) ; //0x83 // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
rfcommbuf [ 3 ] = 0x8D ; // Can receive frames (YES), Ready to Communicate (YES), Ready to Receive (YES), Incomig Call (NO), Data is Value (YES)
// channel direction, CR,channelType,pfBit, data, length
sendRfcomm ( 0 , 0 , ( 1 < < 1 ) , RFCOMM_UIH , 0 , rfcommbuf , 0x04 ) ;
}
} else if ( rfcommChannelType = = RFCOMM_UIH ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Received UIH RFComm Packet on channel: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( rfcommChannel > > 3 , 0x80 ) ;
# endif
if ( l2capinbuf [ 11 ] = = BT_RFCOMM_PN_RSP )
{
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " - BT_RFCOMM_PN_RSP (Parameter Negotiation Response) " ) , 0x80 ) ;
Notify ( PSTR ( " \r \n RFComm 2-nd SABM Sent " ) , 0x80 ) ;
# endif
// channel direction, CR,channelType, pfBit, data, length
sendRfcomm ( ( rfcommChannelConnection < < 3 ) , 0 , ( 1 < < 1 ) , RFCOMM_SABM , ( 1 < < 4 ) , rfcommbuf , 0 ) ;
} else if ( l2capinbuf [ 11 ] = = BT_RFCOMM_MSC_CMD )
{
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " - BT_RFCOMM_MSC_CMD (Modem Status Cmd) " ) , 0x80 ) ;
# endif
rfcommbuf [ 0 ] = BT_RFCOMM_MSC_RSP ; // UIH Modem Status Command
rfcommbuf [ 1 ] = 2 < < 1 | 1 ; // Length and shiftet like so: length << 1 | 1
rfcommbuf [ 2 ] = ( 1 < < 0 ) | ( 1 < < 1 ) | ( 0 < < 2 ) | ( rfcommChannelConnection < < 3 ) ; //0x83 // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
rfcommbuf [ 3 ] = 0x8D ; // Can receive frames (YES), Ready to Communicate (YES), Ready to Receive (YES), Incomig Call (NO), Data is Value (YES)
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Send UIH RFComm Cmd BT_RFCOMM_MSC_RSP (Modem Status Response) " ) , 0x80 ) ;
# endif
// channel direction, CR,channelType,pfBit, data, length
sendRfcomm ( 0 , 0 , ( 1 < < 1 ) , RFCOMM_UIH , 0 , rfcommbuf , 0x04 ) ;
} else if ( l2capinbuf [ 11 ] = = BT_RFCOMM_MSC_RSP )
{
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " - BT_RFCOMM_MSC_RSP (Modem Status Response) " ) , 0x80 ) ;
Notify ( PSTR ( " \r \n RFComm Cmd with Credit Sent " ) , 0x80 ) ;
# endif
sendRfcommCredit ( ( 0x10 < < 3 ) , 0 , ( 1 < < 1 ) , RFCOMM_UIH , 0x10 ,
sizeof ( rfcommDataBuffer ) ) ; // Send credit
connected = true ; // The RFCOMM channel is now established
sppIndex = 0 ;
} else if ( l2capinbuf [ 11 ] = = BT_RFCOMM_RPN_CMD )
{
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " - BT_RFCOMM_RPN_CMD (Remote Port Negotiation Cmd) " ) , 0x80 ) ;
# endif
//Just a stub. This command is optional according to the spec
} else if ( l2capinbuf [ 11 ] = = BT_RFCOMM_RPN_RSP )
{
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " - BT_RFCOMM_RPN_RSP (Remote Port Negotiation Response) " ) , 0x80 ) ;
# endif
//Just a stub. This command is optional according to the spec
} else
{
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " - Unknown Response: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 11 ] , 0x80 ) ;
# endif
}
} else if ( rfcommChannelType = = RFCOMM_DM ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Received DM RFComm Command on channel: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( rfcommChannel > > 3 , 0x80 ) ;
# endif
} else {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Unknown Response, rfCommChannelType: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( rfcommChannelType , 0x80 ) ;
# endif
}
}
} else {
# ifdef EXTRADEBUG
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 " ) , 0x80 ) ;
for ( uint8_t i = 0 ; i < BULK_MAXPKTSIZE ; i + + ) {
D_PrintHex < uint8_t > ( l2capinbuf [ i ] , 0x80 ) ;
Notify ( PSTR ( " " ) , 0x80 ) ;
}
# endif
}
} else {
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n Bad ACL handle: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 0 ] , 0x80 ) ;
Notify ( PSTR ( " " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( l2capinbuf [ 1 ] , 0x80 ) ;
Notify ( PSTR ( " " ) , 0x80 ) ;
# endif
}
}
2014-04-21 18:41:39 +02:00
void SPPClient : : Run ( ) {
2014-04-21 18:27:04 +02:00
if ( pBtd - > pairWithOtherDevice ) {
if ( l2cap_sdp_state = = L2CAP_SDP_WAIT ) {
if ( pBtd - > connectToOtherDevice & & ! pBtd - > l2capConnectionClaimed & & ! connected ) {
pBtd - > l2capConnectionClaimed = true ;
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n SDP Connection Request Sent " ) , 0x80 ) ;
# endif
hci_handle = pBtd - > hci_handle ; // Store the HCI Handle for the connection
identifier = 0 ;
pBtd - > l2cap_connection_request ( hci_handle , identifier , sdp_scid , SDP_PSM ) ;
l2cap_sdp_state = L2CAP_SDP_REQUEST ;
}
}
}
}
/************************************************************/
/* SDP Commands */
/************************************************************/
2014-04-21 18:41:39 +02:00
void SPPClient : : SDP_Command ( uint8_t * data , uint8_t nbytes ) { // See page 223 in the Bluetooth specs
2014-04-21 18:27:04 +02:00
pBtd - > L2CAP_Command ( hci_handle , data , nbytes , sdp_dcid [ 0 ] , sdp_dcid [ 1 ] ) ;
}
2014-04-21 18:41:39 +02:00
void SPPClient : : SDP_Service_Search_Attr ( uint8_t transactionIDHigh , uint8_t transactionIDLow , uint8_t remainingLen ) {
2014-04-21 18:27:04 +02:00
l2capoutbuf [ 0 ] = SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU ;
l2capoutbuf [ 1 ] = transactionIDHigh ;
l2capoutbuf [ 2 ] = transactionIDLow ;
l2capoutbuf [ 3 ] = 0x00 ; // Parameter Length
if ( remainingLen = = 0 )
l2capoutbuf [ 4 ] = 0x0F ; // Parameter Length
else
l2capoutbuf [ 4 ] = 0x11 ; // Parameter Length
l2capoutbuf [ 5 ] = 0x35 ; // Data Element Sequence, data size in next 8 bits
l2capoutbuf [ 6 ] = 0x03 ; // Data size
l2capoutbuf [ 7 ] = 0x19 ; // 00011 001 UUID, 2 bytes
l2capoutbuf [ 8 ] = 0x01 ;
l2capoutbuf [ 9 ] = 0x00 ; // 0x0100 - L2CAP_UUID
l2capoutbuf [ 10 ] = 0x00 ;
l2capoutbuf [ 11 ] = 0x26 ; // 0x0026 Maximum attribute byte count
l2capoutbuf [ 12 ] = 0x35 ; // Data Element Sequence, data size in next 8 bits
l2capoutbuf [ 13 ] = 0x05 ; // Data size
l2capoutbuf [ 14 ] = 0x0A ; // 00001 010 unsigned int, 4 bytes - Attribute ID range
l2capoutbuf [ 15 ] = 0x00 ;
l2capoutbuf [ 16 ] = 0x00 ; // range from 0x0000...
l2capoutbuf [ 17 ] = 0xFF ;
l2capoutbuf [ 18 ] = 0xFF ; // ... to 0xFFFF
if ( remainingLen = = 0 ) {
l2capoutbuf [ 19 ] = 0x00 ; // No more data
SDP_Command ( l2capoutbuf , 20 ) ;
} else {
l2capoutbuf [ 19 ] = 0x02 ;
l2capoutbuf [ 20 ] = 0x0 ; //will be 0 anyway
l2capoutbuf [ 21 ] = remainingLen ;
SDP_Command ( l2capoutbuf , 22 ) ;
}
}
/************************************************************/
/* RFCOMM Commands */
/************************************************************/
2014-04-21 18:41:39 +02:00
void SPPClient : : RFCOMM_Command ( uint8_t * data , uint8_t nbytes ) {
2014-04-21 18:27:04 +02:00
pBtd - > L2CAP_Command ( hci_handle , data , nbytes , rfcomm_dcid [ 0 ] , rfcomm_dcid [ 1 ] ) ;
}
2014-04-21 18:41:39 +02:00
void SPPClient : : parseAttrReply ( uint8_t * l2capinbuf ) {
2014-04-21 18:27:04 +02:00
if ( ( l2capinbuf [ 2 ] + 4 ) < 15 ) return ; // Sanity check
if ( rfcomm_found ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Channel is already found " ) , 0x80 ) ;
# endif
return ;
}
if ( rfcomm_uuid_sign_idx = = sizeof ( rfcomm_uuid_sign ) ) {
// Signature has been already found but channel is in next packet
rfcommChannelConnection = l2capinbuf [ 15 ] ;
rfcomm_found = true ;
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Channel found in second packet: " ) , 0x80 ) ;
Notify ( ( uint8_t ) rfcommChannelConnection , 0x80 ) ;
# endif
return ;
}
uint8_t nextSignBt ;
for ( uint8_t i = 15 ; i < ( l2capinbuf [ 2 ] + 4 ) ; i + + ) { // Searching through packet payload only
// Keep searching for signature
if ( l2capinbuf [ i ] = = pgm_read_byte ( & rfcomm_uuid_sign [ rfcomm_uuid_sign_idx ] ) ) {
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n Found match @ " ) , 0x80 ) ;
Notify ( ( uint8_t ) i , 0x80 ) ;
# endif
rfcomm_uuid_sign_idx + + ;
if ( rfcomm_uuid_sign_idx = = sizeof ( rfcomm_uuid_sign ) ) {
// Signature found, trying to get channel number
if ( l2capinbuf [ i + 1 ] = = 0x2 ) {
// Is the byte we are looking at the second last in the packet?
if ( ( l2capinbuf [ 2 ] + 1 ) = = ( i + 1 ) ) {
// Oh well, channel number didn't fit in this packet, waiting for next
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Channel will be in the next packet " ) , 0x80 ) ;
# endif
return ;
}
}
rfcommChannelConnection = l2capinbuf [ i + 1 ] ;
rfcomm_found = true ;
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Channel found in first packet: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( rfcommChannelConnection , 0x80 ) ;
# endif
return ;
}
} else if ( ( l2capinbuf [ i ] = = 0x2 ) & & ( i = = l2capinbuf [ 2 ] + 1 ) ) {
// This is an indication of packet end with more data to come in next packet - do not reset rfcomm_uuid_sign_idx, we will continue when next packet arrives
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n End of packet reached, no full signature yet " ) , 0x80 ) ;
# endif
return ;
} else {
// Otherwise the signature is not found - start over again
rfcomm_uuid_sign_idx = 0 ;
}
}
return ;
}