mirror of
https://github.com/felis/USB_Host_Shield_2.0.git
synced 2024-03-22 11:31:26 +01:00
getBatteryLevel and some other improvement by timstamp.co.uk
This commit is contained in:
parent
33698b0091
commit
15d8cf1660
2 changed files with 132 additions and 85 deletions
212
XBOXRECV.cpp
212
XBOXRECV.cpp
|
@ -13,6 +13,8 @@
|
|||
Kristian Lauszus, TKJ Electronics
|
||||
Web : http://www.tkjelectronics.com
|
||||
e-mail : kristianl@tkjelectronics.com
|
||||
|
||||
getBatteryLevel and checkStatus functions made by timstamp.co.uk found using BusHound from Perisoft.net
|
||||
*/
|
||||
|
||||
#include "XBOXRECV.h"
|
||||
|
@ -252,7 +254,7 @@ Fail:
|
|||
uint8_t XBOXRECV::Release() {
|
||||
XboxReceiverConnected = false;
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
Xbox360Connected[i] = false;
|
||||
Xbox360Connected[i] = 0x00;
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
bPollEnable = false;
|
||||
|
@ -261,33 +263,30 @@ uint8_t XBOXRECV::Release() {
|
|||
uint8_t XBOXRECV::Poll() {
|
||||
if (!bPollEnable)
|
||||
return 0;
|
||||
for(uint8_t i=0;i<4;i++) {
|
||||
uint16_t BUFFER_SIZE = EP_MAXPKTSIZE;
|
||||
switch (i) {
|
||||
case 0:
|
||||
pUsb->inTransfer(bAddress, epInfo[ XBOX_INPUT_PIPE_1 ].epAddr, &BUFFER_SIZE, readBuf);
|
||||
break;
|
||||
case 1:
|
||||
pUsb->inTransfer(bAddress, epInfo[ XBOX_INPUT_PIPE_2 ].epAddr, &BUFFER_SIZE, readBuf);
|
||||
break;
|
||||
case 2:
|
||||
pUsb->inTransfer(bAddress, epInfo[ XBOX_INPUT_PIPE_3 ].epAddr, &BUFFER_SIZE, readBuf);
|
||||
break;
|
||||
case 3:
|
||||
pUsb->inTransfer(bAddress, epInfo[ XBOX_INPUT_PIPE_4 ].epAddr, &BUFFER_SIZE, readBuf);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if(!timer || ((millis() - timer) > 3000)) { // Run checkStatus every 3 seconds
|
||||
timer = millis();
|
||||
checkStatus();
|
||||
}
|
||||
if(BUFFER_SIZE > 0) {
|
||||
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
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("Bytes Received: "));
|
||||
Serial.print(BUFFER_SIZE);
|
||||
Serial.print(bufferSize);
|
||||
Notify(PSTR("\r\n"));
|
||||
#endif
|
||||
readReport(i);
|
||||
#ifdef PRINTREPORT
|
||||
printReport(i,BUFFER_SIZE); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
|
||||
printReport(i,bufferSize); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -297,30 +296,32 @@ uint8_t XBOXRECV::Poll() {
|
|||
void XBOXRECV::readReport(uint8_t controller) {
|
||||
if (readBuf == NULL)
|
||||
return;
|
||||
if(readBuf[0] == 0x08) { // This report is send when a controller is connected and disconnected
|
||||
Xbox360Connected[controller] = (bool)(readBuf[1] == 0x80);
|
||||
// This report is send when a controller is connected and disconnected
|
||||
if(readBuf[0] == 0x08 && readBuf[1] != Xbox360Connected[controller]) {
|
||||
Xbox360Connected[controller] = readBuf[1];
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("Controller "));
|
||||
Serial.print(controller);
|
||||
#endif
|
||||
if(Xbox360Connected[controller]) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR(": connected\r\n"));
|
||||
#endif
|
||||
switch (controller) {
|
||||
case 0:
|
||||
setLedOn(controller,LED1);
|
||||
break;
|
||||
case 1:
|
||||
setLedOn(controller,LED2);
|
||||
break;
|
||||
case 2:
|
||||
setLedOn(controller,LED3);
|
||||
break;
|
||||
case 3:
|
||||
setLedOn(controller,LED4);
|
||||
break;
|
||||
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"));
|
||||
Notify(str);
|
||||
#endif
|
||||
LED led;
|
||||
switch (controller) {
|
||||
case 0: led = LED1; break;
|
||||
case 1: led = LED2; break;
|
||||
case 2: led = LED3; break;
|
||||
case 3: led = LED4; break;
|
||||
}
|
||||
setLedOn(controller,led);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else
|
||||
|
@ -328,17 +329,24 @@ void XBOXRECV::readReport(uint8_t controller) {
|
|||
#endif
|
||||
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;
|
||||
|
||||
Xbox360Connected[controller] = true; // A controller must be connected if it's sending data
|
||||
// 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][0] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]);
|
||||
hatValue[controller][1] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]);
|
||||
hatValue[controller][2] = (int16_t)(((uint16_t)readBuf[15] << 8) | readBuf[14]);
|
||||
hatValue[controller][3] = (int16_t)(((uint16_t)readBuf[17] << 8) | readBuf[16]);
|
||||
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: "));
|
||||
//PrintHex<uint32_t>(ButtonState[controller]);
|
||||
|
@ -396,25 +404,48 @@ bool XBOXRECV::getButtonClick(uint8_t controller, Button b) {
|
|||
int16_t XBOXRECV::getAnalogHat(uint8_t controller, AnalogHat a) {
|
||||
return hatValue[controller][a];
|
||||
}
|
||||
/*
|
||||
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
|
||||
*/
|
||||
uint8_t XBOXRECV::getBatteryLevel(uint8_t controller) {
|
||||
if(((controllerStatus[controller] & 0x00C0) >> 6) == 0x3)
|
||||
return 100;
|
||||
else if(((controllerStatus[controller] & 0x00C0) >> 6) == 0x2)
|
||||
return 67;
|
||||
else if(((controllerStatus[controller] & 0x00C0) >> 6) == 0x1)
|
||||
return 33;
|
||||
else if(((controllerStatus[controller] & 0x00C0) >> 6) == 0x0)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
void XBOXRECV::XboxCommand(uint8_t controller, uint8_t* data, uint16_t nbytes) {
|
||||
uint8_t rcode;
|
||||
uint8_t outputPipe;
|
||||
switch (controller) {
|
||||
case 0:
|
||||
rcode = pUsb->outTransfer(bAddress, epInfo[ XBOX_OUTPUT_PIPE_1 ].epAddr, nbytes, data);
|
||||
break;
|
||||
case 1:
|
||||
rcode = pUsb->outTransfer(bAddress, epInfo[ XBOX_OUTPUT_PIPE_2 ].epAddr, nbytes, data);
|
||||
break;
|
||||
case 2:
|
||||
rcode = pUsb->outTransfer(bAddress, epInfo[ XBOX_OUTPUT_PIPE_3 ].epAddr, nbytes, data);
|
||||
break;
|
||||
case 3:
|
||||
rcode = pUsb->outTransfer(bAddress, epInfo[ XBOX_OUTPUT_PIPE_4 ].epAddr, nbytes, data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
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);
|
||||
#ifdef EXTRADEBUG
|
||||
if(rcode)
|
||||
Notify(PSTR("Error sending Xbox message\r\n"));
|
||||
|
@ -424,32 +455,46 @@ void XBOXRECV::setLedRaw(uint8_t controller, uint8_t value) {
|
|||
writeBuf[0] = 0x00;
|
||||
writeBuf[1] = 0x00;
|
||||
writeBuf[2] = 0x08;
|
||||
writeBuf[3] = value+0x40;
|
||||
writeBuf[4] = 0x00;
|
||||
writeBuf[5] = 0x00;
|
||||
writeBuf[6] = 0x00;
|
||||
writeBuf[7] = 0x00;
|
||||
writeBuf[8] = 0x00;
|
||||
writeBuf[9] = 0x00;
|
||||
writeBuf[10] = 0x00;
|
||||
writeBuf[11] = 0x00;
|
||||
writeBuf[3] = value | 0x40;
|
||||
|
||||
for(uint8_t i=0;i<10;i++) { // This small hack is needed for some reason as the controller doesn't always respond to the command
|
||||
XboxCommand(controller, writeBuf, 12);
|
||||
delay(1);
|
||||
XboxCommand(controller, writeBuf, 4);
|
||||
}
|
||||
void XBOXRECV::setLedOn(uint8_t controller, LED led) {
|
||||
if(led != ALL) // All LEDs can't be on a the same time
|
||||
setLedRaw(controller,((uint8_t)led)+4);
|
||||
}
|
||||
void XBOXRECV::setLedBlink(uint8_t controller, LED led) {
|
||||
setLedRaw(controller,(uint8_t)led);
|
||||
}
|
||||
void XBOXRECV::setLedMode(uint8_t controller, LEDMode ledMode) { // This function is used to do some speciel LED stuff the controller supports
|
||||
setLedRaw(controller,(uint8_t)ledMode);
|
||||
}
|
||||
/* PC runs this at interval of approx 2 seconds
|
||||
Thanks to BusHound from Perisoft.net for the Windows USB Analysis output
|
||||
Found by timstamp.co.uk
|
||||
*/
|
||||
void XBOXRECV::checkStatus() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
void XBOXRECV::setLedOn(uint8_t controller, LED l) {
|
||||
if(l == ALL) // All LEDs can't be on a the same time
|
||||
return;
|
||||
setLedRaw(controller,((uint8_t)l)+4);
|
||||
}
|
||||
void XBOXRECV::setLedBlink(uint8_t controller, LED l) {
|
||||
setLedRaw(controller,(uint8_t)l);
|
||||
}
|
||||
void XBOXRECV::setLedMode(uint8_t controller, LEDMode lm) { // This function is used to do some speciel LED stuff the controller supports
|
||||
setLedRaw(controller,(uint8_t)lm);
|
||||
}
|
||||
|
||||
void XBOXRECV::setRumbleOn(uint8_t controller, uint8_t lValue, uint8_t rValue) {
|
||||
writeBuf[0] = 0x00;
|
||||
writeBuf[1] = 0x01;
|
||||
|
@ -458,11 +503,6 @@ void XBOXRECV::setRumbleOn(uint8_t controller, uint8_t lValue, uint8_t rValue) {
|
|||
writeBuf[4] = 0x00;
|
||||
writeBuf[5] = lValue; // big weight
|
||||
writeBuf[6] = rValue; // small weight
|
||||
writeBuf[7] = 0x00;
|
||||
writeBuf[8] = 0x00;
|
||||
writeBuf[9] = 0x00;
|
||||
writeBuf[10] = 0x00;
|
||||
writeBuf[11] = 0x00;
|
||||
|
||||
XboxCommand(controller, writeBuf, 12);
|
||||
XboxCommand(controller, writeBuf, 7);
|
||||
}
|
|
@ -13,6 +13,8 @@
|
|||
Kristian Lauszus, TKJ Electronics
|
||||
Web : http://www.tkjelectronics.com
|
||||
e-mail : kristianl@tkjelectronics.com
|
||||
|
||||
getBatteryLevel and checkStatus functions made by timstamp.co.uk found using BusHound from Perisoft.net
|
||||
*/
|
||||
|
||||
#ifndef _xboxrecv_h_
|
||||
|
@ -129,9 +131,10 @@ public:
|
|||
void setLedOn(uint8_t controller, LED l);
|
||||
void setLedBlink(uint8_t controller, LED l);
|
||||
void setLedMode(uint8_t controller, LEDMode lm);
|
||||
uint8_t getBatteryLevel(uint8_t controller); // Returns the battery level in percentage in 25% steps
|
||||
|
||||
bool XboxReceiverConnected; // True if a wireless receiver is connected
|
||||
bool Xbox360Connected[4]; // Variable used to indicate if the XBOX 360 controller is successfully connected
|
||||
uint8_t Xbox360Connected[4]; // Variable used to indicate if the XBOX 360 controller is successfully connected
|
||||
|
||||
protected:
|
||||
/* Mandatory members */
|
||||
|
@ -147,10 +150,13 @@ private:
|
|||
uint32_t OldButtonState[4];
|
||||
uint16_t ButtonClickState[4];
|
||||
int16_t hatValue[4][4];
|
||||
uint16_t controllerStatus[4];
|
||||
|
||||
bool L2Clicked[4]; // These buttons are analog, so we use we use these bools to check if they where clicked or not
|
||||
bool R2Clicked[4];
|
||||
|
||||
unsigned long timer; // Timing for checkStatus() signals
|
||||
|
||||
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
|
||||
uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data
|
||||
|
||||
|
@ -159,5 +165,6 @@ private:
|
|||
|
||||
/* Private commands */
|
||||
void XboxCommand(uint8_t controller, uint8_t* data, uint16_t nbytes);
|
||||
void checkStatus();
|
||||
};
|
||||
#endif
|
Loading…
Reference in a new issue