2012-08-04 12:20:47 +02:00
/* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
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 " ) .
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
Contact information
- - - - - - - - - - - - - - - - - - -
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
Kristian Lauszus , TKJ Electronics
Web : http : //www.tkjelectronics.com
e - mail : kristianl @ tkjelectronics . com
*/
# include "BTD.h"
2013-11-11 11:48:09 +01:00
// To enable serial debugging see "settings.h"
2012-08-04 12:20:47 +02:00
//#define EXTRADEBUG // Uncomment to get even more debugging data
2013-02-05 19:51:45 +01:00
const uint8_t BTD : : BTD_CONTROL_PIPE = 0 ;
2013-03-28 09:37:09 +01:00
const uint8_t BTD : : BTD_EVENT_PIPE = 1 ;
2012-08-04 12:20:47 +02:00
const uint8_t BTD : : BTD_DATAIN_PIPE = 2 ;
const uint8_t BTD : : BTD_DATAOUT_PIPE = 3 ;
2013-03-28 09:37:09 +01:00
BTD : : BTD ( USB * p ) :
2013-09-27 11:07:05 +02:00
connectToWii ( false ) ,
pairWithWii ( false ) ,
2012-08-04 12:20:47 +02:00
pUsb ( p ) , // Pointer to USB class instance - mandatory
bAddress ( 0 ) , // Device address - mandatory
bNumEP ( 1 ) , // If config descriptor needs to be parsed
qNextPollTime ( 0 ) , // Reset NextPollTime
2013-09-27 11:07:05 +02:00
pollInterval ( 0 ) ,
2012-08-04 12:20:47 +02:00
bPollEnable ( false ) // Don't start polling before dongle is connected
{
2013-10-07 00:47:53 +02:00
for ( uint8_t i = 0 ; i < BTD_NUMSERVICES ; i + + )
2013-09-27 21:39:38 +02:00
btService [ i ] = NULL ;
2013-09-27 11:07:05 +02:00
2013-10-07 00:47:53 +02:00
clearAllVariables ( ) ; // Set all variables, endpoint structs etc. to default values
if ( pUsb ) // Register in USB subsystem
pUsb - > RegisterDeviceClass ( this ) ; // Set devConfig[] entry
2012-08-04 12:20:47 +02:00
}
2013-10-07 00:47:53 +02:00
uint8_t BTD : : ConfigureDevice ( uint8_t parent , uint8_t port , bool lowspeed ) {
const uint8_t constBufSize = sizeof ( USB_DEVICE_DESCRIPTOR ) ;
uint8_t buf [ constBufSize ] ;
2013-03-28 09:37:09 +01:00
uint8_t rcode ;
UsbDevice * p = NULL ;
EpInfo * oldep_ptr = NULL ;
2013-10-07 00:47:53 +02:00
clearAllVariables ( ) ; // Set all variables, endpoint structs etc. to default values
AddressPool & addrPool = pUsb - > GetAddressPool ( ) ; // Get memory address of USB device address pool
2012-08-04 12:20:47 +02:00
# ifdef EXTRADEBUG
2013-10-07 00:47:53 +02:00
Notify ( PSTR ( " \r \n BTD ConfigureDevice " ) , 0x80 ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-10-07 00:47:53 +02:00
if ( bAddress ) { // Check if address has already been assigned to an instance
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Address in use " ) , 0x80 ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-03-28 09:37:09 +01:00
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE ;
}
2013-10-07 00:47:53 +02:00
p = addrPool . GetUsbDevicePtr ( 0 ) ; // Get pointer to pseudo device with address 0 assigned
2013-03-28 09:37:09 +01:00
if ( ! p ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Address not found " ) , 0x80 ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-03-28 09:37:09 +01:00
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL ;
}
if ( ! p - > epinfo ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n epinfo is null " ) , 0x80 ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-03-28 09:37:09 +01:00
return USB_ERROR_EPINFO_IS_NULL ;
}
2013-10-07 00:47:53 +02:00
oldep_ptr = p - > epinfo ; // Save old pointer to EP_RECORD of address 0
p - > epinfo = epInfo ; // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
2013-03-28 09:37:09 +01:00
p - > lowspeed = lowspeed ;
2013-10-07 00:47:53 +02:00
rcode = pUsb - > getDevDescr ( 0 , 0 , constBufSize , ( uint8_t * ) buf ) ; // Get device descriptor - addr, ep, nbytes, data
2013-03-28 09:37:09 +01:00
2013-10-07 00:47:53 +02:00
p - > epinfo = oldep_ptr ; // Restore p->epinfo
2013-03-28 09:37:09 +01:00
if ( rcode )
goto FailGetDevDescr ;
2013-10-07 00:47:53 +02:00
bAddress = addrPool . AllocAddress ( parent , false , port ) ; // Allocate new address according to device class
2013-03-28 09:37:09 +01:00
2013-10-07 00:47:53 +02:00
if ( ! bAddress ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Out of address space " ) , 0x80 ) ;
# endif
2013-03-28 09:37:09 +01:00
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL ;
2013-10-07 00:47:53 +02:00
}
epInfo [ 0 ] . maxPktSize = ( uint8_t ) ( ( USB_DEVICE_DESCRIPTOR * ) buf ) - > bMaxPacketSize0 ; // Extract Max Packet Size from device descriptor
epInfo [ 1 ] . epAddr = ( ( USB_DEVICE_DESCRIPTOR * ) buf ) - > bNumConfigurations ; // Steal and abuse from epInfo structure to save memory
2013-10-07 01:45:21 +02:00
VID = ( ( USB_DEVICE_DESCRIPTOR * ) buf ) - > idVendor ;
PID = ( ( USB_DEVICE_DESCRIPTOR * ) buf ) - > idProduct ;
2013-10-07 00:47:53 +02:00
return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET ;
FailGetDevDescr :
# ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr ( rcode ) ;
# endif
2013-10-08 19:51:20 +02:00
if ( rcode ! = hrJERR )
rcode = USB_ERROR_FailGetDevDescr ;
2013-10-07 00:47:53 +02:00
Release ( ) ;
return rcode ;
} ;
uint8_t BTD : : Init ( uint8_t parent , uint8_t port , bool lowspeed ) {
uint8_t rcode ;
uint8_t num_of_conf = epInfo [ 1 ] . epAddr ; // Number of configurations
epInfo [ 1 ] . epAddr = 0 ;
2013-03-28 09:37:09 +01:00
2013-10-07 00:47:53 +02:00
AddressPool & addrPool = pUsb - > GetAddressPool ( ) ;
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n BTD Init " ) , 0x80 ) ;
# endif
UsbDevice * p = addrPool . GetUsbDevicePtr ( bAddress ) ; // Get pointer to assigned address record
2013-03-28 09:37:09 +01:00
2013-10-07 00:47:53 +02:00
if ( ! p ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Address not found " ) , 0x80 ) ;
# endif
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL ;
}
delay ( 300 ) ; // Assign new address to the device
rcode = pUsb - > setAddr ( 0 , 0 , bAddress ) ; // Assign new address to the device
2013-03-28 09:37:09 +01:00
if ( rcode ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n setAddr: " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( rcode , 0x80 ) ;
2013-07-15 19:34:56 +02:00
# endif
2013-10-07 00:47:53 +02:00
p - > lowspeed = false ;
2013-09-06 00:22:00 +02:00
goto Fail ;
2013-03-28 09:37:09 +01:00
}
2012-08-04 12:20:47 +02:00
# ifdef EXTRADEBUG
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Addr: " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( bAddress , 0x80 ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-07-15 19:34:56 +02:00
2013-03-28 09:37:09 +01:00
p - > lowspeed = false ;
2013-10-07 00:47:53 +02:00
p = addrPool . GetUsbDevicePtr ( bAddress ) ; // Get pointer to assigned address record
if ( ! p ) {
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Address not found " ) , 0x80 ) ;
# endif
2013-03-28 09:37:09 +01:00
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL ;
2013-10-07 00:47:53 +02:00
}
2013-03-28 09:37:09 +01:00
p - > lowspeed = lowspeed ;
2013-10-07 00:47:53 +02:00
rcode = pUsb - > setEpInfoEntry ( bAddress , 1 , epInfo ) ; // Assign epInfo to epinfo pointer - only EP0 is known
2013-03-28 09:37:09 +01:00
if ( rcode )
goto FailSetDevTblEntry ;
2013-10-07 00:47:53 +02:00
2013-03-28 09:37:09 +01:00
if ( VID = = PS3_VID & & ( PID = = PS3_PID | | PID = = PS3NAVIGATION_PID | | PID = = PS3MOVE_PID ) ) {
2013-10-21 17:36:42 +02:00
delay ( 100 ) ;
2013-10-07 00:47:53 +02:00
rcode = pUsb - > setConf ( bAddress , epInfo [ BTD_CONTROL_PIPE ] . epAddr , 1 ) ; // We only need the Control endpoint, so we don't have to initialize the other endpoints of device
2013-03-28 09:37:09 +01:00
if ( rcode )
2013-03-30 15:29:16 +01:00
goto FailSetConfDescr ;
2013-03-28 09:37:09 +01:00
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-05-14 00:47:05 +02:00
if ( PID = = PS3_PID | | PID = = PS3NAVIGATION_PID ) {
2013-03-28 09:37:09 +01:00
if ( PID = = PS3_PID )
Notify ( PSTR ( " \r \n Dualshock 3 Controller Connected " ) , 0x80 ) ;
2013-05-14 00:47:05 +02:00
else // It must be a navigation controller
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Navigation Controller Connected " ) , 0x80 ) ;
2013-05-14 00:47:05 +02:00
} else // It must be a Motion controller
Notify ( PSTR ( " \r \n Motion Controller Connected " ) , 0x80 ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-05-14 00:47:05 +02:00
if ( my_bdaddr [ 0 ] = = 0x00 & & my_bdaddr [ 1 ] = = 0x00 & & my_bdaddr [ 2 ] = = 0x00 & & my_bdaddr [ 3 ] = = 0x00 & & my_bdaddr [ 4 ] = = 0x00 & & my_bdaddr [ 5 ] = = 0x00 ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-09-12 22:24:48 +02:00
Notify ( PSTR ( " \r \n Please plug in the dongle before trying to pair with the PS3 Controller \r \n or set the Bluetooth address in the constructor of the PS3BT class " ) , 0x80 ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-05-14 00:47:05 +02:00
} else {
if ( PID = = PS3_PID | | PID = = PS3NAVIGATION_PID )
setBdaddr ( my_bdaddr ) ; // Set internal Bluetooth address
else
setMoveBdaddr ( my_bdaddr ) ; // Set internal Bluetooth address
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-05-14 00:47:05 +02:00
Notify ( PSTR ( " \r \n Bluetooth Address was set to: " ) , 0x80 ) ;
for ( int8_t i = 5 ; i > 0 ; i - - ) {
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( my_bdaddr [ i ] , 0x80 ) ;
2013-05-14 00:47:05 +02:00
Notify ( PSTR ( " : " ) , 0x80 ) ;
}
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( my_bdaddr [ 0 ] , 0x80 ) ;
2013-04-02 00:10:02 +02:00
# endif
2013-05-14 00:47:05 +02:00
}
2013-09-06 00:22:00 +02:00
pUsb - > setConf ( bAddress , epInfo [ BTD_CONTROL_PIPE ] . epAddr , 0 ) ; // Reset configuration value
2013-09-12 22:12:13 +02:00
pUsb - > setAddr ( bAddress , 0 , 0 ) ; // Reset address
Release ( ) ; // Release device
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED ; // Return
2013-03-28 09:37:09 +01:00
} else {
2013-05-14 00:47:05 +02:00
// Check if attached device is a Bluetooth dongle and fill endpoint data structure
// First interface in the configuration must have Bluetooth assigned Class/Subclass/Protocol
// And 3 endpoints - interrupt-IN, bulk-IN, bulk-OUT, not necessarily in this order
2013-03-28 09:37:09 +01:00
for ( uint8_t i = 0 ; i < num_of_conf ; i + + ) {
2013-08-14 00:43:15 +02:00
if ( VID = = IOGEAR_GBU521_VID & & PID = = IOGEAR_GBU521_PID ) {
ConfigDescParser < USB_CLASS_VENDOR_SPECIFIC , WI_SUBCLASS_RF , WI_PROTOCOL_BT , CP_MASK_COMPARE_ALL > confDescrParser ( this ) ; // Needed for the IOGEAR GBU521
rcode = pUsb - > getConfDescr ( bAddress , 0 , i , & confDescrParser ) ;
} else {
ConfigDescParser < USB_CLASS_WIRELESS_CTRL , WI_SUBCLASS_RF , WI_PROTOCOL_BT , CP_MASK_COMPARE_ALL > confDescrParser ( this ) ;
rcode = pUsb - > getConfDescr ( bAddress , 0 , i , & confDescrParser ) ;
}
if ( rcode ) // Check error code
2013-03-28 09:37:09 +01:00
goto FailGetConfDescr ;
if ( bNumEP > = BTD_MAX_ENDPOINTS ) // All endpoints extracted
break ;
}
2013-08-14 00:43:15 +02:00
if ( bNumEP < BTD_MAX_ENDPOINTS )
goto FailUnknownDevice ;
2013-03-28 09:37:09 +01:00
// Assign epInfo to epinfo pointer - this time all 3 endpoins
rcode = pUsb - > setEpInfoEntry ( bAddress , bNumEP , epInfo ) ;
if ( rcode )
goto FailSetDevTblEntry ;
// Set Configuration Value
rcode = pUsb - > setConf ( bAddress , epInfo [ BTD_CONTROL_PIPE ] . epAddr , bConfNum ) ;
if ( rcode )
2013-03-30 15:29:16 +01:00
goto FailSetConfDescr ;
2013-03-28 09:37:09 +01:00
hci_num_reset_loops = 100 ; // only loop 100 times before trying to send the hci reset command
hci_counter = 0 ;
hci_state = HCI_INIT_STATE ;
watingForConnection = false ;
bPollEnable = true ;
2012-08-04 12:20:47 +02:00
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Bluetooth Dongle Initialized " ) , 0x80 ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-03-28 09:37:09 +01:00
}
return 0 ; // Successful configuration
/* diagnostic messages */
2012-08-04 12:20:47 +02:00
FailGetDevDescr :
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-30 15:29:16 +01:00
NotifyFailGetDevDescr ( ) ;
2013-03-28 09:37:09 +01:00
goto Fail ;
2013-05-16 22:43:51 +02:00
# endif
2013-03-30 15:29:16 +01:00
2012-08-04 12:20:47 +02:00
FailSetDevTblEntry :
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-30 15:29:16 +01:00
NotifyFailSetDevTblEntry ( ) ;
2013-03-28 09:37:09 +01:00
goto Fail ;
2013-05-16 22:43:51 +02:00
# endif
2013-03-30 15:29:16 +01:00
2012-08-04 12:20:47 +02:00
FailGetConfDescr :
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-30 15:29:16 +01:00
NotifyFailGetConfDescr ( ) ;
2013-03-28 09:37:09 +01:00
goto Fail ;
2013-05-16 22:43:51 +02:00
# endif
2013-03-30 15:29:16 +01:00
FailSetConfDescr :
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-30 15:29:16 +01:00
NotifyFailSetConfDescr ( ) ;
2013-05-16 22:43:51 +02:00
# endif
2013-03-28 09:37:09 +01:00
goto Fail ;
2013-03-30 15:29:16 +01:00
2013-04-01 03:06:49 +02:00
FailUnknownDevice :
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-05-16 22:43:51 +02:00
NotifyFailUnknownDevice ( VID , PID ) ;
# endif
2013-03-28 09:37:09 +01:00
pUsb - > setAddr ( bAddress , 0 , 0 ) ; // Reset address
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED ;
2012-08-04 12:20:47 +02:00
Fail :
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n BTD Init Failed, error code: " ) , 0x80 ) ;
2013-03-30 15:29:16 +01:00
NotifyFail ( rcode ) ;
2013-05-16 22:43:51 +02:00
# endif
2013-03-28 09:37:09 +01:00
Release ( ) ;
return rcode ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2013-10-07 00:47:53 +02:00
void BTD : : clearAllVariables ( ) {
uint8_t i ;
for ( i = 0 ; i < BTD_MAX_ENDPOINTS ; i + + ) {
epInfo [ i ] . epAddr = 0 ;
epInfo [ i ] . maxPktSize = ( i ) ? 0 : 8 ;
epInfo [ i ] . epAttribs = 0 ;
epInfo [ i ] . bmNakPower = ( i ) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER ;
}
for ( i = 0 ; i < BTD_NUMSERVICES ; i + + ) {
if ( btService [ i ] )
btService [ i ] - > Reset ( ) ; // Reset all Bluetooth services
}
connectToWii = false ;
2013-10-08 18:52:37 +02:00
incomingWii = false ;
2013-10-07 00:47:53 +02:00
bAddress = 0 ; // Clear device address
bNumEP = 1 ; // Must have to be reset to 1
qNextPollTime = 0 ; // Reset next poll time
pollInterval = 0 ;
bPollEnable = false ; // Don't start polling before dongle is connected
}
2012-08-04 12:20:47 +02:00
/* Extracts interrupt-IN, bulk-IN, bulk-OUT endpoint information from config descriptor */
void BTD : : EndpointXtract ( uint8_t conf , uint8_t iface , uint8_t alt , uint8_t proto , const USB_ENDPOINT_DESCRIPTOR * pep ) {
2013-03-28 09:37:09 +01:00
//ErrorMessage<uint8_t>(PSTR("Conf.Val"),conf);
//ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
//ErrorMessage<uint8_t>(PSTR("Alt.Set"),alt);
2013-05-14 00:47:05 +02:00
if ( alt ) // Wrong interface - by BT spec, no alt setting
2013-03-28 09:37:09 +01:00
return ;
bConfNum = conf ;
uint8_t index ;
2013-06-12 05:11:43 +02:00
if ( ( pep - > bmAttributes & 0x03 ) = = 3 & & ( pep - > bEndpointAddress & 0x80 ) = = 0x80 ) { // Interrupt In endpoint found
2013-03-28 09:37:09 +01:00
index = BTD_EVENT_PIPE ;
2013-06-12 05:11:43 +02:00
epInfo [ index ] . bmNakPower = USB_NAK_NOWAIT ;
} else {
2013-05-14 00:47:05 +02:00
if ( ( pep - > bmAttributes & 0x02 ) = = 2 ) // Bulk endpoint found
2013-03-28 09:37:09 +01:00
index = ( ( pep - > bEndpointAddress & 0x80 ) = = 0x80 ) ? BTD_DATAIN_PIPE : BTD_DATAOUT_PIPE ;
else
return ;
}
// Fill the rest of endpoint data structure
epInfo [ index ] . epAddr = ( pep - > bEndpointAddress & 0x0F ) ;
epInfo [ index ] . maxPktSize = ( uint8_t ) pep - > wMaxPacketSize ;
2012-08-04 12:20:47 +02:00
# ifdef EXTRADEBUG
2013-03-28 09:37:09 +01:00
PrintEndpointDescriptor ( pep ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-03-28 09:37:09 +01:00
if ( pollInterval < pep - > bInterval ) // Set the polling interval as the largest polling interval obtained from endpoints
pollInterval = pep - > bInterval ;
bNumEP + + ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
void BTD : : PrintEndpointDescriptor ( const USB_ENDPOINT_DESCRIPTOR * ep_ptr ) {
2013-01-19 15:43:28 +01:00
# ifdef EXTRADEBUG
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Endpoint descriptor: " ) , 0x80 ) ;
Notify ( PSTR ( " \r \n Length: \t \t " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( ep_ptr - > bLength , 0x80 ) ;
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Type: \t \t " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( ep_ptr - > bDescriptorType , 0x80 ) ;
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Address: \t " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( ep_ptr - > bEndpointAddress , 0x80 ) ;
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Attributes: \t " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( ep_ptr - > bmAttributes , 0x80 ) ;
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n MaxPktSize: \t " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint16_t > ( ep_ptr - > wMaxPacketSize , 0x80 ) ;
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Poll Intrv: \t " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( ep_ptr - > bInterval , 0x80 ) ;
2013-01-19 15:43:28 +01:00
# endif
2012-08-04 12:20:47 +02:00
}
/* Performs a cleanup after failed Init() attempt */
uint8_t BTD : : Release ( ) {
2013-10-07 00:47:53 +02:00
clearAllVariables ( ) ; // Set all variables, endpoint structs etc. to default values
2013-03-28 09:37:09 +01:00
pUsb - > GetAddressPool ( ) . FreeAddress ( bAddress ) ;
return 0 ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
uint8_t BTD : : Poll ( ) {
2013-03-28 09:37:09 +01:00
if ( ! bPollEnable )
return 0 ;
if ( qNextPollTime < = millis ( ) ) { // Don't poll if shorter than polling interval
qNextPollTime = millis ( ) + pollInterval ; // Set new poll time
HCI_event_task ( ) ; // poll the HCI event pipe
ACL_event_task ( ) ; // start polling the ACL input pipe too, though discard data until connected
}
return 0 ;
2012-08-04 12:20:47 +02:00
}
void BTD : : HCI_event_task ( ) {
2013-03-28 09:37:09 +01:00
/* check the event pipe*/
uint16_t MAX_BUFFER_SIZE = BULK_MAXPKTSIZE ; // Request more than 16 bytes anyway, the inTransfer routine will take care of this
uint8_t rcode = pUsb - > inTransfer ( bAddress , epInfo [ BTD_EVENT_PIPE ] . epAddr , & MAX_BUFFER_SIZE , hcibuf ) ; // input on endpoint 1
2013-08-02 14:24:06 +02:00
if ( ! rcode | | rcode = = hrNAK ) // Check for errors
2012-08-04 12:20:47 +02:00
{
2013-03-28 09:37:09 +01:00
switch ( hcibuf [ 0 ] ) //switch on event type
{
case EV_COMMAND_COMPLETE :
if ( ! hcibuf [ 5 ] ) { // Check if command succeeded
hci_event_flag | = HCI_FLAG_CMD_COMPLETE ; // set command complete flag
if ( ( hcibuf [ 3 ] = = 0x01 ) & & ( hcibuf [ 4 ] = = 0x10 ) ) { // parameters from read local version information
hci_version = hcibuf [ 6 ] ; // Used to check if it supports 2.0+EDR - see http://www.bluetooth.org/Technical/AssignedNumbers/hci.htm
hci_event_flag | = HCI_FLAG_READ_VERSION ;
} else if ( ( hcibuf [ 3 ] = = 0x09 ) & & ( hcibuf [ 4 ] = = 0x10 ) ) { // parameters from read local bluetooth address
for ( uint8_t i = 0 ; i < 6 ; i + + )
my_bdaddr [ i ] = hcibuf [ 6 + i ] ;
hci_event_flag | = HCI_FLAG_READ_BDADDR ;
}
}
break ;
case EV_COMMAND_STATUS :
2013-11-12 19:38:18 +01:00
if ( hcibuf [ 2 ] ) { // Show status on serial if not OK
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n HCI Command Failed: " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( hcibuf [ 2 ] , 0x80 ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-03-28 09:37:09 +01:00
}
break ;
case EV_INQUIRY_COMPLETE :
2013-10-08 18:52:37 +02:00
if ( inquiry_counter > = 5 & & pairWithWii ) {
2013-03-28 09:37:09 +01:00
inquiry_counter = 0 ;
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Couldn't find Wiimote " ) , 0x80 ) ;
2012-10-08 15:32:42 +02:00
# endif
2013-03-28 09:37:09 +01:00
connectToWii = false ;
pairWithWii = false ;
hci_state = HCI_SCANNING_STATE ;
}
inquiry_counter + + ;
break ;
case EV_INQUIRY_RESULT :
if ( hcibuf [ 2 ] ) { // Check that there is more than zero responses
2012-08-21 14:31:11 +02:00
# ifdef EXTRADEBUG
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Number of responses: " ) , 0x80 ) ;
2013-04-26 23:50:39 +02:00
Notify ( hcibuf [ 2 ] , 0x80 ) ;
2012-08-21 14:31:11 +02:00
# endif
2013-03-28 09:37:09 +01:00
for ( uint8_t i = 0 ; i < hcibuf [ 2 ] ; i + + ) {
if ( ( hcibuf [ 4 + 8 * hcibuf [ 2 ] + 3 * i ] = = 0x04 & & hcibuf [ 5 + 8 * hcibuf [ 2 ] + 3 * i ] = = 0x25 & & hcibuf [ 6 + 8 * hcibuf [ 2 ] + 3 * i ] = = 0x00 ) | | ( hcibuf [ 4 + 8 * hcibuf [ 2 ] + 3 * i ] = = 0x08 & & hcibuf [ 5 + 8 * hcibuf [ 2 ] + 3 * i ] = = 0x05 & & hcibuf [ 6 + 8 * hcibuf [ 2 ] + 3 * i ] = = 0x00 ) ) { // See http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html and http://wiibrew.org/wiki/Wiimote#SDP_information
if ( hcibuf [ 4 + 8 * hcibuf [ 2 ] + 3 * i ] = = 0x08 ) // Check if it's the new Wiimote with motion plus inside that was detected
motionPlusInside = true ;
else
motionPlusInside = false ;
disc_bdaddr [ 0 ] = hcibuf [ 3 + 6 * i ] ;
disc_bdaddr [ 1 ] = hcibuf [ 4 + 6 * i ] ;
disc_bdaddr [ 2 ] = hcibuf [ 5 + 6 * i ] ;
disc_bdaddr [ 3 ] = hcibuf [ 6 + 6 * i ] ;
disc_bdaddr [ 4 ] = hcibuf [ 7 + 6 * i ] ;
disc_bdaddr [ 5 ] = hcibuf [ 8 + 6 * i ] ;
hci_event_flag | = HCI_FLAG_WII_FOUND ;
break ;
}
2012-08-21 14:31:11 +02:00
# ifdef EXTRADEBUG
2013-03-28 09:37:09 +01:00
else {
Notify ( PSTR ( " \r \n Class of device: " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( hcibuf [ 6 + 8 * hcibuf [ 2 ] + 3 * i ] , 0x80 ) ;
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( hcibuf [ 5 + 8 * hcibuf [ 2 ] + 3 * i ] , 0x80 ) ;
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( hcibuf [ 4 + 8 * hcibuf [ 2 ] + 3 * i ] , 0x80 ) ;
2013-03-28 09:37:09 +01:00
}
2012-08-21 14:31:11 +02:00
# endif
2013-03-28 09:37:09 +01:00
}
}
break ;
case EV_CONNECT_COMPLETE :
hci_event_flag | = HCI_FLAG_CONNECT_EVENT ;
if ( ! hcibuf [ 2 ] ) { // check if connected OK
2013-11-15 23:31:05 +01:00
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n Connection established " ) , 0x80 ) ;
# endif
2013-03-28 09:37:09 +01:00
hci_handle = hcibuf [ 3 ] | ( ( hcibuf [ 4 ] & 0x0F ) < < 8 ) ; // store the handle for the ACL connection
hci_event_flag | = HCI_FLAG_CONN_COMPLETE ; // set connection complete flag
2013-11-12 19:38:18 +01:00
} else {
2013-04-01 03:06:49 +02:00
hci_state = HCI_CHECK_WII_SERVICE ;
2013-11-12 19:38:18 +01:00
# ifdef DEBUG_USB_HOST
Notify ( PSTR ( " \r \n Connection Failed: " ) , 0x80 ) ;
D_PrintHex < uint8_t > ( hcibuf [ 2 ] , 0x80 ) ;
2012-08-21 14:31:11 +02:00
# endif
2013-11-12 19:38:18 +01:00
}
2013-03-28 09:37:09 +01:00
break ;
case EV_DISCONNECT_COMPLETE :
if ( ! hcibuf [ 2 ] ) { // check if disconnected OK
hci_event_flag | = HCI_FLAG_DISCONN_COMPLETE ; // set disconnect command complete flag
hci_event_flag & = ~ HCI_FLAG_CONN_COMPLETE ; // clear connection complete flag
}
break ;
case EV_REMOTE_NAME_COMPLETE :
if ( ! hcibuf [ 2 ] ) { // check if reading is OK
2013-05-16 22:43:51 +02:00
for ( uint8_t i = 0 ; i < min ( sizeof ( remote_name ) , sizeof ( hcibuf ) - 9 ) ; i + + )
2013-04-01 03:06:49 +02:00
remote_name [ i ] = hcibuf [ 9 + i ] ;
2013-03-28 09:37:09 +01:00
hci_event_flag | = HCI_FLAG_REMOTE_NAME_COMPLETE ;
}
break ;
case EV_INCOMING_CONNECT :
disc_bdaddr [ 0 ] = hcibuf [ 2 ] ;
disc_bdaddr [ 1 ] = hcibuf [ 3 ] ;
disc_bdaddr [ 2 ] = hcibuf [ 4 ] ;
disc_bdaddr [ 3 ] = hcibuf [ 5 ] ;
disc_bdaddr [ 4 ] = hcibuf [ 6 ] ;
disc_bdaddr [ 5 ] = hcibuf [ 7 ] ;
2013-04-01 03:06:49 +02:00
# ifdef EXTRADEBUG
Notify ( PSTR ( " \r \n Class of device: " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( hcibuf [ 10 ] , 0x80 ) ;
2013-04-01 03:06:49 +02:00
Notify ( PSTR ( " " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( hcibuf [ 9 ] , 0x80 ) ;
2013-04-01 03:06:49 +02:00
Notify ( PSTR ( " " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( hcibuf [ 8 ] , 0x80 ) ;
2013-04-01 03:06:49 +02:00
# endif
2013-03-28 09:37:09 +01:00
hci_event_flag | = HCI_FLAG_INCOMING_REQUEST ;
break ;
case EV_PIN_CODE_REQUEST :
if ( pairWithWii ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Pairing with wiimote " ) , 0x80 ) ;
2012-10-07 14:50:51 +02:00
# endif
2013-03-28 09:37:09 +01:00
hci_pin_code_request_reply ( ) ;
} else if ( btdPin ! = NULL ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Bluetooth pin is set too: " ) , 0x80 ) ;
2013-04-26 23:50:39 +02:00
NotifyStr ( btdPin , 0x80 ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-03-28 09:37:09 +01:00
hci_pin_code_request_reply ( ) ;
} else {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n No pin was set " ) , 0x80 ) ;
2012-08-09 20:22:11 +02:00
# endif
2013-03-28 09:37:09 +01:00
hci_pin_code_negative_request_reply ( ) ;
}
break ;
case EV_LINK_KEY_REQUEST :
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Received Key Request " ) , 0x80 ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-03-28 09:37:09 +01:00
hci_link_key_request_negative_reply ( ) ;
break ;
case EV_AUTHENTICATION_COMPLETE :
if ( pairWithWii & & ! connectToWii ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Pairing successful " ) , 0x80 ) ;
2012-10-07 14:50:51 +02:00
# endif
2013-03-28 09:37:09 +01:00
connectToWii = true ; // Only send the ACL data to the Wii service
}
break ;
/* We will just ignore the following events */
case EV_NUM_COMPLETE_PKT :
case EV_ROLE_CHANGED :
case EV_PAGE_SCAN_REP_MODE :
case EV_LOOPBACK_COMMAND :
case EV_DATA_BUFFER_OVERFLOW :
case EV_CHANGE_CONNECTION_LINK :
case EV_MAX_SLOTS_CHANGE :
case EV_QOS_SETUP_COMPLETE :
case EV_LINK_KEY_NOTIFICATION :
case EV_ENCRYPTION_CHANGE :
case EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE :
break ;
2012-10-07 15:22:29 +02:00
# ifdef EXTRADEBUG
2013-03-28 09:37:09 +01:00
default :
if ( hcibuf [ 0 ] ! = 0x00 ) {
Notify ( PSTR ( " \r \n Unmanaged HCI Event: " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( hcibuf [ 0 ] , 0x80 ) ;
2013-03-28 09:37:09 +01:00
}
break ;
2012-08-04 12:20:47 +02:00
# endif
2013-03-28 09:37:09 +01:00
} // switch
}
2012-08-04 12:20:47 +02:00
# ifdef EXTRADEBUG
2013-08-02 14:24:06 +02:00
else {
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n HCI event error: " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( rcode , 0x80 ) ;
2013-03-28 09:37:09 +01:00
}
2012-08-09 21:22:55 +02:00
# endif
2013-04-01 03:06:49 +02:00
HCI_task ( ) ;
2012-08-04 12:20:47 +02:00
}
/* Poll Bluetooth and print result */
void BTD : : HCI_task ( ) {
2013-03-28 09:37:09 +01:00
switch ( hci_state ) {
case HCI_INIT_STATE :
hci_counter + + ;
if ( hci_counter > hci_num_reset_loops ) { // wait until we have looped x times to clear any old events
hci_reset ( ) ;
hci_state = HCI_RESET_STATE ;
hci_counter = 0 ;
}
break ;
case HCI_RESET_STATE :
hci_counter + + ;
if ( hci_cmd_complete ) {
hci_counter = 0 ;
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n HCI Reset complete " ) , 0x80 ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-03-28 09:37:09 +01:00
hci_state = HCI_CLASS_STATE ;
hci_write_class_of_device ( ) ;
} else if ( hci_counter > hci_num_reset_loops ) {
hci_num_reset_loops * = 10 ;
if ( hci_num_reset_loops > 2000 )
hci_num_reset_loops = 2000 ;
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n No response to HCI Reset " ) , 0x80 ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-03-28 09:37:09 +01:00
hci_state = HCI_INIT_STATE ;
hci_counter = 0 ;
}
break ;
2013-03-14 23:40:52 +01:00
2013-03-28 09:37:09 +01:00
case HCI_CLASS_STATE :
if ( hci_cmd_complete ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Write class of device " ) , 0x80 ) ;
2013-03-14 23:40:52 +01:00
# endif
2013-03-28 09:37:09 +01:00
hci_state = HCI_BDADDR_STATE ;
hci_read_bdaddr ( ) ;
}
break ;
case HCI_BDADDR_STATE :
if ( hci_read_bdaddr_complete ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Local Bluetooth Address: " ) , 0x80 ) ;
for ( int8_t i = 5 ; i > 0 ; i - - ) {
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( my_bdaddr [ i ] , 0x80 ) ;
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " : " ) , 0x80 ) ;
}
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( my_bdaddr [ 0 ] , 0x80 ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-03-28 09:37:09 +01:00
hci_read_local_version_information ( ) ;
hci_state = HCI_LOCAL_VERSION_STATE ;
}
break ;
case HCI_LOCAL_VERSION_STATE : // The local version is used by the PS3BT class
if ( hci_read_version_complete ) {
if ( btdName ! = NULL ) {
hci_set_local_name ( btdName ) ;
hci_state = HCI_SET_NAME_STATE ;
} else
hci_state = HCI_CHECK_WII_SERVICE ;
}
break ;
case HCI_SET_NAME_STATE :
if ( hci_cmd_complete ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n The name is set to: " ) , 0x80 ) ;
2013-04-26 23:50:39 +02:00
NotifyStr ( btdName , 0x80 ) ;
2012-08-21 14:31:11 +02:00
# endif
2013-03-28 09:37:09 +01:00
hci_state = HCI_CHECK_WII_SERVICE ;
}
break ;
case HCI_CHECK_WII_SERVICE :
if ( pairWithWii ) { // Check if it should try to connect to a wiimote
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Starting inquiry \r \n Press 1 & 2 on the Wiimote \r \n Or press sync if you are using a Wii U Pro Controller " ) , 0x80 ) ;
# endif
hci_inquiry ( ) ;
hci_state = HCI_INQUIRY_STATE ;
} else
hci_state = HCI_SCANNING_STATE ; // Don't try to connect to a Wiimote
break ;
case HCI_INQUIRY_STATE :
if ( hci_wii_found ) {
hci_inquiry_cancel ( ) ; // Stop inquiry
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Wiimote found " ) , 0x80 ) ;
Notify ( PSTR ( " \r \n Now just create the instance like so: " ) , 0x80 ) ;
Notify ( PSTR ( " \r \n WII Wii(&Btd); " ) , 0x80 ) ;
Notify ( PSTR ( " \r \n And then press any button on the Wiimote " ) , 0x80 ) ;
# endif
if ( motionPlusInside ) {
hci_remote_name ( ) ; // We need to know the name to distinguish between a Wiimote and a Wii U Pro Controller
hci_state = HCI_REMOTE_NAME_STATE ;
} else
hci_state = HCI_CONNECT_WII_STATE ;
}
break ;
case HCI_CONNECT_WII_STATE :
if ( hci_cmd_complete ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Connecting to Wiimote " ) , 0x80 ) ;
# endif
hci_connect ( ) ;
hci_state = HCI_CONNECTED_WII_STATE ;
}
break ;
case HCI_CONNECTED_WII_STATE :
if ( hci_connect_event ) {
if ( hci_connect_complete ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Connected to Wiimote " ) , 0x80 ) ;
2012-08-21 14:31:11 +02:00
# endif
2013-03-28 09:37:09 +01:00
hci_authentication_request ( ) ; // This will start the pairing with the wiimote
hci_state = HCI_SCANNING_STATE ;
} else {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Trying to connect one more time... " ) , 0x80 ) ;
# endif
hci_connect ( ) ; // Try to connect one more time
}
}
break ;
case HCI_SCANNING_STATE :
if ( ! connectToWii & & ! pairWithWii ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Wait For Incoming Connection Request " ) , 0x80 ) ;
# endif
hci_write_scan_enable ( ) ;
watingForConnection = true ;
hci_state = HCI_CONNECT_IN_STATE ;
}
break ;
case HCI_CONNECT_IN_STATE :
if ( hci_incoming_connect_request ) {
watingForConnection = false ;
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Incoming Connection Request " ) , 0x80 ) ;
# endif
hci_remote_name ( ) ;
hci_state = HCI_REMOTE_NAME_STATE ;
} else if ( hci_disconnect_complete )
hci_state = HCI_DISCONNECT_STATE ;
2012-08-04 12:20:47 +02:00
break ;
2013-03-28 09:37:09 +01:00
case HCI_REMOTE_NAME_STATE :
if ( hci_remote_name_complete ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Remote Name: " ) , 0x80 ) ;
for ( uint8_t i = 0 ; i < 30 ; i + + ) {
if ( remote_name [ i ] = = NULL )
break ;
2013-04-26 23:50:39 +02:00
Notifyc ( remote_name [ i ] , 0x80 ) ;
2013-03-28 09:37:09 +01:00
}
2013-02-02 22:14:01 +01:00
# endif
2013-03-28 09:37:09 +01:00
if ( strncmp ( ( const char * ) remote_name , " Nintendo " , 8 ) = = 0 ) {
2013-04-01 03:06:49 +02:00
incomingWii = true ;
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Wiimote is connecting " ) , 0x80 ) ;
2013-02-02 22:14:01 +01:00
# endif
2013-03-28 09:37:09 +01:00
if ( strncmp ( ( const char * ) remote_name , " Nintendo RVL-CNT-01-TR " , 22 ) = = 0 ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " with Motion Plus Inside " ) , 0x80 ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-03-28 09:37:09 +01:00
motionPlusInside = true ;
} else if ( strncmp ( ( const char * ) remote_name , " Nintendo RVL-CNT-01-UC " , 22 ) = = 0 ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " - Wii U Pro Controller " ) , 0x80 ) ;
2013-02-02 22:14:01 +01:00
# endif
2013-03-28 09:37:09 +01:00
motionPlusInside = true ;
wiiUProController = true ;
} else {
motionPlusInside = false ;
wiiUProController = false ;
}
}
if ( pairWithWii & & motionPlusInside )
hci_state = HCI_CONNECT_WII_STATE ;
else {
hci_accept_connection ( ) ;
hci_state = HCI_CONNECTED_STATE ;
}
}
break ;
case HCI_CONNECTED_STATE :
if ( hci_connect_complete ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Connected to Device: " ) , 0x80 ) ;
for ( int8_t i = 5 ; i > 0 ; i - - ) {
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( disc_bdaddr [ i ] , 0x80 ) ;
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " : " ) , 0x80 ) ;
}
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( disc_bdaddr [ 0 ] , 0x80 ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-03-28 09:37:09 +01:00
// Clear these flags for a new connection
l2capConnectionClaimed = false ;
sdpConnectionClaimed = false ;
rfcommConnectionClaimed = false ;
hci_event_flag = 0 ;
hci_state = HCI_DONE_STATE ;
}
break ;
case HCI_DONE_STATE :
hci_counter + + ;
if ( hci_counter > 1000 ) { // Wait until we have looped 1000 times to make sure that the L2CAP connection has been started
hci_counter = 0 ;
hci_state = HCI_SCANNING_STATE ;
}
break ;
case HCI_DISCONNECT_STATE :
if ( hci_disconnect_complete ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n HCI Disconnected from Device " ) , 0x80 ) ;
2012-08-04 12:20:47 +02:00
# endif
2013-03-28 09:37:09 +01:00
hci_event_flag = 0 ; // Clear all flags
// Reset all buffers
for ( uint8_t i = 0 ; i < BULK_MAXPKTSIZE ; i + + )
hcibuf [ i ] = 0 ;
for ( uint8_t i = 0 ; i < BULK_MAXPKTSIZE ; i + + )
l2capinbuf [ i ] = 0 ;
2013-10-07 00:47:53 +02:00
connectToWii = false ;
incomingWii = false ;
pairWithWii = false ;
2013-03-28 09:37:09 +01:00
hci_state = HCI_SCANNING_STATE ;
}
break ;
default :
break ;
}
2012-08-04 12:20:47 +02:00
}
void BTD : : ACL_event_task ( ) {
2013-03-28 09:37:09 +01:00
uint16_t MAX_BUFFER_SIZE = BULK_MAXPKTSIZE ;
uint8_t rcode = pUsb - > inTransfer ( bAddress , epInfo [ BTD_DATAIN_PIPE ] . epAddr , & MAX_BUFFER_SIZE , l2capinbuf ) ; // input on endpoint 2
if ( ! rcode ) { // Check for errors
for ( uint8_t i = 0 ; i < BTD_NUMSERVICES ; i + + )
if ( btService [ i ] )
btService [ i ] - > ACLData ( l2capinbuf ) ;
}
2012-08-04 12:20:47 +02:00
# ifdef EXTRADEBUG
2013-03-28 09:37:09 +01:00
else if ( rcode ! = hrNAK ) {
Notify ( PSTR ( " \r \n ACL data in error: " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( rcode , 0x80 ) ;
2013-03-28 09:37:09 +01:00
}
2012-08-09 21:22:55 +02:00
# endif
2013-03-28 09:37:09 +01:00
for ( uint8_t i = 0 ; i < BTD_NUMSERVICES ; i + + )
if ( btService [ i ] )
btService [ i ] - > Run ( ) ;
2012-08-04 12:20:47 +02:00
}
/************************************************************/
/* HCI Commands */
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
/************************************************************/
void BTD : : HCI_Command ( uint8_t * data , uint16_t nbytes ) {
2013-03-28 09:37:09 +01:00
hci_event_flag & = ~ HCI_FLAG_CMD_COMPLETE ;
pUsb - > ctrlReq ( bAddress , epInfo [ BTD_CONTROL_PIPE ] . epAddr , bmREQ_HCI_OUT , 0x00 , 0x00 , 0x00 , 0x00 , nbytes , nbytes , data , NULL ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
void BTD : : hci_reset ( ) {
2013-03-28 09:37:09 +01:00
hci_event_flag = 0 ; // Clear all the flags
hcibuf [ 0 ] = 0x03 ; // HCI OCF = 3
hcibuf [ 1 ] = 0x03 < < 2 ; // HCI OGF = 3
hcibuf [ 2 ] = 0x00 ;
2013-04-03 18:30:46 +02:00
2013-03-28 09:37:09 +01:00
HCI_Command ( hcibuf , 3 ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
void BTD : : hci_write_scan_enable ( ) {
2013-03-28 09:37:09 +01:00
hci_event_flag & = ~ HCI_FLAG_INCOMING_REQUEST ;
hcibuf [ 0 ] = 0x1A ; // HCI OCF = 1A
hcibuf [ 1 ] = 0x03 < < 2 ; // HCI OGF = 3
hcibuf [ 2 ] = 0x01 ; // parameter length = 1
if ( btdName ! = NULL )
hcibuf [ 3 ] = 0x03 ; // Inquiry Scan enabled. Page Scan enabled.
else
hcibuf [ 3 ] = 0x02 ; // Inquiry Scan disabled. Page Scan enabled.
2013-04-03 18:30:46 +02:00
2013-03-28 09:37:09 +01:00
HCI_Command ( hcibuf , 4 ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
void BTD : : hci_write_scan_disable ( ) {
2013-03-28 09:37:09 +01:00
hcibuf [ 0 ] = 0x1A ; // HCI OCF = 1A
hcibuf [ 1 ] = 0x03 < < 2 ; // HCI OGF = 3
hcibuf [ 2 ] = 0x01 ; // parameter length = 1
hcibuf [ 3 ] = 0x00 ; // Inquiry Scan disabled. Page Scan disabled.
2013-04-03 18:30:46 +02:00
2013-03-28 09:37:09 +01:00
HCI_Command ( hcibuf , 4 ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
void BTD : : hci_read_bdaddr ( ) {
hcibuf [ 0 ] = 0x09 ; // HCI OCF = 9
hcibuf [ 1 ] = 0x04 < < 2 ; // HCI OGF = 4
hcibuf [ 2 ] = 0x00 ;
2013-04-03 18:30:46 +02:00
2013-03-28 09:37:09 +01:00
HCI_Command ( hcibuf , 3 ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
void BTD : : hci_read_local_version_information ( ) {
2013-03-28 09:37:09 +01:00
hcibuf [ 0 ] = 0x01 ; // HCI OCF = 1
hcibuf [ 1 ] = 0x04 < < 2 ; // HCI OGF = 4
hcibuf [ 2 ] = 0x00 ;
2013-04-03 18:30:46 +02:00
2013-03-28 09:37:09 +01:00
HCI_Command ( hcibuf , 3 ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
void BTD : : hci_accept_connection ( ) {
2013-03-28 09:37:09 +01:00
hci_event_flag & = ~ HCI_FLAG_CONN_COMPLETE ;
hcibuf [ 0 ] = 0x09 ; // HCI OCF = 9
hcibuf [ 1 ] = 0x01 < < 2 ; // HCI OGF = 1
hcibuf [ 2 ] = 0x07 ; // parameter length 7
hcibuf [ 3 ] = disc_bdaddr [ 0 ] ; // 6 octet bdaddr
hcibuf [ 4 ] = disc_bdaddr [ 1 ] ;
hcibuf [ 5 ] = disc_bdaddr [ 2 ] ;
hcibuf [ 6 ] = disc_bdaddr [ 3 ] ;
hcibuf [ 7 ] = disc_bdaddr [ 4 ] ;
hcibuf [ 8 ] = disc_bdaddr [ 5 ] ;
hcibuf [ 9 ] = 0x00 ; //switch role to master
HCI_Command ( hcibuf , 10 ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
void BTD : : hci_remote_name ( ) {
2013-03-28 09:37:09 +01:00
hci_event_flag & = ~ HCI_FLAG_REMOTE_NAME_COMPLETE ;
hcibuf [ 0 ] = 0x19 ; // HCI OCF = 19
hcibuf [ 1 ] = 0x01 < < 2 ; // HCI OGF = 1
hcibuf [ 2 ] = 0x0A ; // parameter length = 10
hcibuf [ 3 ] = disc_bdaddr [ 0 ] ; // 6 octet bdaddr
hcibuf [ 4 ] = disc_bdaddr [ 1 ] ;
hcibuf [ 5 ] = disc_bdaddr [ 2 ] ;
hcibuf [ 6 ] = disc_bdaddr [ 3 ] ;
hcibuf [ 7 ] = disc_bdaddr [ 4 ] ;
hcibuf [ 8 ] = disc_bdaddr [ 5 ] ;
hcibuf [ 9 ] = 0x01 ; //Page Scan Repetition Mode
hcibuf [ 10 ] = 0x00 ; //Reserved
hcibuf [ 11 ] = 0x00 ; //Clock offset - low byte
hcibuf [ 12 ] = 0x00 ; //Clock offset - high byte
HCI_Command ( hcibuf , 13 ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
void BTD : : hci_set_local_name ( const char * name ) {
2013-03-28 09:37:09 +01:00
hcibuf [ 0 ] = 0x13 ; // HCI OCF = 13
hcibuf [ 1 ] = 0x03 < < 2 ; // HCI OGF = 3
hcibuf [ 2 ] = strlen ( name ) + 1 ; // parameter length = the length of the string + end byte
uint8_t i ;
for ( i = 0 ; i < strlen ( name ) ; i + + )
hcibuf [ i + 3 ] = name [ i ] ;
hcibuf [ i + 3 ] = 0x00 ; // End of string
HCI_Command ( hcibuf , 4 + strlen ( name ) ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-21 14:31:11 +02:00
void BTD : : hci_inquiry ( ) {
2013-03-28 09:37:09 +01:00
hci_event_flag & = ~ HCI_FLAG_WII_FOUND ;
hcibuf [ 0 ] = 0x01 ;
hcibuf [ 1 ] = 0x01 < < 2 ; // HCI OGF = 1
hcibuf [ 2 ] = 0x05 ; // Parameter Total Length = 5
hcibuf [ 3 ] = 0x33 ; // LAP: Genera/Unlimited Inquiry Access Code (GIAC = 0x9E8B33) - see https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
hcibuf [ 4 ] = 0x8B ;
hcibuf [ 5 ] = 0x9E ;
hcibuf [ 6 ] = 0x30 ; // Inquiry time = 61.44 sec (maximum)
hcibuf [ 7 ] = 0x0A ; // 10 number of responses
HCI_Command ( hcibuf , 8 ) ;
2012-08-21 14:31:11 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-21 14:31:11 +02:00
void BTD : : hci_inquiry_cancel ( ) {
2013-03-28 09:37:09 +01:00
hcibuf [ 0 ] = 0x02 ;
hcibuf [ 1 ] = 0x01 < < 2 ; // HCI OGF = 1
2013-04-03 18:30:46 +02:00
hcibuf [ 2 ] = 0x00 ; // Parameter Total Length = 0
2013-03-28 09:37:09 +01:00
HCI_Command ( hcibuf , 3 ) ;
2012-08-21 14:31:11 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-21 14:31:11 +02:00
void BTD : : hci_connect ( ) {
2013-03-28 09:37:09 +01:00
hci_event_flag & = ~ ( HCI_FLAG_CONN_COMPLETE | HCI_FLAG_CONNECT_EVENT ) ;
hcibuf [ 0 ] = 0x05 ;
hcibuf [ 1 ] = 0x01 < < 2 ; // HCI OGF = 1
hcibuf [ 2 ] = 0x0D ; // parameter Total Length = 13
hcibuf [ 3 ] = disc_bdaddr [ 0 ] ; // 6 octet bdaddr
hcibuf [ 4 ] = disc_bdaddr [ 1 ] ;
hcibuf [ 5 ] = disc_bdaddr [ 2 ] ;
hcibuf [ 6 ] = disc_bdaddr [ 3 ] ;
hcibuf [ 7 ] = disc_bdaddr [ 4 ] ;
hcibuf [ 8 ] = disc_bdaddr [ 5 ] ;
hcibuf [ 9 ] = 0x18 ; // DM1 or DH1 may be used
hcibuf [ 10 ] = 0xCC ; // DM3, DH3, DM5, DH5 may be used
hcibuf [ 11 ] = 0x01 ; // Page repetition mode R1
hcibuf [ 12 ] = 0x00 ; // Reserved
hcibuf [ 13 ] = 0x00 ; // Clock offset
hcibuf [ 14 ] = 0x00 ; // Invalid clock offset
hcibuf [ 15 ] = 0x00 ; // Do not allow role switch
HCI_Command ( hcibuf , 16 ) ;
2012-08-21 14:31:11 +02:00
}
2013-03-28 09:37:09 +01:00
2012-10-07 14:50:51 +02:00
void BTD : : hci_pin_code_request_reply ( ) {
2013-03-28 09:37:09 +01:00
hcibuf [ 0 ] = 0x0D ; // HCI OCF = 0D
hcibuf [ 1 ] = 0x01 < < 2 ; // HCI OGF = 1
hcibuf [ 2 ] = 0x17 ; // parameter length 23
hcibuf [ 3 ] = disc_bdaddr [ 0 ] ; // 6 octet bdaddr
hcibuf [ 4 ] = disc_bdaddr [ 1 ] ;
hcibuf [ 5 ] = disc_bdaddr [ 2 ] ;
hcibuf [ 6 ] = disc_bdaddr [ 3 ] ;
hcibuf [ 7 ] = disc_bdaddr [ 4 ] ;
hcibuf [ 8 ] = disc_bdaddr [ 5 ] ;
2013-04-03 18:30:24 +02:00
if ( pairWithWii ) {
hcibuf [ 9 ] = 6 ; // Pin length is the length of the Bluetooth address
2013-05-16 22:43:51 +02:00
if ( wiiUProController ) {
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-04-03 18:30:24 +02:00
Notify ( PSTR ( " \r \n Paring with Wii U Pro Controller " ) , 0x80 ) ;
2013-02-02 22:14:01 +01:00
# endif
2013-05-16 22:43:51 +02:00
for ( uint8_t i = 0 ; i < 6 ; i + + )
2013-04-03 18:30:24 +02:00
hcibuf [ 10 + i ] = my_bdaddr [ i ] ; // The pin is the Bluetooth dongles Bluetooth address backwards
2013-05-16 22:43:51 +02:00
} else {
for ( uint8_t i = 0 ; i < 6 ; i + + )
2013-04-03 18:30:24 +02:00
hcibuf [ 10 + i ] = disc_bdaddr [ i ] ; // The pin is the Wiimote's Bluetooth address backwards
}
2013-03-28 09:37:09 +01:00
for ( uint8_t i = 16 ; i < 26 ; i + + )
hcibuf [ i ] = 0x00 ; // The rest should be 0
} else {
hcibuf [ 9 ] = strlen ( btdPin ) ; // Length of pin
uint8_t i ;
for ( i = 0 ; i < strlen ( btdPin ) ; i + + ) // The maximum size of the pin is 16
hcibuf [ i + 10 ] = btdPin [ i ] ;
for ( ; i < 16 ; i + + )
hcibuf [ i + 10 ] = 0x00 ; // The rest should be 0
}
HCI_Command ( hcibuf , 26 ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
void BTD : : hci_pin_code_negative_request_reply ( ) {
2013-03-28 09:37:09 +01:00
hcibuf [ 0 ] = 0x0E ; // HCI OCF = 0E
hcibuf [ 1 ] = 0x01 < < 2 ; // HCI OGF = 1
hcibuf [ 2 ] = 0x06 ; // parameter length 6
hcibuf [ 3 ] = disc_bdaddr [ 0 ] ; // 6 octet bdaddr
hcibuf [ 4 ] = disc_bdaddr [ 1 ] ;
hcibuf [ 5 ] = disc_bdaddr [ 2 ] ;
hcibuf [ 6 ] = disc_bdaddr [ 3 ] ;
hcibuf [ 7 ] = disc_bdaddr [ 4 ] ;
hcibuf [ 8 ] = disc_bdaddr [ 5 ] ;
HCI_Command ( hcibuf , 9 ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
void BTD : : hci_link_key_request_negative_reply ( ) {
2013-03-28 09:37:09 +01:00
hcibuf [ 0 ] = 0x0C ; // HCI OCF = 0C
hcibuf [ 1 ] = 0x01 < < 2 ; // HCI OGF = 1
hcibuf [ 2 ] = 0x06 ; // parameter length 6
hcibuf [ 3 ] = disc_bdaddr [ 0 ] ; // 6 octet bdaddr
hcibuf [ 4 ] = disc_bdaddr [ 1 ] ;
hcibuf [ 5 ] = disc_bdaddr [ 2 ] ;
hcibuf [ 6 ] = disc_bdaddr [ 3 ] ;
hcibuf [ 7 ] = disc_bdaddr [ 4 ] ;
hcibuf [ 8 ] = disc_bdaddr [ 5 ] ;
HCI_Command ( hcibuf , 9 ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2012-10-07 14:50:51 +02:00
void BTD : : hci_authentication_request ( ) {
2013-03-28 09:37:09 +01:00
hcibuf [ 0 ] = 0x11 ; // HCI OCF = 11
hcibuf [ 1 ] = 0x01 < < 2 ; // HCI OGF = 1
hcibuf [ 2 ] = 0x02 ; // parameter length = 2
hcibuf [ 3 ] = ( uint8_t ) ( hci_handle & 0xFF ) ; //connection handle - low byte
hcibuf [ 4 ] = ( uint8_t ) ( ( hci_handle > > 8 ) & 0x0F ) ; //connection handle - high byte
HCI_Command ( hcibuf , 5 ) ;
2012-10-07 14:50:51 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
void BTD : : hci_disconnect ( uint16_t handle ) { // This is called by the different services
2013-03-28 09:37:09 +01:00
hci_event_flag & = ~ HCI_FLAG_DISCONN_COMPLETE ;
hcibuf [ 0 ] = 0x06 ; // HCI OCF = 6
hcibuf [ 1 ] = 0x01 < < 2 ; // HCI OGF = 1
hcibuf [ 2 ] = 0x03 ; // parameter length = 3
hcibuf [ 3 ] = ( uint8_t ) ( handle & 0xFF ) ; //connection handle - low byte
hcibuf [ 4 ] = ( uint8_t ) ( ( handle > > 8 ) & 0x0F ) ; //connection handle - high byte
hcibuf [ 5 ] = 0x13 ; // reason
HCI_Command ( hcibuf , 6 ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2013-03-14 23:40:52 +01:00
void BTD : : hci_write_class_of_device ( ) { // See http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html
2013-11-12 19:38:18 +01:00
hcibuf [ 0 ] = 0x24 ; // HCI OCF = 24
2013-03-28 09:37:09 +01:00
hcibuf [ 1 ] = 0x03 < < 2 ; // HCI OGF = 3
hcibuf [ 2 ] = 0x03 ; // parameter length = 3
hcibuf [ 3 ] = 0x04 ; // Robot
hcibuf [ 4 ] = 0x08 ; // Toy
hcibuf [ 5 ] = 0x00 ;
2013-04-03 18:30:46 +02:00
2013-03-28 09:37:09 +01:00
HCI_Command ( hcibuf , 6 ) ;
2013-03-14 23:40:52 +01:00
}
2012-08-04 12:20:47 +02:00
/*******************************************************************
* *
* HCI ACL Data Packet *
* *
* buf [ 0 ] buf [ 1 ] buf [ 2 ] buf [ 3 ]
* 0 4 8 11 12 16 24 31 MSB
* . - + - + - + - + - + - + - + - | - + - + - + - | - + - | - + - | - + - + - + - + - + - + - + - | - + - + - + - + - + - + - + - .
* | HCI Handle | PB | BC | Data Total Length | HCI ACL Data Packet
* . - + - + - + - + - + - + - + - | - + - + - + - | - + - | - + - | - + - + - + - + - + - + - + - | - + - + - + - + - + - + - + - .
*
* buf [ 4 ] buf [ 5 ] buf [ 6 ] buf [ 7 ]
* 0 8 16 31 MSB
* . - + - + - + - + - + - + - + - | - + - + - + - + - + - + - + - | - + - + - + - + - + - + - + - | - + - + - + - + - + - + - + - .
* | Length | Channel ID | Basic L2CAP header
* . - + - + - + - + - + - + - + - | - + - + - + - + - + - + - + - | - + - + - + - + - + - + - + - | - + - + - + - + - + - + - + - .
*
* buf [ 8 ] buf [ 9 ] buf [ 10 ] buf [ 11 ]
* 0 8 16 31 MSB
* . - + - + - + - + - + - + - + - | - + - + - + - + - + - + - + - | - + - + - + - + - + - + - + - | - + - + - + - + - + - + - + - .
* | Code | Identifier | Length | Control frame ( C - frame )
* . - + - + - + - + - + - + - + - | - + - + - + - + - + - + - + - | - + - + - + - + - + - + - + - | - + - + - + - + - + - + - + - . ( signaling packet format )
*/
/************************************************************/
/* L2CAP Commands */
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
/************************************************************/
void BTD : : L2CAP_Command ( uint16_t handle , uint8_t * data , uint8_t nbytes , uint8_t channelLow , uint8_t channelHigh ) {
2013-03-28 09:37:09 +01:00
uint8_t buf [ 8 + nbytes ] ;
buf [ 0 ] = ( uint8_t ) ( handle & 0xff ) ; // HCI handle with PB,BC flag
buf [ 1 ] = ( uint8_t ) ( ( ( handle > > 8 ) & 0x0f ) | 0x20 ) ;
buf [ 2 ] = ( uint8_t ) ( ( 4 + nbytes ) & 0xff ) ; // HCI ACL total data length
buf [ 3 ] = ( uint8_t ) ( ( 4 + nbytes ) > > 8 ) ;
buf [ 4 ] = ( uint8_t ) ( nbytes & 0xff ) ; // L2CAP header: Length
buf [ 5 ] = ( uint8_t ) ( nbytes > > 8 ) ;
buf [ 6 ] = channelLow ;
buf [ 7 ] = channelHigh ;
for ( uint16_t i = 0 ; i < nbytes ; i + + ) // L2CAP C-frame
buf [ 8 + i ] = data [ i ] ;
uint8_t rcode = pUsb - > outTransfer ( bAddress , epInfo [ BTD_DATAOUT_PIPE ] . epAddr , ( 8 + nbytes ) , buf ) ;
if ( rcode ) {
delay ( 100 ) ; // This small delay prevents it from overflowing if it fails
2013-06-12 05:11:43 +02:00
# ifdef DEBUG_USB_HOST
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " \r \n Error sending L2CAP message: 0x " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( rcode , 0x80 ) ;
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " - Channel ID: " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( channelHigh , 0x80 ) ;
2013-03-28 09:37:09 +01:00
Notify ( PSTR ( " " ) , 0x80 ) ;
2013-06-17 21:37:09 +02:00
D_PrintHex < uint8_t > ( channelLow , 0x80 ) ;
2013-03-28 09:37:09 +01:00
# endif
}
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-21 14:31:11 +02:00
void BTD : : l2cap_connection_request ( uint16_t handle , uint8_t rxid , uint8_t * scid , uint16_t psm ) {
2013-03-28 09:37:09 +01:00
l2capoutbuf [ 0 ] = L2CAP_CMD_CONNECTION_REQUEST ; // Code
l2capoutbuf [ 1 ] = rxid ; // Identifier
l2capoutbuf [ 2 ] = 0x04 ; // Length
l2capoutbuf [ 3 ] = 0x00 ;
l2capoutbuf [ 4 ] = ( uint8_t ) ( psm & 0xff ) ; // PSM
l2capoutbuf [ 5 ] = ( uint8_t ) ( psm > > 8 ) ;
l2capoutbuf [ 6 ] = scid [ 0 ] ; // Source CID
l2capoutbuf [ 7 ] = scid [ 1 ] ;
L2CAP_Command ( handle , l2capoutbuf , 8 ) ;
}
void BTD : : l2cap_connection_response ( uint16_t handle , uint8_t rxid , uint8_t * dcid , uint8_t * scid , uint8_t result ) {
l2capoutbuf [ 0 ] = L2CAP_CMD_CONNECTION_RESPONSE ; // Code
l2capoutbuf [ 1 ] = rxid ; // Identifier
l2capoutbuf [ 2 ] = 0x08 ; // Length
l2capoutbuf [ 3 ] = 0x00 ;
l2capoutbuf [ 4 ] = dcid [ 0 ] ; // Destination CID
l2capoutbuf [ 5 ] = dcid [ 1 ] ;
l2capoutbuf [ 6 ] = scid [ 0 ] ; // Source CID
l2capoutbuf [ 7 ] = scid [ 1 ] ;
l2capoutbuf [ 8 ] = result ; // Result: Pending or Success
l2capoutbuf [ 9 ] = 0x00 ;
l2capoutbuf [ 10 ] = 0x00 ; // No further information
l2capoutbuf [ 11 ] = 0x00 ;
L2CAP_Command ( handle , l2capoutbuf , 12 ) ;
2012-08-21 14:31:11 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
void BTD : : l2cap_config_request ( uint16_t handle , uint8_t rxid , uint8_t * dcid ) {
2013-03-28 09:37:09 +01:00
l2capoutbuf [ 0 ] = L2CAP_CMD_CONFIG_REQUEST ; // Code
l2capoutbuf [ 1 ] = rxid ; // Identifier
l2capoutbuf [ 2 ] = 0x08 ; // Length
l2capoutbuf [ 3 ] = 0x00 ;
l2capoutbuf [ 4 ] = dcid [ 0 ] ; // Destination CID
l2capoutbuf [ 5 ] = dcid [ 1 ] ;
l2capoutbuf [ 6 ] = 0x00 ; // Flags
l2capoutbuf [ 7 ] = 0x00 ;
l2capoutbuf [ 8 ] = 0x01 ; // Config Opt: type = MTU (Maximum Transmission Unit) - Hint
l2capoutbuf [ 9 ] = 0x02 ; // Config Opt: length
l2capoutbuf [ 10 ] = 0xFF ; // MTU
l2capoutbuf [ 11 ] = 0xFF ;
L2CAP_Command ( handle , l2capoutbuf , 12 ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
void BTD : : l2cap_config_response ( uint16_t handle , uint8_t rxid , uint8_t * scid ) {
l2capoutbuf [ 0 ] = L2CAP_CMD_CONFIG_RESPONSE ; // Code
l2capoutbuf [ 1 ] = rxid ; // Identifier
l2capoutbuf [ 2 ] = 0x0A ; // Length
l2capoutbuf [ 3 ] = 0x00 ;
l2capoutbuf [ 4 ] = scid [ 0 ] ; // Source CID
l2capoutbuf [ 5 ] = scid [ 1 ] ;
l2capoutbuf [ 6 ] = 0x00 ; // Flag
l2capoutbuf [ 7 ] = 0x00 ;
l2capoutbuf [ 8 ] = 0x00 ; // Result
l2capoutbuf [ 9 ] = 0x00 ;
l2capoutbuf [ 10 ] = 0x01 ; // Config
l2capoutbuf [ 11 ] = 0x02 ;
l2capoutbuf [ 12 ] = 0xA0 ;
l2capoutbuf [ 13 ] = 0x02 ;
L2CAP_Command ( handle , l2capoutbuf , 14 ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
void BTD : : l2cap_disconnection_request ( uint16_t handle , uint8_t rxid , uint8_t * dcid , uint8_t * scid ) {
2013-03-28 09:37:09 +01:00
l2capoutbuf [ 0 ] = L2CAP_CMD_DISCONNECT_REQUEST ; // Code
l2capoutbuf [ 1 ] = rxid ; // Identifier
l2capoutbuf [ 2 ] = 0x04 ; // Length
l2capoutbuf [ 3 ] = 0x00 ;
l2capoutbuf [ 4 ] = dcid [ 0 ] ;
l2capoutbuf [ 5 ] = dcid [ 1 ] ;
l2capoutbuf [ 6 ] = scid [ 0 ] ;
l2capoutbuf [ 7 ] = scid [ 1 ] ;
2013-04-03 18:30:46 +02:00
2013-03-28 09:37:09 +01:00
L2CAP_Command ( handle , l2capoutbuf , 8 ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
void BTD : : l2cap_disconnection_response ( uint16_t handle , uint8_t rxid , uint8_t * dcid , uint8_t * scid ) {
2013-03-28 09:37:09 +01:00
l2capoutbuf [ 0 ] = L2CAP_CMD_DISCONNECT_RESPONSE ; // Code
l2capoutbuf [ 1 ] = rxid ; // Identifier
l2capoutbuf [ 2 ] = 0x04 ; // Length
l2capoutbuf [ 3 ] = 0x00 ;
l2capoutbuf [ 4 ] = dcid [ 0 ] ;
l2capoutbuf [ 5 ] = dcid [ 1 ] ;
l2capoutbuf [ 6 ] = scid [ 0 ] ;
l2capoutbuf [ 7 ] = scid [ 1 ] ;
2013-04-03 18:30:46 +02:00
2013-03-28 09:37:09 +01:00
L2CAP_Command ( handle , l2capoutbuf , 8 ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2012-08-04 12:20:47 +02:00
void BTD : : l2cap_information_response ( uint16_t handle , uint8_t rxid , uint8_t infoTypeLow , uint8_t infoTypeHigh ) {
2013-03-28 09:37:09 +01:00
l2capoutbuf [ 0 ] = L2CAP_CMD_INFORMATION_RESPONSE ; // Code
l2capoutbuf [ 1 ] = rxid ; // Identifier
l2capoutbuf [ 2 ] = 0x08 ; // Length
l2capoutbuf [ 3 ] = 0x00 ;
l2capoutbuf [ 4 ] = infoTypeLow ;
l2capoutbuf [ 5 ] = infoTypeHigh ;
l2capoutbuf [ 6 ] = 0x00 ; // Result = success
l2capoutbuf [ 7 ] = 0x00 ; // Result = success
l2capoutbuf [ 8 ] = 0x00 ;
l2capoutbuf [ 9 ] = 0x00 ;
l2capoutbuf [ 10 ] = 0x00 ;
l2capoutbuf [ 11 ] = 0x00 ;
2013-04-03 18:30:46 +02:00
2013-03-28 09:37:09 +01:00
L2CAP_Command ( handle , l2capoutbuf , 12 ) ;
2012-08-04 12:20:47 +02:00
}
2013-04-02 00:10:02 +02:00
/* PS3 Commands - only set Bluetooth address is implemented in this library */
void BTD : : setBdaddr ( uint8_t * bdaddr ) {
/* Set the internal Bluetooth address */
2013-03-28 09:37:09 +01:00
uint8_t buf [ 8 ] ;
buf [ 0 ] = 0x01 ;
buf [ 1 ] = 0x00 ;
2013-04-02 00:10:02 +02:00
2013-03-28 09:37:09 +01:00
for ( uint8_t i = 0 ; i < 6 ; i + + )
2013-11-12 19:38:18 +01:00
buf [ i + 2 ] = bdaddr [ 5 - i ] ; // Copy into buffer, has to be written reversed, so it is MSB first
2013-03-28 09:37:09 +01:00
2013-11-12 19:38:18 +01:00
// bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data
2013-03-28 09:37:09 +01:00
pUsb - > ctrlReq ( bAddress , epInfo [ BTD_CONTROL_PIPE ] . epAddr , bmREQ_HID_OUT , HID_REQUEST_SET_REPORT , 0xF5 , 0x03 , 0x00 , 8 , 8 , buf , NULL ) ;
2012-08-04 12:20:47 +02:00
}
2013-03-28 09:37:09 +01:00
2013-04-02 00:10:02 +02:00
void BTD : : setMoveBdaddr ( uint8_t * bdaddr ) {
/* Set the internal Bluetooth address */
2013-03-28 09:37:09 +01:00
uint8_t buf [ 11 ] ;
buf [ 0 ] = 0x05 ;
buf [ 7 ] = 0x10 ;
buf [ 8 ] = 0x01 ;
buf [ 9 ] = 0x02 ;
buf [ 10 ] = 0x12 ;
for ( uint8_t i = 0 ; i < 6 ; i + + )
2013-04-02 00:10:02 +02:00
buf [ i + 1 ] = bdaddr [ i ] ;
2013-03-28 09:37:09 +01:00
2013-11-12 19:38:18 +01:00
// bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x05), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data
2013-03-28 09:37:09 +01:00
pUsb - > ctrlReq ( bAddress , epInfo [ BTD_CONTROL_PIPE ] . epAddr , bmREQ_HID_OUT , HID_REQUEST_SET_REPORT , 0x05 , 0x03 , 0x00 , 11 , 11 , buf , NULL ) ;
2013-09-27 11:07:05 +02:00
}