2012-12-28 06:37:42 +01:00
/* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
2013-03-28 09:37:09 +01:00
2012-12-28 06:37:42 +01: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-12-28 06:37:42 +01:00
Contact information
- - - - - - - - - - - - - - - - - - -
2013-03-28 09:37:09 +01:00
2012-12-28 06:37:42 +01:00
Kristian Lauszus , TKJ Electronics
Web : http : //www.tkjelectronics.com
e - mail : kristianl @ tkjelectronics . com
2013-01-06 03:43:03 +01:00
getBatteryLevel and checkStatus functions made by timstamp . co . uk found using BusHound from Perisoft . net
2012-12-28 06:37:42 +01:00
*/
# include "XBOXRECV.h"
2013-06-09 20:49:32 +02:00
// To enable serial debugging uncomment "#define DEBUG" in message.h
2012-12-28 06:37:42 +01:00
//#define EXTRADEBUG // Uncomment to get even more debugging data
//#define PRINTREPORT // Uncomment to print the report send by the Xbox 360 Controller
2013-03-28 09:46:43 +01:00
XBOXRECV : : XBOXRECV ( USB * p ) :
2012-12-28 06:37:42 +01:00
pUsb ( p ) , // pointer to USB class instance - mandatory
bAddress ( 0 ) , // device address - mandatory
bPollEnable ( false ) { // don't start polling before dongle is connected
2013-03-28 09:46:43 +01:00
for ( uint8_t i = 0 ; i < XBOX_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 ;
}
if ( pUsb ) // register in USB subsystem
pUsb - > RegisterDeviceClass ( this ) ; //set devConfig[] entry
2012-12-28 06:37:42 +01:00
}
uint8_t XBOXRECV : : Init ( uint8_t parent , uint8_t port , bool lowspeed ) {
2013-03-28 09:46:43 +01:00
uint8_t buf [ sizeof ( USB_DEVICE_DESCRIPTOR ) ] ;
uint8_t rcode ;
UsbDevice * p = NULL ;
EpInfo * oldep_ptr = NULL ;
uint16_t PID ;
uint16_t VID ;
// get memory address of USB device address pool
AddressPool & addrPool = pUsb - > GetAddressPool ( ) ;
2012-12-28 06:37:42 +01:00
# ifdef EXTRADEBUG
2013-03-28 09:46:43 +01:00
Notify ( PSTR ( " \r \n XBOXRECV Init " ) , 0x80 ) ;
2012-12-28 06:37:42 +01:00
# endif
2013-03-28 09:46:43 +01:00
// check if address has already been assigned to an instance
if ( bAddress ) {
2012-12-28 06:37:42 +01:00
# ifdef DEBUG
2013-03-28 09:46:43 +01:00
Notify ( PSTR ( " \r \n Address in use " ) , 0x80 ) ;
2012-12-28 06:37:42 +01:00
# endif
2013-03-28 09:46:43 +01:00
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE ;
}
2013-03-28 09:37:09 +01:00
2013-03-28 09:46:43 +01:00
// Get pointer to pseudo device with address 0 assigned
p = addrPool . GetUsbDevicePtr ( 0 ) ;
2013-03-28 09:37:09 +01:00
2013-03-28 09:46:43 +01:00
if ( ! p ) {
2012-12-28 06:37:42 +01:00
# ifdef DEBUG
2013-03-28 09:46:43 +01:00
Notify ( PSTR ( " \r \n Address not found " ) , 0x80 ) ;
2012-12-28 06:37:42 +01:00
# endif
2013-03-28 09:46:43 +01:00
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL ;
}
2013-03-28 09:37:09 +01:00
2013-03-28 09:46:43 +01:00
if ( ! p - > epinfo ) {
2012-12-28 06:37:42 +01:00
# ifdef DEBUG
2013-03-28 09:46:43 +01:00
Notify ( PSTR ( " \r \n epinfo is null " ) , 0x80 ) ;
2012-12-28 06:37:42 +01:00
# endif
2013-03-28 09:46:43 +01:00
return USB_ERROR_EPINFO_IS_NULL ;
}
2013-03-28 09:37:09 +01:00
2013-03-28 09:46:43 +01:00
// Save old pointer to EP_RECORD of address 0
oldep_ptr = p - > epinfo ;
2013-03-28 09:37:09 +01:00
2013-03-28 09:46:43 +01:00
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
p - > epinfo = epInfo ;
2013-03-28 09:37:09 +01:00
2013-03-28 09:46:43 +01:00
p - > lowspeed = lowspeed ;
2013-03-28 09:37:09 +01:00
2013-03-28 09:46:43 +01:00
// Get device descriptor
rcode = pUsb - > getDevDescr ( 0 , 0 , sizeof ( USB_DEVICE_DESCRIPTOR ) , ( uint8_t * ) buf ) ; // Get device descriptor - addr, ep, nbytes, data
// Restore p->epinfo
p - > epinfo = oldep_ptr ;
2013-03-28 09:37:09 +01:00
2013-03-28 09:46:43 +01:00
if ( rcode )
goto FailGetDevDescr ;
2013-03-28 09:37:09 +01:00
2013-03-28 09:46:43 +01:00
VID = ( ( USB_DEVICE_DESCRIPTOR * ) buf ) - > idVendor ;
PID = ( ( USB_DEVICE_DESCRIPTOR * ) buf ) - > idProduct ;
2013-03-28 09:37:09 +01:00
2013-03-28 09:46:43 +01:00
if ( VID ! = XBOX_VID & & VID ! = MADCATZ_VID ) // We just check if it's a xbox receiver using the Vendor ID
goto FailUnknownDevice ;
else if ( PID ! = XBOX_WIRELESS_RECEIVER_PID & & PID ! = XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID ) {
2012-12-28 06:37:42 +01:00
# ifdef DEBUG
2013-03-28 09:46:43 +01:00
Notify ( PSTR ( " \r \n You'll need a wireless receiver for this libary to work " ) , 0x80 ) ;
2012-12-28 06:37:42 +01:00
# endif
2013-03-28 09:46:43 +01:00
goto FailUnknownDevice ;
}
2013-03-28 09:37:09 +01:00
2013-03-28 09:46:43 +01:00
// Allocate new address according to device class
bAddress = addrPool . AllocAddress ( parent , false , port ) ;
2013-03-28 09:37:09 +01:00
2013-03-28 09:46:43 +01:00
if ( ! bAddress )
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL ;
2013-03-28 09:37:09 +01:00
2013-03-28 09:46:43 +01:00
// Extract Max Packet Size from device descriptor
epInfo [ 0 ] . maxPktSize = ( uint8_t ) ( ( USB_DEVICE_DESCRIPTOR * ) buf ) - > bMaxPacketSize0 ;
2013-03-28 09:37:09 +01:00
2013-03-28 09:46:43 +01:00
// Assign new address to the device
rcode = pUsb - > setAddr ( 0 , 0 , bAddress ) ;
if ( rcode ) {
p - > lowspeed = false ;
addrPool . FreeAddress ( bAddress ) ;
bAddress = 0 ;
2012-12-28 06:37:42 +01:00
# ifdef DEBUG
2013-03-28 09:46:43 +01:00
Notify ( PSTR ( " \r \n setAddr: " ) , 0x80 ) ;
PrintHex < uint8_t > ( rcode , 0x80 ) ;
2013-05-16 22:43:51 +02:00
# endif
2013-03-28 09:46:43 +01:00
return rcode ;
}
2012-12-28 06:37:42 +01:00
# ifdef EXTRADEBUG
2013-03-28 09:46:43 +01:00
Notify ( PSTR ( " \r \n Addr: " ) , 0x80 ) ;
PrintHex < uint8_t > ( bAddress , 0x80 ) ;
2012-12-28 06:37:42 +01:00
# endif
2013-03-28 09:46:43 +01:00
p - > lowspeed = false ;
//get pointer to assigned address record
p = addrPool . GetUsbDevicePtr ( bAddress ) ;
if ( ! p )
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL ;
p - > lowspeed = lowspeed ;
// Assign epInfo to epinfo pointer - only EP0 is known
rcode = pUsb - > setEpInfoEntry ( bAddress , 1 , epInfo ) ;
if ( rcode )
goto FailSetDevTblEntry ;
/* The application will work in reduced host mode, so we can save program and data
memory space . After verifying the VID we will use known values for the
configuration values for device , interface , endpoints and HID for the XBOX360 Wireless receiver */
/* Initialize data structures for endpoints of device */
epInfo [ XBOX_INPUT_PIPE_1 ] . epAddr = 0x01 ; // XBOX 360 report endpoint - poll interval 1ms
epInfo [ XBOX_INPUT_PIPE_1 ] . epAttribs = EP_INTERRUPT ;
epInfo [ XBOX_INPUT_PIPE_1 ] . bmNakPower = USB_NAK_NOWAIT ; // Only poll once for interrupt endpoints
epInfo [ XBOX_INPUT_PIPE_1 ] . maxPktSize = EP_MAXPKTSIZE ;
epInfo [ XBOX_INPUT_PIPE_1 ] . bmSndToggle = bmSNDTOG0 ;
epInfo [ XBOX_INPUT_PIPE_1 ] . bmRcvToggle = bmRCVTOG0 ;
epInfo [ XBOX_OUTPUT_PIPE_1 ] . epAddr = 0x01 ; // XBOX 360 output endpoint - poll interval 8ms
epInfo [ XBOX_OUTPUT_PIPE_1 ] . epAttribs = EP_INTERRUPT ;
epInfo [ XBOX_OUTPUT_PIPE_1 ] . bmNakPower = USB_NAK_NOWAIT ; // Only poll once for interrupt endpoints
epInfo [ XBOX_OUTPUT_PIPE_1 ] . maxPktSize = EP_MAXPKTSIZE ;
epInfo [ XBOX_OUTPUT_PIPE_1 ] . bmSndToggle = bmSNDTOG0 ;
epInfo [ XBOX_OUTPUT_PIPE_1 ] . bmRcvToggle = bmRCVTOG0 ;
epInfo [ XBOX_INPUT_PIPE_2 ] . epAddr = 0x03 ; // XBOX 360 report endpoint - poll interval 1ms
epInfo [ XBOX_INPUT_PIPE_2 ] . epAttribs = EP_INTERRUPT ;
epInfo [ XBOX_INPUT_PIPE_2 ] . bmNakPower = USB_NAK_NOWAIT ; // Only poll once for interrupt endpoints
epInfo [ XBOX_INPUT_PIPE_2 ] . maxPktSize = EP_MAXPKTSIZE ;
epInfo [ XBOX_INPUT_PIPE_2 ] . bmSndToggle = bmSNDTOG0 ;
epInfo [ XBOX_INPUT_PIPE_2 ] . bmRcvToggle = bmRCVTOG0 ;
epInfo [ XBOX_OUTPUT_PIPE_2 ] . epAddr = 0x03 ; // XBOX 360 output endpoint - poll interval 8ms
epInfo [ XBOX_OUTPUT_PIPE_2 ] . epAttribs = EP_INTERRUPT ;
epInfo [ XBOX_OUTPUT_PIPE_2 ] . bmNakPower = USB_NAK_NOWAIT ; // Only poll once for interrupt endpoints
epInfo [ XBOX_OUTPUT_PIPE_2 ] . maxPktSize = EP_MAXPKTSIZE ;
epInfo [ XBOX_OUTPUT_PIPE_2 ] . bmSndToggle = bmSNDTOG0 ;
epInfo [ XBOX_OUTPUT_PIPE_2 ] . bmRcvToggle = bmRCVTOG0 ;
epInfo [ XBOX_INPUT_PIPE_3 ] . epAddr = 0x05 ; // XBOX 360 report endpoint - poll interval 1ms
epInfo [ XBOX_INPUT_PIPE_3 ] . epAttribs = EP_INTERRUPT ;
epInfo [ XBOX_INPUT_PIPE_3 ] . bmNakPower = USB_NAK_NOWAIT ; // Only poll once for interrupt endpoints
epInfo [ XBOX_INPUT_PIPE_3 ] . maxPktSize = EP_MAXPKTSIZE ;
epInfo [ XBOX_INPUT_PIPE_3 ] . bmSndToggle = bmSNDTOG0 ;
epInfo [ XBOX_INPUT_PIPE_3 ] . bmRcvToggle = bmRCVTOG0 ;
epInfo [ XBOX_OUTPUT_PIPE_3 ] . epAddr = 0x05 ; // XBOX 360 output endpoint - poll interval 8ms
epInfo [ XBOX_OUTPUT_PIPE_3 ] . epAttribs = EP_INTERRUPT ;
epInfo [ XBOX_OUTPUT_PIPE_3 ] . bmNakPower = USB_NAK_NOWAIT ; // Only poll once for interrupt endpoints
epInfo [ XBOX_OUTPUT_PIPE_3 ] . maxPktSize = EP_MAXPKTSIZE ;
epInfo [ XBOX_OUTPUT_PIPE_3 ] . bmSndToggle = bmSNDTOG0 ;
epInfo [ XBOX_OUTPUT_PIPE_3 ] . bmRcvToggle = bmRCVTOG0 ;
epInfo [ XBOX_INPUT_PIPE_4 ] . epAddr = 0x07 ; // XBOX 360 report endpoint - poll interval 1ms
epInfo [ XBOX_INPUT_PIPE_4 ] . epAttribs = EP_INTERRUPT ;
epInfo [ XBOX_INPUT_PIPE_4 ] . bmNakPower = USB_NAK_NOWAIT ; // Only poll once for interrupt endpoints
epInfo [ XBOX_INPUT_PIPE_4 ] . maxPktSize = EP_MAXPKTSIZE ;
epInfo [ XBOX_INPUT_PIPE_4 ] . bmSndToggle = bmSNDTOG0 ;
epInfo [ XBOX_INPUT_PIPE_4 ] . bmRcvToggle = bmRCVTOG0 ;
epInfo [ XBOX_OUTPUT_PIPE_4 ] . epAddr = 0x07 ; // XBOX 360 output endpoint - poll interval 8ms
epInfo [ XBOX_OUTPUT_PIPE_4 ] . epAttribs = EP_INTERRUPT ;
epInfo [ XBOX_OUTPUT_PIPE_4 ] . bmNakPower = USB_NAK_NOWAIT ; // Only poll once for interrupt endpoints
epInfo [ XBOX_OUTPUT_PIPE_4 ] . maxPktSize = EP_MAXPKTSIZE ;
epInfo [ XBOX_OUTPUT_PIPE_4 ] . bmSndToggle = bmSNDTOG0 ;
epInfo [ XBOX_OUTPUT_PIPE_4 ] . bmRcvToggle = bmRCVTOG0 ;
rcode = pUsb - > setEpInfoEntry ( bAddress , 9 , epInfo ) ;
if ( rcode )
goto FailSetDevTblEntry ;
delay ( 200 ) ; //Give time for address change
rcode = pUsb - > setConf ( bAddress , epInfo [ XBOX_CONTROL_PIPE ] . epAddr , 1 ) ;
if ( rcode )
2013-03-30 15:29:16 +01:00
goto FailSetConfDescr ;
2012-12-28 06:37:42 +01:00
# ifdef DEBUG
2013-03-28 09:46:43 +01:00
Notify ( PSTR ( " \r \n Xbox Wireless Receiver Connected \r \n " ) , 0x80 ) ;
2012-12-28 06:37:42 +01:00
# endif
2013-03-28 09:46:43 +01:00
XboxReceiverConnected = true ;
bPollEnable = true ;
return 0 ; // successful configuration
2013-03-28 09:37:09 +01:00
2013-03-28 09:46:43 +01:00
/* diagnostic messages */
2012-12-28 06:37:42 +01:00
FailGetDevDescr :
2013-05-16 22:43:51 +02:00
# ifdef DEBUG
2013-03-30 15:29:16 +01:00
NotifyFailGetDevDescr ( ) ;
2013-03-28 09:46:43 +01:00
goto Fail ;
2013-05-16 22:43:51 +02:00
# endif
2013-03-30 15:29:16 +01:00
2012-12-28 06:37:42 +01:00
FailSetDevTblEntry :
2013-05-16 22:43:51 +02:00
# ifdef DEBUG
2013-03-30 15:29:16 +01:00
NotifyFailSetDevTblEntry ( ) ;
2013-03-28 09:46:43 +01:00
goto Fail ;
2013-05-16 22:43:51 +02:00
# endif
2013-03-30 15:29:16 +01:00
FailSetConfDescr :
2013-05-16 22:43:51 +02:00
# ifdef DEBUG
2013-03-30 15:29:16 +01:00
NotifyFailSetConfDescr ( ) ;
2013-05-16 22:43:51 +02:00
# endif
2013-03-28 09:46:43 +01:00
goto Fail ;
2013-03-30 15:29:16 +01:00
2013-04-01 03:05:37 +02:00
FailUnknownDevice :
2013-05-16 22:43:51 +02:00
# ifdef DEBUG
2013-03-30 15:29:16 +01:00
NotifyFailUnknownDevice ( VID , PID ) ;
2013-05-16 22:43:51 +02:00
# endif
2013-03-28 09:46:43 +01:00
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED ;
2013-03-30 15:29:16 +01:00
2012-12-28 06:37:42 +01:00
Fail :
# ifdef DEBUG
2013-03-28 09:46:43 +01:00
Notify ( PSTR ( " \r \n Xbox 360 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:46:43 +01:00
Release ( ) ;
return rcode ;
2012-12-28 06:37:42 +01:00
}
/* Performs a cleanup after failed Init() attempt */
uint8_t XBOXRECV : : Release ( ) {
2013-03-28 09:46:43 +01:00
XboxReceiverConnected = false ;
for ( uint8_t i = 0 ; i < 4 ; i + + )
Xbox360Connected [ i ] = 0x00 ;
pUsb - > GetAddressPool ( ) . FreeAddress ( bAddress ) ;
bAddress = 0 ;
bPollEnable = false ;
return 0 ;
2012-12-28 06:37:42 +01:00
}
2013-03-28 09:46:43 +01:00
2013-03-28 09:37:09 +01:00
uint8_t XBOXRECV : : Poll ( ) {
2013-03-28 09:46:43 +01:00
if ( ! bPollEnable )
return 0 ;
if ( ! timer | | ( ( millis ( ) - timer ) > 3000 ) ) { // Run checkStatus every 3 seconds
timer = millis ( ) ;
checkStatus ( ) ;
2012-12-28 06:37:42 +01:00
}
2013-03-28 09:46:43 +01:00
uint8_t inputPipe ;
uint16_t bufferSize ;
for ( uint8_t i = 0 ; i < 4 ; i + + ) {
switch ( i ) {
case 0 : inputPipe = XBOX_INPUT_PIPE_1 ;
break ;
case 1 : inputPipe = XBOX_INPUT_PIPE_2 ;
break ;
case 2 : inputPipe = XBOX_INPUT_PIPE_3 ;
break ;
case 3 : inputPipe = XBOX_INPUT_PIPE_4 ;
break ;
}
bufferSize = EP_MAXPKTSIZE ; // This is the maximum number of bytes we want to receive
pUsb - > inTransfer ( bAddress , epInfo [ inputPipe ] . epAddr , & bufferSize , readBuf ) ;
if ( bufferSize > 0 ) { // The number of received bytes
2012-12-28 06:37:42 +01:00
# ifdef EXTRADEBUG
2013-03-28 09:46:43 +01:00
Notify ( PSTR ( " Bytes Received: " ) , 0x80 ) ;
2013-04-26 23:50:39 +02:00
PrintHex < uint16_t > ( bufferSize , 0x80 ) ;
2013-03-28 09:46:43 +01:00
Notify ( PSTR ( " \r \n " ) , 0x80 ) ;
2012-12-28 06:37:42 +01:00
# endif
2013-03-28 09:46:43 +01:00
readReport ( i ) ;
2012-12-28 06:37:42 +01:00
# ifdef PRINTREPORT
2013-03-28 09:46:43 +01:00
printReport ( i , bufferSize ) ; // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
2013-03-28 09:37:09 +01:00
# endif
2013-03-28 09:46:43 +01:00
}
2012-12-28 06:37:42 +01:00
}
2013-03-28 09:46:43 +01:00
return 0 ;
2012-12-28 06:37:42 +01:00
}
void XBOXRECV : : readReport ( uint8_t controller ) {
2013-03-28 09:46:43 +01:00
if ( readBuf = = NULL )
return ;
// This report is send when a controller is connected and disconnected
if ( readBuf [ 0 ] = = 0x08 & & readBuf [ 1 ] ! = Xbox360Connected [ controller ] ) {
Xbox360Connected [ controller ] = readBuf [ 1 ] ;
2013-01-02 22:38:31 +01:00
# ifdef DEBUG
2013-03-28 09:46:43 +01:00
Notify ( PSTR ( " Controller " ) , 0x80 ) ;
2013-04-26 23:50:39 +02:00
Notify ( controller , 0x80 ) ;
2013-01-02 22:38:31 +01:00
# endif
2013-03-28 09:46:43 +01:00
if ( Xbox360Connected [ controller ] ) {
2013-01-02 22:38:31 +01:00
# ifdef DEBUG
2013-03-28 09:46:43 +01:00
char * str = 0 ;
switch ( readBuf [ 1 ] ) {
case 0x80 : str = PSTR ( " as controller \r \n " ) ;
break ;
case 0x40 : str = PSTR ( " as headset \r \n " ) ;
break ;
case 0xC0 : str = PSTR ( " as controller+headset \r \n " ) ;
break ;
}
Notify ( PSTR ( " : connected " ) , 0x80 ) ;
Notify ( str , 0x80 ) ;
2013-01-02 22:38:31 +01:00
# endif
2013-03-28 09:46:43 +01:00
LED led ;
switch ( controller ) {
case 0 : led = LED1 ;
break ;
case 1 : led = LED2 ;
break ;
case 2 : led = LED3 ;
break ;
case 3 : led = LED4 ;
break ;
}
2013-05-16 22:41:52 +02:00
setLedOn ( led , controller ) ;
2013-03-28 09:46:43 +01:00
}
2013-01-02 22:38:31 +01:00
# ifdef DEBUG
2013-03-28 09:46:43 +01:00
else
Notify ( PSTR ( " : disconnected \r \n " ) , 0x80 ) ;
2013-01-02 22:38:31 +01:00
# endif
2013-03-28 09:46:43 +01:00
return ;
}
// Controller status report
if ( readBuf [ 1 ] = = 0x00 & & readBuf [ 3 ] & 0x13 & & readBuf [ 4 ] > = 0x22 ) {
controllerStatus [ controller ] = ( ( uint16_t ) readBuf [ 3 ] < < 8 ) | readBuf [ 4 ] ;
return ;
}
if ( readBuf [ 1 ] ! = 0x01 ) // Check if it's the correct report - the receiver also sends different status reports
return ;
// A controller must be connected if it's sending data
if ( ! Xbox360Connected [ controller ] )
Xbox360Connected [ controller ] | = 0x80 ;
ButtonState [ controller ] = ( uint32_t ) ( readBuf [ 9 ] | ( ( uint16_t ) readBuf [ 8 ] < < 8 ) | ( ( uint32_t ) readBuf [ 7 ] < < 16 ) | ( ( uint32_t ) readBuf [ 6 ] < < 24 ) ) ;
hatValue [ controller ] [ LeftHatX ] = ( int16_t ) ( ( ( uint16_t ) readBuf [ 11 ] < < 8 ) | readBuf [ 10 ] ) ;
hatValue [ controller ] [ LeftHatY ] = ( int16_t ) ( ( ( uint16_t ) readBuf [ 13 ] < < 8 ) | readBuf [ 12 ] ) ;
hatValue [ controller ] [ RightHatX ] = ( int16_t ) ( ( ( uint16_t ) readBuf [ 15 ] < < 8 ) | readBuf [ 14 ] ) ;
hatValue [ controller ] [ RightHatY ] = ( int16_t ) ( ( ( uint16_t ) readBuf [ 17 ] < < 8 ) | readBuf [ 16 ] ) ;
//Notify(PSTR("\r\nButtonState: "), 0x80);
//PrintHex<uint32_t>(ButtonState[controller], 0x80);
if ( ButtonState [ controller ] ! = OldButtonState [ controller ] ) {
buttonStateChanged [ controller ] = true ;
ButtonClickState [ controller ] = ( ButtonState [ controller ] > > 16 ) & ( ( ~ OldButtonState [ controller ] ) > > 16 ) ; // Update click state variable, but don't include the two trigger buttons L2 and R2
if ( ( ( uint8_t ) OldButtonState [ controller ] ) = = 0 & & ( ( uint8_t ) ButtonState [ controller ] ) ! = 0 ) // The L2 and R2 buttons are special as they are analog buttons
R2Clicked [ controller ] = true ;
if ( ( uint8_t ) ( OldButtonState [ controller ] > > 8 ) = = 0 & & ( uint8_t ) ( ButtonState [ controller ] > > 8 ) ! = 0 )
L2Clicked [ controller ] = true ;
OldButtonState [ controller ] = ButtonState [ controller ] ;
}
2012-12-28 06:37:42 +01:00
}
void XBOXRECV : : printReport ( uint8_t controller , uint8_t nBytes ) { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
2013-01-19 15:43:28 +01:00
# ifdef PRINTREPORT
2013-03-28 09:46:43 +01:00
if ( readBuf = = NULL )
return ;
Notify ( PSTR ( " Controller " ) , 0x80 ) ;
2013-04-26 23:50:39 +02:00
Notify ( controller , 0x80 ) ;
2013-03-28 09:46:43 +01:00
Notify ( PSTR ( " : " ) , 0x80 ) ;
for ( uint8_t i = 0 ; i < nBytes ; i + + ) {
PrintHex < uint8_t > ( readBuf [ i ] , 0x80 ) ;
2013-04-26 23:50:39 +02:00
Notify ( PSTR ( " " ) , 0x80 ) ;
2013-03-28 09:46:43 +01:00
}
2013-04-26 23:50:39 +02:00
Notify ( PSTR ( " \r \n " ) , 0x80 ) ;
2013-01-02 22:38:31 +01:00
# endif
2012-12-28 06:37:42 +01:00
}
2013-03-28 09:46:43 +01:00
2013-05-16 22:41:52 +02:00
uint8_t XBOXRECV : : getButtonPress ( Button b , uint8_t controller ) {
2013-03-28 09:46:43 +01:00
if ( b = = L2 ) // These are analog buttons
return ( uint8_t ) ( ButtonState [ controller ] > > 8 ) ;
else if ( b = = R2 )
return ( uint8_t ) ButtonState [ controller ] ;
2013-04-15 18:37:24 +02:00
return ( bool ) ( ButtonState [ controller ] & ( ( uint32_t ) pgm_read_word ( & XBOXBUTTONS [ ( uint8_t ) b ] ) < < 16 ) ) ;
2012-12-28 06:37:42 +01:00
}
2013-03-28 09:46:43 +01:00
2013-05-16 22:41:52 +02:00
bool XBOXRECV : : getButtonClick ( Button b , uint8_t controller ) {
2013-03-28 09:46:43 +01:00
if ( b = = L2 ) {
if ( L2Clicked [ controller ] ) {
L2Clicked [ controller ] = false ;
return true ;
}
return false ;
} else if ( b = = R2 ) {
if ( R2Clicked [ controller ] ) {
R2Clicked [ controller ] = false ;
return true ;
}
return false ;
2012-12-28 06:37:42 +01:00
}
2013-03-28 09:46:43 +01:00
uint16_t button = pgm_read_word ( & XBOXBUTTONS [ ( uint8_t ) b ] ) ;
bool click = ( ButtonClickState [ controller ] & button ) ;
ButtonClickState [ controller ] & = ~ button ; // clear "click" event
return click ;
2012-12-28 06:37:42 +01:00
}
2013-03-28 09:46:43 +01:00
2013-05-16 22:41:52 +02:00
int16_t XBOXRECV : : getAnalogHat ( AnalogHat a , uint8_t controller ) {
2013-03-28 09:46:43 +01:00
return hatValue [ controller ] [ a ] ;
2012-12-28 06:37:42 +01:00
}
2013-03-28 09:46:43 +01:00
2013-01-08 08:16:01 +01:00
bool XBOXRECV : : buttonChanged ( uint8_t controller ) {
2013-03-28 09:46:43 +01:00
bool state = buttonStateChanged [ controller ] ;
buttonStateChanged [ controller ] = false ;
return state ;
2013-01-08 08:16:01 +01:00
}
2013-03-28 09:46:43 +01:00
2013-01-06 03:43:03 +01:00
/*
ControllerStatus Breakdown
ControllerStatus [ controller ] & 0x0001 // 0
ControllerStatus [ controller ] & 0x0002 // normal batteries, no rechargeable battery pack
ControllerStatus [ controller ] & 0x0004 // controller starting up / settling
ControllerStatus [ controller ] & 0x0008 // headset adapter plugged in, but no headphones connected (mute?)
ControllerStatus [ controller ] & 0x0010 // 0
ControllerStatus [ controller ] & 0x0020 // 1
ControllerStatus [ controller ] & 0x0040 // battery level (high bit)
ControllerStatus [ controller ] & 0x0080 // battery level (low bit)
ControllerStatus [ controller ] & 0x0100 // 1
ControllerStatus [ controller ] & 0x0200 // 1
ControllerStatus [ controller ] & 0x0400 // headset adapter plugged in
ControllerStatus [ controller ] & 0x0800 // 0
ControllerStatus [ controller ] & 0x1000 // 1
ControllerStatus [ controller ] & 0x2000 // 0
ControllerStatus [ controller ] & 0x4000 // 0
ControllerStatus [ controller ] & 0x8000 // 0
2013-03-28 09:46:43 +01:00
*/
2013-01-06 03:43:03 +01:00
uint8_t XBOXRECV : : getBatteryLevel ( uint8_t controller ) {
2013-03-30 16:25:28 +01:00
return ( ( controllerStatus [ controller ] & 0x00C0 ) > > 6 ) ;
2013-01-06 03:43:03 +01:00
}
2012-12-28 06:37:42 +01:00
void XBOXRECV : : XboxCommand ( uint8_t controller , uint8_t * data , uint16_t nbytes ) {
2013-03-28 09:46:43 +01:00
uint8_t rcode ;
uint8_t outputPipe ;
switch ( controller ) {
case 0 : outputPipe = XBOX_OUTPUT_PIPE_1 ;
break ;
case 1 : outputPipe = XBOX_OUTPUT_PIPE_2 ;
break ;
case 2 : outputPipe = XBOX_OUTPUT_PIPE_3 ;
break ;
case 3 : outputPipe = XBOX_OUTPUT_PIPE_4 ;
break ;
}
rcode = pUsb - > outTransfer ( bAddress , epInfo [ outputPipe ] . epAddr , nbytes , data ) ;
2012-12-28 06:37:42 +01:00
# ifdef EXTRADEBUG
2013-03-28 09:46:43 +01:00
if ( rcode )
Notify ( PSTR ( " Error sending Xbox message \r \n " ) , 0x80 ) ;
2012-12-28 06:37:42 +01:00
# endif
}
2013-03-28 09:46:43 +01:00
2013-05-16 22:41:52 +02:00
void XBOXRECV : : setLedRaw ( uint8_t value , uint8_t controller ) {
2013-03-28 09:46:43 +01:00
writeBuf [ 0 ] = 0x00 ;
writeBuf [ 1 ] = 0x00 ;
writeBuf [ 2 ] = 0x08 ;
writeBuf [ 3 ] = value | 0x40 ;
2013-03-28 09:37:09 +01:00
2013-03-28 09:46:43 +01:00
XboxCommand ( controller , writeBuf , 4 ) ;
2012-12-28 06:37:42 +01:00
}
2013-03-28 09:46:43 +01:00
2013-05-16 22:41:52 +02:00
void XBOXRECV : : setLedOn ( LED led , uint8_t controller ) {
2013-03-28 09:46:43 +01:00
if ( led ! = ALL ) // All LEDs can't be on a the same time
2013-05-17 00:37:59 +02:00
setLedRaw ( pgm_read_byte ( & XBOXLEDS [ ( uint8_t ) led ] ) + 4 , controller ) ;
2013-01-06 03:43:03 +01:00
}
2013-03-28 09:46:43 +01:00
2013-05-16 22:41:52 +02:00
void XBOXRECV : : setLedBlink ( LED led , uint8_t controller ) {
2013-05-17 00:37:59 +02:00
setLedRaw ( pgm_read_byte ( & XBOXLEDS [ ( uint8_t ) led ] ) , controller ) ;
2012-12-28 06:37:42 +01:00
}
2013-03-28 09:46:43 +01:00
2013-05-16 22:41:52 +02:00
void XBOXRECV : : setLedMode ( LEDMode ledMode , uint8_t controller ) { // This function is used to do some speciel LED stuff the controller supports
2013-05-17 00:37:59 +02:00
setLedRaw ( ( uint8_t ) ledMode , controller ) ;
2012-12-28 06:37:42 +01:00
}
2013-03-28 09:46:43 +01:00
2013-03-28 09:37:09 +01:00
/* PC runs this at interval of approx 2 seconds
2013-01-06 03:43:03 +01:00
Thanks to BusHound from Perisoft . net for the Windows USB Analysis output
Found by timstamp . co . uk
2013-03-28 09:46:43 +01:00
*/
2013-01-06 03:43:03 +01:00
void XBOXRECV : : checkStatus ( ) {
2013-03-28 09:46:43 +01:00
if ( ! bPollEnable )
return ;
// Get controller info
writeBuf [ 0 ] = 0x08 ;
writeBuf [ 1 ] = 0x00 ;
writeBuf [ 2 ] = 0x0f ;
writeBuf [ 3 ] = 0xc0 ;
for ( uint8_t i = 0 ; i < 4 ; i + + ) {
XboxCommand ( i , writeBuf , 4 ) ;
}
// Get battery status
writeBuf [ 0 ] = 0x00 ;
writeBuf [ 1 ] = 0x00 ;
writeBuf [ 2 ] = 0x00 ;
writeBuf [ 3 ] = 0x40 ;
for ( uint8_t i = 0 ; i < 4 ; i + + ) {
if ( Xbox360Connected [ i ] )
XboxCommand ( i , writeBuf , 4 ) ;
}
2012-12-28 06:37:42 +01:00
}
2013-01-06 03:43:03 +01:00
2013-05-16 22:41:52 +02:00
void XBOXRECV : : setRumbleOn ( uint8_t lValue , uint8_t rValue , uint8_t controller ) {
2013-03-28 09:46:43 +01:00
writeBuf [ 0 ] = 0x00 ;
writeBuf [ 1 ] = 0x01 ;
writeBuf [ 2 ] = 0x0f ;
writeBuf [ 3 ] = 0xc0 ;
writeBuf [ 4 ] = 0x00 ;
writeBuf [ 5 ] = lValue ; // big weight
writeBuf [ 6 ] = rValue ; // small weight
XboxCommand ( controller , writeBuf , 7 ) ;
2013-03-28 09:37:09 +01:00
}