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
|
Kristian Lauszus, TKJ Electronics
|
||||||
Web : http://www.tkjelectronics.com
|
Web : http://www.tkjelectronics.com
|
||||||
e-mail : kristianl@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"
|
#include "XBOXRECV.h"
|
||||||
|
@ -252,7 +254,7 @@ Fail:
|
||||||
uint8_t XBOXRECV::Release() {
|
uint8_t XBOXRECV::Release() {
|
||||||
XboxReceiverConnected = false;
|
XboxReceiverConnected = false;
|
||||||
for(uint8_t i=0;i<4;i++)
|
for(uint8_t i=0;i<4;i++)
|
||||||
Xbox360Connected[i] = false;
|
Xbox360Connected[i] = 0x00;
|
||||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||||
bAddress = 0;
|
bAddress = 0;
|
||||||
bPollEnable = false;
|
bPollEnable = false;
|
||||||
|
@ -261,33 +263,30 @@ uint8_t XBOXRECV::Release() {
|
||||||
uint8_t XBOXRECV::Poll() {
|
uint8_t XBOXRECV::Poll() {
|
||||||
if (!bPollEnable)
|
if (!bPollEnable)
|
||||||
return 0;
|
return 0;
|
||||||
for(uint8_t i=0;i<4;i++) {
|
if(!timer || ((millis() - timer) > 3000)) { // Run checkStatus every 3 seconds
|
||||||
uint16_t BUFFER_SIZE = EP_MAXPKTSIZE;
|
timer = millis();
|
||||||
switch (i) {
|
checkStatus();
|
||||||
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(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
|
#ifdef EXTRADEBUG
|
||||||
Notify(PSTR("Bytes Received: "));
|
Notify(PSTR("Bytes Received: "));
|
||||||
Serial.print(BUFFER_SIZE);
|
Serial.print(bufferSize);
|
||||||
Notify(PSTR("\r\n"));
|
Notify(PSTR("\r\n"));
|
||||||
#endif
|
#endif
|
||||||
readReport(i);
|
readReport(i);
|
||||||
#ifdef PRINTREPORT
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,30 +296,32 @@ uint8_t XBOXRECV::Poll() {
|
||||||
void XBOXRECV::readReport(uint8_t controller) {
|
void XBOXRECV::readReport(uint8_t controller) {
|
||||||
if (readBuf == NULL)
|
if (readBuf == NULL)
|
||||||
return;
|
return;
|
||||||
if(readBuf[0] == 0x08) { // This report is send when a controller is connected and disconnected
|
// This report is send when a controller is connected and disconnected
|
||||||
Xbox360Connected[controller] = (bool)(readBuf[1] == 0x80);
|
if(readBuf[0] == 0x08 && readBuf[1] != Xbox360Connected[controller]) {
|
||||||
|
Xbox360Connected[controller] = readBuf[1];
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
Notify(PSTR("Controller "));
|
Notify(PSTR("Controller "));
|
||||||
Serial.print(controller);
|
Serial.print(controller);
|
||||||
#endif
|
#endif
|
||||||
if(Xbox360Connected[controller]) {
|
if(Xbox360Connected[controller]) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
Notify(PSTR(": connected\r\n"));
|
char* str = 0;
|
||||||
#endif
|
switch(readBuf[1]) {
|
||||||
switch (controller) {
|
case 0x80: str = PSTR(" as controller\r\n"); break;
|
||||||
case 0:
|
case 0x40: str = PSTR(" as headset\r\n"); break;
|
||||||
setLedOn(controller,LED1);
|
case 0xC0: str = PSTR(" as controller+headset\r\n"); break;
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
setLedOn(controller,LED2);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
setLedOn(controller,LED3);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
setLedOn(controller,LED4);
|
|
||||||
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
|
#ifdef DEBUG
|
||||||
else
|
else
|
||||||
|
@ -328,17 +329,24 @@ void XBOXRECV::readReport(uint8_t controller) {
|
||||||
#endif
|
#endif
|
||||||
return;
|
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
|
if(readBuf[1] != 0x01) // Check if it's the correct report - the receiver also sends different status reports
|
||||||
return;
|
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));
|
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][LeftHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]);
|
||||||
hatValue[controller][1] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]);
|
hatValue[controller][LeftHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]);
|
||||||
hatValue[controller][2] = (int16_t)(((uint16_t)readBuf[15] << 8) | readBuf[14]);
|
hatValue[controller][RightHatX] = (int16_t)(((uint16_t)readBuf[15] << 8) | readBuf[14]);
|
||||||
hatValue[controller][3] = (int16_t)(((uint16_t)readBuf[17] << 8) | readBuf[16]);
|
hatValue[controller][RightHatY] = (int16_t)(((uint16_t)readBuf[17] << 8) | readBuf[16]);
|
||||||
|
|
||||||
//Notify(PSTR("\r\nButtonState: "));
|
//Notify(PSTR("\r\nButtonState: "));
|
||||||
//PrintHex<uint32_t>(ButtonState[controller]);
|
//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) {
|
int16_t XBOXRECV::getAnalogHat(uint8_t controller, AnalogHat a) {
|
||||||
return hatValue[controller][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) {
|
void XBOXRECV::XboxCommand(uint8_t controller, uint8_t* data, uint16_t nbytes) {
|
||||||
uint8_t rcode;
|
uint8_t rcode;
|
||||||
|
uint8_t outputPipe;
|
||||||
switch (controller) {
|
switch (controller) {
|
||||||
case 0:
|
case 0: outputPipe = XBOX_OUTPUT_PIPE_1; break;
|
||||||
rcode = pUsb->outTransfer(bAddress, epInfo[ XBOX_OUTPUT_PIPE_1 ].epAddr, nbytes, data);
|
case 1: outputPipe = XBOX_OUTPUT_PIPE_2; break;
|
||||||
break;
|
case 2: outputPipe = XBOX_OUTPUT_PIPE_3; break;
|
||||||
case 1:
|
case 3: outputPipe = XBOX_OUTPUT_PIPE_4; break;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
rcode = pUsb->outTransfer(bAddress, epInfo[ outputPipe ].epAddr, nbytes, data);
|
||||||
#ifdef EXTRADEBUG
|
#ifdef EXTRADEBUG
|
||||||
if(rcode)
|
if(rcode)
|
||||||
Notify(PSTR("Error sending Xbox message\r\n"));
|
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[0] = 0x00;
|
||||||
writeBuf[1] = 0x00;
|
writeBuf[1] = 0x00;
|
||||||
writeBuf[2] = 0x08;
|
writeBuf[2] = 0x08;
|
||||||
writeBuf[3] = value+0x40;
|
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;
|
|
||||||
|
|
||||||
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, 4);
|
||||||
XboxCommand(controller, writeBuf, 12);
|
}
|
||||||
delay(1);
|
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) {
|
void XBOXRECV::setRumbleOn(uint8_t controller, uint8_t lValue, uint8_t rValue) {
|
||||||
writeBuf[0] = 0x00;
|
writeBuf[0] = 0x00;
|
||||||
writeBuf[1] = 0x01;
|
writeBuf[1] = 0x01;
|
||||||
|
@ -458,11 +503,6 @@ void XBOXRECV::setRumbleOn(uint8_t controller, uint8_t lValue, uint8_t rValue) {
|
||||||
writeBuf[4] = 0x00;
|
writeBuf[4] = 0x00;
|
||||||
writeBuf[5] = lValue; // big weight
|
writeBuf[5] = lValue; // big weight
|
||||||
writeBuf[6] = rValue; // small 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
|
Kristian Lauszus, TKJ Electronics
|
||||||
Web : http://www.tkjelectronics.com
|
Web : http://www.tkjelectronics.com
|
||||||
e-mail : kristianl@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_
|
#ifndef _xboxrecv_h_
|
||||||
|
@ -129,9 +131,10 @@ public:
|
||||||
void setLedOn(uint8_t controller, LED l);
|
void setLedOn(uint8_t controller, LED l);
|
||||||
void setLedBlink(uint8_t controller, LED l);
|
void setLedBlink(uint8_t controller, LED l);
|
||||||
void setLedMode(uint8_t controller, LEDMode lm);
|
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 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:
|
protected:
|
||||||
/* Mandatory members */
|
/* Mandatory members */
|
||||||
|
@ -147,10 +150,13 @@ private:
|
||||||
uint32_t OldButtonState[4];
|
uint32_t OldButtonState[4];
|
||||||
uint16_t ButtonClickState[4];
|
uint16_t ButtonClickState[4];
|
||||||
int16_t hatValue[4][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 L2Clicked[4]; // These buttons are analog, so we use we use these bools to check if they where clicked or not
|
||||||
bool R2Clicked[4];
|
bool R2Clicked[4];
|
||||||
|
|
||||||
|
unsigned long timer; // Timing for checkStatus() signals
|
||||||
|
|
||||||
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
|
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
|
||||||
uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data
|
uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data
|
||||||
|
|
||||||
|
@ -159,5 +165,6 @@ private:
|
||||||
|
|
||||||
/* Private commands */
|
/* Private commands */
|
||||||
void XboxCommand(uint8_t controller, uint8_t* data, uint16_t nbytes);
|
void XboxCommand(uint8_t controller, uint8_t* data, uint16_t nbytes);
|
||||||
|
void checkStatus();
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
Loading…
Reference in a new issue