Merge pull request #365 from felis/xboxone

Added support for rumble effect on Xbox One controllers
This commit is contained in:
Kristian Sloth Lauszus 2018-03-15 23:06:32 +01:00 committed by GitHub
commit 48b7315b7d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 92 additions and 13 deletions

View file

@ -179,10 +179,11 @@ uint8_t XBOXONE::Init(uint8_t parent, uint8_t port, bool lowspeed) {
delay(200); // let things settle delay(200); // let things settle
// Initialize the controller for input // Initialize the controller for input
cmdCounter = 0; // Reset the counter used when sending out the commands
uint8_t writeBuf[5]; uint8_t writeBuf[5];
writeBuf[0] = 0x05; writeBuf[0] = 0x05;
writeBuf[1] = 0x20; writeBuf[1] = 0x20;
writeBuf[2] = 0x00; // Byte 2 is set in "XboxCommand"
writeBuf[3] = 0x01; writeBuf[3] = 0x01;
writeBuf[4] = 0x00; writeBuf[4] = 0x00;
rcode = XboxCommand(writeBuf, 5); rcode = XboxCommand(writeBuf, 5);
@ -402,6 +403,7 @@ int16_t XBOXONE::getAnalogHat(AnalogHatEnum a) {
/* Xbox Controller commands */ /* Xbox Controller commands */
uint8_t XBOXONE::XboxCommand(uint8_t* data, uint16_t nbytes) { uint8_t XBOXONE::XboxCommand(uint8_t* data, uint16_t nbytes) {
data[2] = cmdCounter++; // Increment the output command counter
uint8_t rcode = pUsb->outTransfer(bAddress, epInfo[ XBOX_ONE_OUTPUT_PIPE ].epAddr, nbytes, data); uint8_t rcode = pUsb->outTransfer(bAddress, epInfo[ XBOX_ONE_OUTPUT_PIPE ].epAddr, nbytes, data);
#ifdef DEBUG_USB_HOST #ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nXboxCommand, Return: "), 0x80); Notify(PSTR("\r\nXboxCommand, Return: "), 0x80);
@ -410,22 +412,73 @@ uint8_t XBOXONE::XboxCommand(uint8_t* data, uint16_t nbytes) {
return rcode; return rcode;
} }
// The Xbox One packets are described at: https://github.com/quantus/xbox-one-controller-protocol
void XBOXONE::onInit() { void XBOXONE::onInit() {
// A short buzz to show the controller is active // A short buzz to show the controller is active
uint8_t writeBuf[11]; uint8_t writeBuf[13];
// Activate rumble
writeBuf[0] = 0x09; writeBuf[0] = 0x09;
writeBuf[1] = 0x08; writeBuf[1] = 0x00;
writeBuf[2] = 0x00; // Byte 2 is set in "XboxCommand"
writeBuf[3] = 0x09;
writeBuf[4] = 0x00; // Single rumble effect
writeBuf[5] = 0x0f; writeBuf[3] = 0x09; // Substructure (what substructure rest of this packet has)
writeBuf[6] = 0x04; writeBuf[4] = 0x00; // Mode
writeBuf[7] = 0x04; writeBuf[5] = 0x0F; // Rumble mask (what motors are activated) (0000 lT rT L R)
writeBuf[8] = 0x20; writeBuf[6] = 0x04; // lT force
writeBuf[9] = 0x20; writeBuf[7] = 0x04; // rT force
writeBuf[10] = 0x80; writeBuf[8] = 0x20; // L force
XboxCommand(writeBuf, 11); writeBuf[9] = 0x20; // R force
writeBuf[10] = 0x80; // Length of pulse
writeBuf[11] = 0x00; // Off period
writeBuf[12] = 0x00; // Repeat count
XboxCommand(writeBuf, 13);
if(pFuncOnInit) if(pFuncOnInit)
pFuncOnInit(); // Call the user function pFuncOnInit(); // Call the user function
} }
void XBOXONE::setRumbleOff() {
uint8_t writeBuf[13];
// Activate rumble
writeBuf[0] = 0x09;
writeBuf[1] = 0x00;
// Byte 2 is set in "XboxCommand"
// Continuous rumble effect
writeBuf[3] = 0x09; // Substructure (what substructure rest of this packet has)
writeBuf[4] = 0x00; // Mode
writeBuf[5] = 0x0F; // Rumble mask (what motors are activated) (0000 lT rT L R)
writeBuf[6] = 0x00; // lT force
writeBuf[7] = 0x00; // rT force
writeBuf[8] = 0x00; // L force
writeBuf[9] = 0x00; // R force
writeBuf[10] = 0x00; // On period
writeBuf[11] = 0x00; // Off period
writeBuf[12] = 0x00; // Repeat count
XboxCommand(writeBuf, 13);
}
void XBOXONE::setRumbleOn(uint8_t leftTrigger, uint8_t rightTrigger, uint8_t leftMotor, uint8_t rightMotor) {
uint8_t writeBuf[13];
// Activate rumble
writeBuf[0] = 0x09;
writeBuf[1] = 0x00;
// Byte 2 is set in "XboxCommand"
// Continuous rumble effect
writeBuf[3] = 0x09; // Substructure (what substructure rest of this packet has)
writeBuf[4] = 0x00; // Mode
writeBuf[5] = 0x0F; // Rumble mask (what motors are activated) (0000 lT rT L R)
writeBuf[6] = leftTrigger; // lT force
writeBuf[7] = rightTrigger; // rT force
writeBuf[8] = leftMotor; // L force
writeBuf[9] = rightMotor; // R force
writeBuf[10] = 0xFF; // On period
writeBuf[11] = 0x00; // Off period
writeBuf[12] = 0xFF; // Repeat count
XboxCommand(writeBuf, 13);
}

View file

@ -156,6 +156,18 @@ public:
void attachOnInit(void (*funcOnInit)(void)) { void attachOnInit(void (*funcOnInit)(void)) {
pFuncOnInit = funcOnInit; pFuncOnInit = funcOnInit;
}; };
/** Used to set the rumble off. */
void setRumbleOff();
/**
* Used to turn on rumble continuously.
* @param leftTrigger Left trigger force.
* @param rightTrigger Right trigger force.
* @param leftMotor Left motor force.
* @param rightMotor Right motor force.
*/
void setRumbleOn(uint8_t leftTrigger, uint8_t rightTrigger, uint8_t leftMotor, uint8_t rightMotor);
/**@}*/ /**@}*/
/** True if a Xbox ONE controller is connected. */ /** True if a Xbox ONE controller is connected. */
@ -217,6 +229,7 @@ private:
bool R2Clicked; bool R2Clicked;
uint8_t readBuf[XBOX_ONE_EP_MAXPKTSIZE]; // General purpose buffer for input data uint8_t readBuf[XBOX_ONE_EP_MAXPKTSIZE]; // General purpose buffer for input data
uint8_t cmdCounter;
void readReport(); // Used to read the incoming data void readReport(); // Used to read the incoming data

View file

@ -63,6 +63,19 @@ void loop() {
Serial.println(); Serial.println();
} }
// Set rumble effect
static uint16_t oldL2Value, oldR2Value;
if (Xbox.getButtonPress(L2) != oldL2Value || Xbox.getButtonPress(R2) != oldR2Value) {
oldL2Value = Xbox.getButtonPress(L2);
oldR2Value = Xbox.getButtonPress(R2);
uint8_t leftRumble = map(oldL2Value, 0, 1023, 0, 255); // Map the trigger values into a byte
uint8_t rightRumble = map(oldR2Value, 0, 1023, 0, 255);
if (leftRumble > 0 || rightRumble > 0)
Xbox.setRumbleOn(leftRumble, rightRumble, leftRumble, rightRumble);
else
Xbox.setRumbleOff();
}
if (Xbox.getButtonClick(UP)) if (Xbox.getButtonClick(UP))
Serial.println(F("Up")); Serial.println(F("Up"));
if (Xbox.getButtonClick(DOWN)) if (Xbox.getButtonClick(DOWN))