Skip to content

Commit e81aa92

Browse files
authored
Merge pull request #6 from dmadison/recv-callback
Receive Callback
2 parents 87b5507 + dfc7a91 commit e81aa92

7 files changed

Lines changed: 122 additions & 16 deletions

File tree

examples/BasicGamepad/BasicGamepad.ino

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,4 @@ void loop() {
7474

7575
// Send control data to the computer
7676
XInput.send();
77-
78-
// Receive data (player number, rumble motors, etc.)
79-
XInput.receive();
8077
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Project Arduino XInput Library
3+
* @author David Madison
4+
* @link github.com/dmadison/ArduinoXInput
5+
* @license MIT - Copyright (c) 2019 David Madison
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
* THE SOFTWARE.
24+
*
25+
* Example: ReceiveCallback
26+
* Description: Shows how to set up a custom callback to process rumble or LED
27+
* data when the device receives a new USB packet from the host.
28+
*
29+
* WARNING: The callback is called from within the USB ISR. Keep it short!
30+
*
31+
*/
32+
33+
#include <XInput.h>
34+
35+
const uint8_t LED_Pin = LED_BUILTIN;
36+
const uint8_t Button_Pin = 6;
37+
38+
void setup() {
39+
pinMode(Button_Pin, INPUT_PULLUP); // Set button pin as input w/ pullup
40+
41+
pinMode(LED_Pin, OUTPUT); // Set LED pin as output
42+
digitalWrite(LED_Pin, LOW); // Turn LED off
43+
44+
// Set callback function. Function must have a 'void' return type
45+
// and take a single uint8_t as an argument
46+
XInput.setReceiveCallback(rumbleCallback);
47+
}
48+
49+
void loop() {
50+
boolean buttonState = digitalRead(Button_Pin);
51+
52+
if(buttonState == LOW) {
53+
XInput.press(TRIGGER_RIGHT);
54+
}
55+
else {
56+
XInput.release(TRIGGER_RIGHT);
57+
}
58+
59+
XInput.send();
60+
}
61+
62+
void rumbleCallback(uint8_t packetType) {
63+
// If we have an LED packet (0x01), do nothing
64+
if (packetType == (uint8_t) XInputReceiveType::LEDs) {
65+
return;
66+
}
67+
68+
// If we have a rumble packet (0x00), see our rumble data on the LED
69+
else if (packetType == (uint8_t) XInputReceiveType::Rumble) {
70+
uint8_t rumbleValue = XInput.getRumbleLeft() | XInput.getRumbleRight();
71+
analogWrite(LED_Pin, rumbleValue);
72+
}
73+
}

examples/TestAll/TestAll.ino

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,4 @@ void loop() {
135135

136136
// Send values to PC
137137
XInput.send();
138-
139-
// Receive data from PC
140-
XInput.receive();
141138
}

examples/WiiClassicController/WiiClassicController.ino

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,5 +77,4 @@ void loop() {
7777
}
7878

7979
XInput.send();
80-
XInput.receive();
8180
}

keywords.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ XInputGamepad KEYWORD1
1414

1515
# Enums
1616
XInputControl KEYWORD1
17+
XInputReceiveType KEYWORD1
1718
XInputLEDPattern KEYWORD1
1819

1920
#######################################
@@ -43,8 +44,9 @@ getPlayer KEYWORD2
4344
getRumble KEYWORD2
4445
getRumbleLeft KEYWORD2
4546
getRumbleRight KEYWORD2
47+
getLEDPattern KEYWORD2
4648

47-
getLEDPatternID KEYWORD2
49+
setReceiveCallback KEYWORD2
4850

4951
# USB I/O
5052
connected KEYWORD2
@@ -89,6 +91,10 @@ TRIGGER_RIGHT LITERAL1
8991
JOY_LEFT LITERAL1
9092
JOY_RIGHT LITERAL1
9193

94+
# USB Receive Packet Types
95+
Rumble LITERAL1
96+
LEDs LITERAL1
97+
9298
# LED Patterns
9399
Off LITERAL1
94100
Blinking LITERAL1

src/XInput.cpp

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,16 @@ struct XInputMap_Rumble {
167167
static const XInputMap_Rumble RumbleLeft(3, 0); // Large motor
168168
static const XInputMap_Rumble RumbleRight(4, 1); // Small motor
169169

170+
// --------------------------------------------------------
171+
// XInput USB Receive Callback |
172+
// --------------------------------------------------------
173+
174+
#ifdef USB_XINPUT
175+
static void XInputLib_Receive_Callback() {
176+
XInput.receive();
177+
}
178+
#endif
179+
170180

171181
// --------------------------------------------------------
172182
// XInputGamepad Class (API) |
@@ -176,6 +186,9 @@ XInputGamepad::XInputGamepad() :
176186
tx(), rumble() // Zero initialize arrays
177187
{
178188
reset();
189+
#ifdef USB_XINPUT
190+
XInputUSB::setRecvCallback(XInputLib_Receive_Callback);
191+
#endif
179192
}
180193

181194
void XInputGamepad::press(XInputControl button) {
@@ -300,8 +313,8 @@ XInputLEDPattern XInputGamepad::getLEDPattern() const {
300313
return ledPattern;
301314
}
302315

303-
uint8_t XInputGamepad::getLEDPatternID() const {
304-
return (uint8_t)ledPattern;
316+
void XInputGamepad::setReceiveCallback(RecvCallbackType cback) {
317+
recvCallback = cback;
305318
}
306319

307320
boolean XInputGamepad::connected() {
@@ -334,16 +347,24 @@ size_t XInputGamepad::receive() {
334347
// Grab packet and store it in rx array
335348
uint8_t rx[8];
336349
size_t bytesRecv = XInputUSB::recv(rx, USB_Timeout);
350+
351+
const uint8_t PacketType = rx[0];
337352

338353
// Rumble Packet
339-
if ((rx[0] == 0x00) & (rx[1] == 0x08)) {
354+
if(PacketType == (uint8_t) XInputReceiveType::Rumble) {
340355
rumble[RumbleLeft.bufferIndex] = rx[RumbleLeft.rxIndex]; // Big weight (Left grip)
341356
rumble[RumbleRight.bufferIndex] = rx[RumbleRight.rxIndex]; // Small weight (Right grip)
342357
}
343358
// LED Packet
344-
else if (rx[0] == 0x01) {
359+
else if (PacketType == (uint8_t) XInputReceiveType::LEDs) {
345360
parseLED(rx[2]);
346361
}
362+
363+
// User-defined receive callback
364+
if (recvCallback != nullptr) {
365+
recvCallback(PacketType);
366+
}
367+
347368
return bytesRecv;
348369
#else
349370
return 0;
@@ -431,6 +452,9 @@ void XInputGamepad::reset() {
431452
// Reset rescale ranges
432453
setTriggerRange(XInputMap_Trigger::range.min, XInputMap_Trigger::range.max);
433454
setJoystickRange(XInputMap_Joystick::range.min, XInputMap_Joystick::range.max);
455+
456+
// Clear user-set receive callback
457+
recvCallback = nullptr;
434458
}
435459

436460
void XInputGamepad::printDebug(Print &output) const {

src/XInput.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ enum XInputControl {
5151
JOY_RIGHT,
5252
};
5353

54+
enum class XInputReceiveType {
55+
Rumble = 0x00,
56+
LEDs = 0x01,
57+
};
58+
5459
enum class XInputLEDPattern {
5560
Off = 0x00,
5661
Blinking = 0x01,
@@ -96,13 +101,17 @@ class XInputGamepad {
96101

97102
// Received Data
98103
uint8_t getPlayer() const; // Player # assigned to the controller (0 is unassigned)
104+
99105
uint16_t getRumble() const; // Rumble motors. MSB is large weight, LSB is small
100-
uint8_t getRumbleLeft() const; // Large rumble motor, left grip
101-
uint8_t getRumbleRight() const; // Small rumble motor, right grip
102-
103-
uint8_t getLEDPatternID() const; // Returns LED pattern ID #
106+
uint8_t getRumbleLeft() const; // Large rumble motor, left grip
107+
uint8_t getRumbleRight() const; // Small rumble motor, right grip
108+
104109
XInputLEDPattern getLEDPattern() const; // Returns LED pattern type
105110

111+
// Received Data Callback
112+
using RecvCallbackType = void(*)(uint8_t packetType);
113+
void setReceiveCallback(RecvCallbackType);
114+
106115
// USB IO
107116
boolean connected();
108117
size_t send();
@@ -126,6 +135,7 @@ class XInputGamepad {
126135
uint8_t tx[20]; // USB transmit data
127136
boolean newData; // Flag for tx data changed
128137

138+
RecvCallbackType recvCallback;
129139
uint8_t player; // Gamepad player #, buffered
130140
uint8_t rumble[2]; // Rumble motor data in, buffered
131141
XInputLEDPattern ledPattern; // LED pattern data in, buffered

0 commit comments

Comments
 (0)