mirror of
https://github.com/gdsports/USBHost_t36
synced 2024-11-15 21:55:01 -05:00
Merge pull request #14 from KurtE/Joystick_More_Axis_Rumble
Joystick - USB enhance More Axis, Rumble, LEDS
This commit is contained in:
commit
84d1df0065
@ -603,7 +603,11 @@ class USBHIDParser : public USBDriver {
|
|||||||
public:
|
public:
|
||||||
USBHIDParser(USBHost &host) { init(); }
|
USBHIDParser(USBHost &host) { init(); }
|
||||||
static void driver_ready_for_hid_collection(USBHIDInput *driver);
|
static void driver_ready_for_hid_collection(USBHIDInput *driver);
|
||||||
bool sendPacket(const uint8_t *buffer);
|
bool sendPacket(const uint8_t *buffer, int cb=-1);
|
||||||
|
void setTXBuffers(uint8_t *buffer1, uint8_t *buffer2, uint8_t cb);
|
||||||
|
|
||||||
|
bool sendControlPacket(uint32_t bmRequestType, uint32_t bRequest,
|
||||||
|
uint32_t wValue, uint32_t wIndex, uint32_t wLength, void *buf);
|
||||||
protected:
|
protected:
|
||||||
enum { TOPUSAGE_LIST_LEN = 4 };
|
enum { TOPUSAGE_LIST_LEN = 4 };
|
||||||
enum { USAGE_LIST_LEN = 24 };
|
enum { USAGE_LIST_LEN = 24 };
|
||||||
@ -784,8 +788,18 @@ public:
|
|||||||
void joystickDataClear();
|
void joystickDataClear();
|
||||||
uint32_t getButtons() { return buttons; }
|
uint32_t getButtons() { return buttons; }
|
||||||
int getAxis(uint32_t index) { return (index < (sizeof(axis)/sizeof(axis[0]))) ? axis[index] : 0; }
|
int getAxis(uint32_t index) { return (index < (sizeof(axis)/sizeof(axis[0]))) ? axis[index] : 0; }
|
||||||
uint32_t axisMask() {return axis_mask_;}
|
uint64_t axisMask() {return axis_mask_;}
|
||||||
enum { AXIS_COUNT = 10 };
|
uint64_t axisChangedMask() { return axis_changed_mask_;}
|
||||||
|
uint64_t axisChangeNotifyMask() {return axis_change_notify_mask_;}
|
||||||
|
void axisChangeNotifyMask(uint64_t notify_mask) {axis_change_notify_mask_ = notify_mask;}
|
||||||
|
|
||||||
|
// set functions functionality depends on underlying joystick.
|
||||||
|
bool setRumble(uint8_t lValue, uint8_t rValue, uint8_t timeout=0xff);
|
||||||
|
// setLEDs on PS4(RGB), PS3 simple LED setting (only uses lr)
|
||||||
|
bool setLEDs(uint8_t lr, uint8_t lg=0, uint8_t lb=0); // sets Leds,
|
||||||
|
enum { STANDARD_AXIS_COUNT = 10, ADDITIONAL_AXIS_COUNT = 54, TOTAL_AXIS_COUNT = (STANDARD_AXIS_COUNT+ADDITIONAL_AXIS_COUNT) };
|
||||||
|
typedef enum { UNKNOWN=0, PS3, PS4, XBOXONE} joytype_t;
|
||||||
|
joytype_t joystickType = UNKNOWN;
|
||||||
protected:
|
protected:
|
||||||
// From USBDriver
|
// From USBDriver
|
||||||
virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len);
|
virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len);
|
||||||
@ -798,16 +812,34 @@ protected:
|
|||||||
virtual void hid_input_data(uint32_t usage, int32_t value);
|
virtual void hid_input_data(uint32_t usage, int32_t value);
|
||||||
virtual void hid_input_end();
|
virtual void hid_input_end();
|
||||||
virtual void disconnect_collection(Device_t *dev);
|
virtual void disconnect_collection(Device_t *dev);
|
||||||
|
virtual bool hid_process_out_data(const Transfer_t *transfer);
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Class specific
|
// Class specific
|
||||||
void init();
|
void init();
|
||||||
|
USBHIDParser *driver_ = nullptr;
|
||||||
|
joytype_t mapVIDPIDtoJoystickType(uint16_t idVendor, uint16_t idProduct, bool exclude_hid_devices);
|
||||||
|
bool transmitPS4UserFeedbackMsg();
|
||||||
|
bool transmitPS3UserFeedbackMsg();
|
||||||
|
|
||||||
bool anychange = false;
|
bool anychange = false;
|
||||||
volatile bool joystickEvent = false;
|
volatile bool joystickEvent = false;
|
||||||
uint32_t buttons = 0;
|
uint32_t buttons = 0;
|
||||||
int axis[AXIS_COUNT] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
int axis[TOTAL_AXIS_COUNT] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
uint32_t axis_mask_ = 0; // which axis have valid data
|
uint64_t axis_mask_ = 0; // which axis have valid data
|
||||||
|
uint64_t axis_changed_mask_ = 0;
|
||||||
|
uint64_t axis_change_notify_mask_ = 0x3ff; // assume the low 10 values only.
|
||||||
|
|
||||||
|
uint16_t additional_axis_usage_page_ = 0;
|
||||||
|
uint16_t additional_axis_usage_start_ = 0;
|
||||||
|
uint16_t additional_axis_usage_count_ = 0;
|
||||||
|
|
||||||
|
// State values to output to Joystick.
|
||||||
|
uint8_t rumble_lValue_ = 0;
|
||||||
|
uint8_t rumble_rValue_ = 0;
|
||||||
|
uint8_t rumble_timeout_ = 0;
|
||||||
|
uint8_t leds_[3] = {0,0,0};
|
||||||
|
|
||||||
|
|
||||||
// Used by HID code
|
// Used by HID code
|
||||||
uint8_t collections_claimed = 0;
|
uint8_t collections_claimed = 0;
|
||||||
@ -827,11 +859,13 @@ private:
|
|||||||
Pipe_t *rxpipe_;
|
Pipe_t *rxpipe_;
|
||||||
Pipe_t *txpipe_;
|
Pipe_t *txpipe_;
|
||||||
uint8_t rxbuf_[64]; // receive circular buffer
|
uint8_t rxbuf_[64]; // receive circular buffer
|
||||||
|
uint8_t txbuf_[64]; // buffer to use to send commands to joystick
|
||||||
// Mapping table to say which devices we handle
|
// Mapping table to say which devices we handle
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint16_t idVendor;
|
uint16_t idVendor;
|
||||||
uint16_t idProduct;
|
uint16_t idProduct;
|
||||||
|
joytype_t joyType;
|
||||||
|
bool hidDevice;
|
||||||
} product_vendor_mapping_t;
|
} product_vendor_mapping_t;
|
||||||
static product_vendor_mapping_t pid_vid_mapping[];
|
static product_vendor_mapping_t pid_vid_mapping[];
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ USBHub hub1(myusb);
|
|||||||
USBHub hub2(myusb);
|
USBHub hub2(myusb);
|
||||||
KeyboardController keyboard1(myusb);
|
KeyboardController keyboard1(myusb);
|
||||||
KeyboardController keyboard2(myusb);
|
KeyboardController keyboard2(myusb);
|
||||||
//KeyboardHIDExtrasController hidextras(myusb);
|
|
||||||
USBHIDParser hid1(myusb);
|
USBHIDParser hid1(myusb);
|
||||||
USBHIDParser hid2(myusb);
|
USBHIDParser hid2(myusb);
|
||||||
USBHIDParser hid3(myusb);
|
USBHIDParser hid3(myusb);
|
||||||
@ -17,6 +16,8 @@ USBHIDParser hid4(myusb);
|
|||||||
USBHIDParser hid5(myusb);
|
USBHIDParser hid5(myusb);
|
||||||
MouseController mouse1(myusb);
|
MouseController mouse1(myusb);
|
||||||
JoystickController joystick1(myusb);
|
JoystickController joystick1(myusb);
|
||||||
|
int user_axis[64];
|
||||||
|
uint32_t buttons_prev = 0;
|
||||||
RawHIDController rawhid1(myusb);
|
RawHIDController rawhid1(myusb);
|
||||||
RawHIDController rawhid2(myusb, 0xffc90004);
|
RawHIDController rawhid2(myusb, 0xffc90004);
|
||||||
|
|
||||||
@ -30,7 +31,11 @@ USBHIDInput *hiddrivers[] = {&mouse1, &joystick1, &rawhid1, &rawhid2};
|
|||||||
#define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0]))
|
#define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0]))
|
||||||
const char * hid_driver_names[CNT_DEVICES] = {"Mouse1","Joystick1", "RawHid1", "RawHid2"};
|
const char * hid_driver_names[CNT_DEVICES] = {"Mouse1","Joystick1", "RawHid1", "RawHid2"};
|
||||||
bool hid_driver_active[CNT_DEVICES] = {false, false};
|
bool hid_driver_active[CNT_DEVICES] = {false, false};
|
||||||
|
bool show_changed_only = false;
|
||||||
|
|
||||||
|
uint8_t joystick_left_trigger_value = 0;
|
||||||
|
uint8_t joystick_right_trigger_value = 0;
|
||||||
|
uint64_t joystick_full_notify_mask = (uint64_t)-1;
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
@ -54,6 +59,27 @@ void loop()
|
|||||||
{
|
{
|
||||||
myusb.Task();
|
myusb.Task();
|
||||||
|
|
||||||
|
if (Serial.available()) {
|
||||||
|
int ch = Serial.read(); // get the first char.
|
||||||
|
while (Serial.read() != -1) ;
|
||||||
|
if ((ch == 'b') || (ch == 'B')) {
|
||||||
|
Serial.println("Only notify on Basic Axis changes");
|
||||||
|
joystick1.axisChangeNotifyMask(0x3ff);
|
||||||
|
} else if ((ch == 'f') || (ch == 'F')) {
|
||||||
|
Serial.println("Only notify on Full Axis changes");
|
||||||
|
joystick1.axisChangeNotifyMask(joystick_full_notify_mask);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (show_changed_only) {
|
||||||
|
show_changed_only = false;
|
||||||
|
Serial.println("\n*** Show All fields mode ***");
|
||||||
|
} else {
|
||||||
|
show_changed_only = true;
|
||||||
|
Serial.println("\n*** Show only changed fields mode ***");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (uint8_t i = 0; i < CNT_DEVICES; i++) {
|
for (uint8_t i = 0; i < CNT_DEVICES; i++) {
|
||||||
if (*drivers[i] != driver_active[i]) {
|
if (*drivers[i] != driver_active[i]) {
|
||||||
if (driver_active[i]) {
|
if (driver_active[i]) {
|
||||||
@ -109,14 +135,75 @@ void loop()
|
|||||||
mouse1.mouseDataClear();
|
mouse1.mouseDataClear();
|
||||||
}
|
}
|
||||||
if (joystick1.available()) {
|
if (joystick1.available()) {
|
||||||
uint32_t axis_mask = joystick1.axisMask();
|
uint64_t axis_mask = joystick1.axisMask();
|
||||||
|
uint64_t axis_changed_mask = joystick1.axisChangedMask();
|
||||||
Serial.print("Joystick: buttons = ");
|
Serial.print("Joystick: buttons = ");
|
||||||
Serial.print(joystick1.getButtons(), HEX);
|
uint32_t buttons = joystick1.getButtons();
|
||||||
|
Serial.print(buttons, HEX);
|
||||||
|
//Serial.printf(" AMasks: %x %x:%x", axis_mask, (uint32_t)(user_axis_mask >> 32), (uint32_t)(user_axis_mask & 0xffffffff));
|
||||||
|
//Serial.printf(" M: %lx %lx", axis_mask, joystick1.axisChangedMask());
|
||||||
|
if (show_changed_only) {
|
||||||
|
for (uint8_t i = 0; axis_changed_mask != 0; i++, axis_changed_mask >>= 1) {
|
||||||
|
if (axis_changed_mask & 1) {
|
||||||
|
Serial.printf(" %d:%d", i, joystick1.getAxis(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
for (uint8_t i = 0; axis_mask != 0; i++, axis_mask >>= 1) {
|
for (uint8_t i = 0; axis_mask != 0; i++, axis_mask >>= 1) {
|
||||||
if (axis_mask & 1) {
|
if (axis_mask & 1) {
|
||||||
Serial.printf(" %d:%d", i, joystick1.getAxis(i));
|
Serial.printf(" %d:%d", i, joystick1.getAxis(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
uint8_t ltv;
|
||||||
|
uint8_t rtv;
|
||||||
|
switch (joystick1.joystickType) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case JoystickController::PS4:
|
||||||
|
ltv = joystick1.getAxis(3);
|
||||||
|
rtv = joystick1.getAxis(4);
|
||||||
|
if ((ltv != joystick_left_trigger_value) || (rtv != joystick_right_trigger_value)) {
|
||||||
|
joystick_left_trigger_value = ltv;
|
||||||
|
joystick_right_trigger_value = rtv;
|
||||||
|
joystick1.setRumble(ltv, rtv);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JoystickController::PS3:
|
||||||
|
ltv = joystick1.getAxis(18);
|
||||||
|
rtv = joystick1.getAxis(19);
|
||||||
|
if ((ltv != joystick_left_trigger_value) || (rtv != joystick_right_trigger_value)) {
|
||||||
|
joystick_left_trigger_value = ltv;
|
||||||
|
joystick_right_trigger_value = rtv;
|
||||||
|
joystick1.setRumble(ltv, rtv, 50);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JoystickController::XBOXONE:
|
||||||
|
ltv = joystick1.getAxis(4);
|
||||||
|
rtv = joystick1.getAxis(5);
|
||||||
|
if ((ltv != joystick_left_trigger_value) || (rtv != joystick_right_trigger_value)) {
|
||||||
|
joystick_left_trigger_value = ltv;
|
||||||
|
joystick_right_trigger_value = rtv;
|
||||||
|
joystick1.setRumble(ltv, rtv);
|
||||||
|
Serial.printf(" Set Rumble %d %d", ltv, rtv);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (buttons != buttons_prev) {
|
||||||
|
if (joystick1.joystickType == JoystickController::PS3) {
|
||||||
|
joystick1.setLEDs((buttons>>12) & 0xf); // try to get to TRI/CIR/X/SQuare
|
||||||
|
} else {
|
||||||
|
uint8_t lr = (buttons & 1)? 0xff : 0;
|
||||||
|
uint8_t lg = (buttons & 2)? 0xff : 0;
|
||||||
|
uint8_t lb = (buttons & 4)? 0xff : 0;
|
||||||
|
joystick1.setLEDs(lr, lg, lb);
|
||||||
|
}
|
||||||
|
buttons_prev = buttons;
|
||||||
|
}
|
||||||
|
|
||||||
Serial.println();
|
Serial.println();
|
||||||
joystick1.joystickDataClear();
|
joystick1.joystickDataClear();
|
||||||
}
|
}
|
||||||
|
53
hid.cpp
53
hid.cpp
@ -205,13 +205,12 @@ void USBHIDParser::disconnect()
|
|||||||
// Called when the HID device sends a report
|
// Called when the HID device sends a report
|
||||||
void USBHIDParser::in_data(const Transfer_t *transfer)
|
void USBHIDParser::in_data(const Transfer_t *transfer)
|
||||||
{
|
{
|
||||||
/*Serial.print("HID: ");
|
/*Serial.printf("HID: ");
|
||||||
uint8_t *pb = (uint8_t*)transfer->buffer;
|
uint8_t *pb = (uint8_t*)transfer->buffer;
|
||||||
for (uint8_t i = 0; i < transfer->length; i++) {
|
for (uint8_t i = 0; i < transfer->length; i++) {
|
||||||
Serial.print(pb[i], HEX);
|
Serial.printf("%x ",pb[i]);
|
||||||
Serial.print(" ");
|
|
||||||
}
|
}
|
||||||
Serial.println(); */
|
Serial.printf("\n"); */
|
||||||
|
|
||||||
print("HID: ");
|
print("HID: ");
|
||||||
print(use_report_id);
|
print(use_report_id);
|
||||||
@ -249,7 +248,7 @@ void USBHIDParser::out_data(const Transfer_t *transfer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool USBHIDParser::sendPacket(const uint8_t *buffer) {
|
bool USBHIDParser::sendPacket(const uint8_t *buffer, int cb) {
|
||||||
if (!out_size || !out_pipe) return false;
|
if (!out_size || !out_pipe) return false;
|
||||||
if (!tx1) {
|
if (!tx1) {
|
||||||
// Was not init before, for now lets put it at end of descriptor
|
// Was not init before, for now lets put it at end of descriptor
|
||||||
@ -259,22 +258,40 @@ bool USBHIDParser::sendPacket(const uint8_t *buffer) {
|
|||||||
tx2 = tx1 - out_size;
|
tx2 = tx1 - out_size;
|
||||||
}
|
}
|
||||||
if ((txstate & 3) == 3) return false; // both transmit buffers are full
|
if ((txstate & 3) == 3) return false; // both transmit buffers are full
|
||||||
|
if (cb == -1)
|
||||||
|
cb = out_size;
|
||||||
uint8_t *p = tx1;
|
uint8_t *p = tx1;
|
||||||
if ((txstate & 1) == 0) {
|
if ((txstate & 1) == 0) {
|
||||||
txstate |= 1;
|
txstate |= 1;
|
||||||
} else {
|
} else {
|
||||||
|
if (!tx2)
|
||||||
|
return false; // only one buffer
|
||||||
txstate |= 2;
|
txstate |= 2;
|
||||||
p = tx2;
|
p = tx2;
|
||||||
}
|
}
|
||||||
// copy the users data into our out going buffer
|
// copy the users data into our out going buffer
|
||||||
memcpy(p, buffer, out_size);
|
memcpy(p, buffer, cb);
|
||||||
println("USBHIDParser Send packet");
|
println("USBHIDParser Send packet");
|
||||||
print_hexbytes(buffer, out_size);
|
print_hexbytes(buffer, cb);
|
||||||
queue_Data_Transfer(out_pipe, p, out_size, this);
|
queue_Data_Transfer(out_pipe, p, cb, this);
|
||||||
println(" Queue_data transfer returned");
|
println(" Queue_data transfer returned");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void USBHIDParser::setTXBuffers(uint8_t *buffer1, uint8_t *buffer2, uint8_t cb)
|
||||||
|
{
|
||||||
|
tx1 = buffer1;
|
||||||
|
tx2 = buffer2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool USBHIDParser::sendControlPacket(uint32_t bmRequestType, uint32_t bRequest,
|
||||||
|
uint32_t wValue, uint32_t wIndex, uint32_t wLength, void *buf)
|
||||||
|
{
|
||||||
|
// Use setup structure to build packet
|
||||||
|
mk_setup(setup, bmRequestType, bRequest, wValue, wIndex, wLength); // ps3 tell to send report 1?
|
||||||
|
return queue_Control_Transfer(device, &setup, buf, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// This no-inputs parse is meant to be used when we first get the
|
// This no-inputs parse is meant to be used when we first get the
|
||||||
// HID report descriptor. It finds all the top level collections
|
// HID report descriptor. It finds all the top level collections
|
||||||
@ -444,6 +461,7 @@ void USBHIDParser::parse(uint16_t type_and_report_id, const uint8_t *data, uint3
|
|||||||
uint16_t report_size = 0;
|
uint16_t report_size = 0;
|
||||||
uint16_t report_count = 0;
|
uint16_t report_count = 0;
|
||||||
uint16_t usage_page = 0;
|
uint16_t usage_page = 0;
|
||||||
|
uint32_t last_usage = 0;
|
||||||
int32_t logical_min = 0;
|
int32_t logical_min = 0;
|
||||||
int32_t logical_max = 0;
|
int32_t logical_max = 0;
|
||||||
uint32_t bitindex = 0;
|
uint32_t bitindex = 0;
|
||||||
@ -551,23 +569,38 @@ void USBHIDParser::parse(uint16_t type_and_report_id, const uint8_t *data, uint3
|
|||||||
if ((val & 2)) {
|
if ((val & 2)) {
|
||||||
// ordinary variable format
|
// ordinary variable format
|
||||||
uint32_t uindex = 0;
|
uint32_t uindex = 0;
|
||||||
|
uint32_t uindex_max = 0xffff; // assume no MAX
|
||||||
bool uminmax = false;
|
bool uminmax = false;
|
||||||
if (usage_count > USAGE_LIST_LEN || usage_count == 0) {
|
if (usage_count > USAGE_LIST_LEN) {
|
||||||
// usage numbers by min/max, not from list
|
// usage numbers by min/max, not from list
|
||||||
uindex = usage[0];
|
uindex = usage[0];
|
||||||
|
uindex_max = usage[1];
|
||||||
|
uminmax = true;
|
||||||
|
} else if ((report_count > 1) && (usage_count <= 1)) {
|
||||||
|
// Special cases: Either only one or no usages specified and there are more than one
|
||||||
|
// report counts .
|
||||||
|
if (usage_count == 1) {
|
||||||
|
uindex = usage[0];
|
||||||
|
} else {
|
||||||
|
// BUGBUG:: Not sure good place to start? maybe round up from last usage to next higher group up of 0x100?
|
||||||
|
uindex = (last_usage & 0xff00) + 0x100;
|
||||||
|
}
|
||||||
uminmax = true;
|
uminmax = true;
|
||||||
}
|
}
|
||||||
|
//Serial.printf("TU:%x US:%x %x %d %d: C:%d, %d, MM:%d, %x %x\n", topusage, usage_page, val, logical_min, logical_max,
|
||||||
|
// report_count, usage_count, uminmax, usage[0], usage[1]);
|
||||||
for (uint32_t i=0; i < report_count; i++) {
|
for (uint32_t i=0; i < report_count; i++) {
|
||||||
uint32_t u;
|
uint32_t u;
|
||||||
if (uminmax) {
|
if (uminmax) {
|
||||||
u = uindex;
|
u = uindex;
|
||||||
if (uindex < usage[1]) uindex++;
|
if (uindex < uindex_max) uindex++;
|
||||||
} else {
|
} else {
|
||||||
u = usage[uindex++];
|
u = usage[uindex++];
|
||||||
if (uindex >= USAGE_LIST_LEN-1) {
|
if (uindex >= USAGE_LIST_LEN-1) {
|
||||||
uindex = USAGE_LIST_LEN-1;
|
uindex = USAGE_LIST_LEN-1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
last_usage = u; // remember the last one we used...
|
||||||
u |= (uint32_t)usage_page << 16;
|
u |= (uint32_t)usage_page << 16;
|
||||||
print(" usage = ", u, HEX);
|
print(" usage = ", u, HEX);
|
||||||
|
|
||||||
|
203
joystick.cpp
203
joystick.cpp
@ -27,6 +27,18 @@
|
|||||||
#define print USBHost::print_
|
#define print USBHost::print_
|
||||||
#define println USBHost::println_
|
#define println USBHost::println_
|
||||||
|
|
||||||
|
// PID/VID to joystick mapping - Only the XBOXOne is used to claim the USB interface directly,
|
||||||
|
// The others are used after claim-hid code to know which one we have and to use it for
|
||||||
|
// doing other features.
|
||||||
|
JoystickController::product_vendor_mapping_t JoystickController::pid_vid_mapping[] = {
|
||||||
|
{ 0x045e, 0x02ea, XBOXONE, false },{ 0x045e, 0x02dd, XBOXONE, false },
|
||||||
|
{ 0x054C, 0x0268, PS3, true},
|
||||||
|
{ 0x054C, 0x05C4, PS4, true}, {0x054C, 0x09CC, PS4, true }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
void JoystickController::init()
|
void JoystickController::init()
|
||||||
{
|
{
|
||||||
contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t));
|
contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t));
|
||||||
@ -36,6 +48,19 @@ void JoystickController::init()
|
|||||||
USBHIDParser::driver_ready_for_hid_collection(this);
|
USBHIDParser::driver_ready_for_hid_collection(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
JoystickController::joytype_t JoystickController::mapVIDPIDtoJoystickType(uint16_t idVendor, uint16_t idProduct, bool exclude_hid_devices)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < (sizeof(pid_vid_mapping)/sizeof(pid_vid_mapping[0])); i++) {
|
||||||
|
if ((idVendor == pid_vid_mapping[i].idVendor) && (idProduct == pid_vid_mapping[i].idProduct)) {
|
||||||
|
println("Match PID/VID: ", i, DEC);
|
||||||
|
if (exclude_hid_devices && pid_vid_mapping[i].hidDevice) return UNKNOWN;
|
||||||
|
return pid_vid_mapping[i].joyType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UNKNOWN; // Not in our list
|
||||||
|
}
|
||||||
|
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
// Some simple query functions depend on which interface we are using...
|
// Some simple query functions depend on which interface we are using...
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
@ -76,9 +101,109 @@ const uint8_t *JoystickController::serialNumber()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool JoystickController::setRumble(uint8_t lValue, uint8_t rValue, uint8_t timeout)
|
||||||
|
{
|
||||||
|
// Need to know which joystick we are on. Start off with XBox support - maybe need to add some enum value for the known
|
||||||
|
// joystick types.
|
||||||
|
rumble_lValue_ = lValue;
|
||||||
|
rumble_rValue_ = rValue;
|
||||||
|
rumble_timeout_ = timeout;
|
||||||
|
|
||||||
|
switch (joystickType) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case PS3:
|
||||||
|
return transmitPS3UserFeedbackMsg();
|
||||||
|
case PS4:
|
||||||
|
return transmitPS4UserFeedbackMsg();
|
||||||
|
case XBOXONE:
|
||||||
|
// Lets try sending a request to the XBox 1.
|
||||||
|
txbuf_[0] = 0x9;
|
||||||
|
txbuf_[1] = 0x8;
|
||||||
|
txbuf_[2] = 0x0;
|
||||||
|
txbuf_[3] = 0x08; // Substructure (what substructure rest of this packet has)
|
||||||
|
txbuf_[4] = 0x00; // Mode
|
||||||
|
txbuf_[5] = 0x0f; // Rumble mask (what motors are activated) (0000 lT rT L R)
|
||||||
|
txbuf_[6] = 0x0; // lT force
|
||||||
|
txbuf_[7] = 0x0; // rT force
|
||||||
|
txbuf_[8] = lValue; // L force
|
||||||
|
txbuf_[9] = rValue; // R force
|
||||||
|
txbuf_[10] = 0x80; // Length of pulse
|
||||||
|
txbuf_[11] = 0x00; // Period between pulses
|
||||||
|
if (!queue_Data_Transfer(txpipe_, txbuf_, 12, this)) {
|
||||||
|
println("XBoxOne rumble transfer fail");
|
||||||
|
}
|
||||||
|
return true; //
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JoystickController::setLEDs(uint8_t lr, uint8_t lg, uint8_t lb)
|
||||||
|
{
|
||||||
|
// Need to know which joystick we are on. Start off with XBox support - maybe need to add some enum value for the known
|
||||||
|
// joystick types.
|
||||||
|
if ((leds_[0] != lr) || (leds_[1] != lg) || (leds_[2] != lb)) {
|
||||||
|
leds_[0] = lr;
|
||||||
|
leds_[1] = lg;
|
||||||
|
leds_[2] = lb;
|
||||||
|
|
||||||
|
switch (joystickType) {
|
||||||
|
case PS3:
|
||||||
|
return transmitPS3UserFeedbackMsg();
|
||||||
|
case PS4:
|
||||||
|
return transmitPS4UserFeedbackMsg();
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JoystickController::transmitPS4UserFeedbackMsg() {
|
||||||
|
if (!driver_) return false;
|
||||||
|
uint8_t packet[32];
|
||||||
|
memset(packet, 0, sizeof(packet));
|
||||||
|
|
||||||
|
packet[0] = 0x05; // Report ID
|
||||||
|
packet[1]= 0xFF;
|
||||||
|
|
||||||
|
packet[4] = rumble_lValue_; // Small Rumble
|
||||||
|
packet[5] = rumble_rValue_; // Big rumble
|
||||||
|
packet[6] = leds_[0]; // RGB value
|
||||||
|
packet[7] = leds_[1];
|
||||||
|
packet[8] = leds_[2];
|
||||||
|
// 9, 10 flash ON, OFF times in 100ths of sedond? 2.5 seconds = 255
|
||||||
|
Serial.printf("Joystick update Rumble/LEDs");
|
||||||
|
return driver_->sendPacket(packet, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint8_t PS3_USER_FEEDBACK_INIT[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0xff, 0x27, 0x10, 0x00, 0x32,
|
||||||
|
0xff, 0x27, 0x10, 0x00, 0x32,
|
||||||
|
0xff, 0x27, 0x10, 0x00, 0x32,
|
||||||
|
0xff, 0x27, 0x10, 0x00, 0x32,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
|
bool JoystickController::transmitPS3UserFeedbackMsg() {
|
||||||
|
if (!driver_) return false;
|
||||||
|
memcpy(txbuf_, PS3_USER_FEEDBACK_INIT, 48);
|
||||||
|
|
||||||
|
txbuf_[1] = rumble_lValue_? rumble_timeout_ : 0;
|
||||||
|
txbuf_[2] = rumble_lValue_; // Small Rumble
|
||||||
|
txbuf_[3] = rumble_rValue_? rumble_timeout_ : 0;
|
||||||
|
txbuf_[4] = rumble_rValue_; // Big rumble
|
||||||
|
txbuf_[9] = leds_[0] << 1; // RGB value
|
||||||
|
//Serial.printf("\nJoystick update Rumble/LEDs %d %d %d %d %d\n", txbuf_[1], txbuf_[2], txbuf_[3], txbuf_[4], txbuf_[9]);
|
||||||
|
return driver_->sendControlPacket(0x21, 9, 0x201, 0, 48, txbuf_);
|
||||||
|
}
|
||||||
|
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
// Support for Joysticks that USe HID data.
|
// Support for Joysticks that Use HID data.
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
|
|
||||||
hidclaim_t JoystickController::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage)
|
hidclaim_t JoystickController::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage)
|
||||||
@ -90,6 +215,31 @@ hidclaim_t JoystickController::claim_collection(USBHIDParser *driver, Device_t *
|
|||||||
mydevice = dev;
|
mydevice = dev;
|
||||||
collections_claimed++;
|
collections_claimed++;
|
||||||
anychange = true; // always report values on first read
|
anychange = true; // always report values on first read
|
||||||
|
driver_ = driver; // remember the driver.
|
||||||
|
driver_->setTXBuffers(txbuf_, nullptr, sizeof(txbuf_));
|
||||||
|
|
||||||
|
// Lets see if we know what type of joystick this is. That is, is it a PS3 or PS4 or ...
|
||||||
|
joystickType = mapVIDPIDtoJoystickType(mydevice->idVendor, mydevice->idProduct, false);
|
||||||
|
switch (joystickType) {
|
||||||
|
case PS3:
|
||||||
|
additional_axis_usage_page_ = 0x1;
|
||||||
|
additional_axis_usage_start_ = 0x100;
|
||||||
|
additional_axis_usage_count_ = 39;
|
||||||
|
axis_change_notify_mask_ = (uint64_t)-1; // Start off assume all bits
|
||||||
|
break;
|
||||||
|
case PS4:
|
||||||
|
additional_axis_usage_page_ = 0xFF00;
|
||||||
|
additional_axis_usage_start_ = 0x21;
|
||||||
|
additional_axis_usage_count_ = 54;
|
||||||
|
axis_change_notify_mask_ = (uint64_t)0xfffffffffffff3ffl; // Start off assume all bits - 10 and 11
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
additional_axis_usage_page_ = 0;
|
||||||
|
additional_axis_usage_start_ = 0;
|
||||||
|
additional_axis_usage_count_ = 0;
|
||||||
|
axis_change_notify_mask_ = 0x3ff; // Start off assume only the 10 bits...
|
||||||
|
}
|
||||||
|
Serial.printf("Claim Additional axis: %x %x %d\n", additional_axis_usage_page_, additional_axis_usage_start_, additional_axis_usage_count_);
|
||||||
return CLAIM_REPORT;
|
return CLAIM_REPORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +247,9 @@ void JoystickController::disconnect_collection(Device_t *dev)
|
|||||||
{
|
{
|
||||||
if (--collections_claimed == 0) {
|
if (--collections_claimed == 0) {
|
||||||
mydevice = NULL;
|
mydevice = NULL;
|
||||||
|
driver_ = nullptr;
|
||||||
axis_mask_ = 0;
|
axis_mask_ = 0;
|
||||||
|
axis_changed_mask_ = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,8 +283,32 @@ void JoystickController::hid_input_data(uint32_t usage, int32_t value)
|
|||||||
axis_mask_ |= (1 << i); // Keep record of which axis we have data on.
|
axis_mask_ |= (1 << i); // Keep record of which axis we have data on.
|
||||||
if (axis[i] != value) {
|
if (axis[i] != value) {
|
||||||
axis[i] = value;
|
axis[i] = value;
|
||||||
|
axis_changed_mask_ |= (1 << i);
|
||||||
|
if (axis_changed_mask_ & axis_change_notify_mask_)
|
||||||
anychange = true;
|
anychange = true;
|
||||||
}
|
}
|
||||||
|
} else if (usage_page == additional_axis_usage_page_) {
|
||||||
|
// see if the usage is witin range.
|
||||||
|
//Serial.printf("UP: usage_page=%x usage=%x User: %x %d\n", usage_page, usage, user_buttons_usage_start, user_buttons_count_);
|
||||||
|
if ((usage >= additional_axis_usage_start_) && (usage < (additional_axis_usage_start_ + additional_axis_usage_count_))) {
|
||||||
|
// We are in the user range.
|
||||||
|
uint16_t usage_index = usage - additional_axis_usage_start_ + STANDARD_AXIS_COUNT;
|
||||||
|
if (usage_index < (sizeof(axis)/sizeof(axis[0]))) {
|
||||||
|
if (axis[usage_index] != value) {
|
||||||
|
axis[usage_index] = value;
|
||||||
|
if (usage_index > 63) usage_index = 63; // don't overflow our mask
|
||||||
|
axis_changed_mask_ |= ((uint64_t)1 << usage_index); // Keep track of which ones changed.
|
||||||
|
if (axis_changed_mask_ & axis_change_notify_mask_)
|
||||||
|
anychange = true; // We have changes...
|
||||||
|
}
|
||||||
|
axis_mask_ |= ((uint64_t)1 << usage_index); // Keep record of which axis we have data on.
|
||||||
|
}
|
||||||
|
//Serial.printf("UB: index=%x value=%x\n", usage_index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Serial.printf("UP: usage_page=%x usage=%x add: %x %x %d\n", usage_page, usage, additional_axis_usage_page_, additional_axis_usage_start_, additional_axis_usage_count_);
|
||||||
|
|
||||||
}
|
}
|
||||||
// TODO: hat switch?
|
// TODO: hat switch?
|
||||||
}
|
}
|
||||||
@ -144,18 +320,23 @@ void JoystickController::hid_input_end()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool JoystickController::hid_process_out_data(const Transfer_t *transfer)
|
||||||
|
{
|
||||||
|
Serial.printf("JoystickController::hid_process_out_data\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void JoystickController::joystickDataClear() {
|
void JoystickController::joystickDataClear() {
|
||||||
joystickEvent = false;
|
joystickEvent = false;
|
||||||
anychange = false;
|
anychange = false;
|
||||||
|
axis_changed_mask_ = 0;
|
||||||
|
axis_mask_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
// Support for Joysticks that are class specific and do not use HID
|
// Support for Joysticks that are class specific and do not use HID
|
||||||
// Example: XBox One controller.
|
// Example: XBox One controller.
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
// Note: currently just XBOX one.
|
|
||||||
JoystickController::product_vendor_mapping_t JoystickController::pid_vid_mapping[] = {
|
|
||||||
{ 0x045e, 0x02ea },{ 0x045e, 0x02dd } };
|
|
||||||
|
|
||||||
static uint8_t start_input[] = {0x05, 0x20, 0x00, 0x01, 0x00};
|
static uint8_t start_input[] = {0x05, 0x20, 0x00, 0x01, 0x00};
|
||||||
|
|
||||||
@ -167,13 +348,10 @@ bool JoystickController::claim(Device_t *dev, int type, const uint8_t *descripto
|
|||||||
if (type != 0) return false;
|
if (type != 0) return false;
|
||||||
print_hexbytes(descriptors, len);
|
print_hexbytes(descriptors, len);
|
||||||
|
|
||||||
uint8_t i = 0;
|
JoystickController::joytype_t jtype = mapVIDPIDtoJoystickType(dev->idVendor, dev->idProduct, true);
|
||||||
for (; i < (sizeof(pid_vid_mapping)/sizeof(pid_vid_mapping[0])); i++) {
|
println("Jtype=", (uint8_t)jtype, DEC);
|
||||||
if ((dev->idVendor == pid_vid_mapping[i].idVendor) && (dev->idProduct == pid_vid_mapping[i].idProduct)) {
|
if (jtype == UNKNOWN)
|
||||||
break;
|
return false;
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == (sizeof(pid_vid_mapping)/sizeof(pid_vid_mapping[0]))) return false; // Not in our list
|
|
||||||
|
|
||||||
// 0 1 2 3 4 5 6 7 8 *9 10 1 2 3 4 5 *6 7 8 9 20 1 2 3 4 5 6 7 8 9 30 1...
|
// 0 1 2 3 4 5 6 7 8 *9 10 1 2 3 4 5 *6 7 8 9 20 1 2 3 4 5 6 7 8 9 30 1...
|
||||||
// 09 04 00 00 02 FF 47 D0 00 07 05 02 03 40 00 04 07 05 82 03 40 00 04 09 04 01 00 00 FF 47 D0 00
|
// 09 04 00 00 02 FF 47 D0 00 07 05 02 03 40 00 04 07 05 82 03 40 00 04 09 04 01 00 00 FF 47 D0 00
|
||||||
@ -226,6 +404,7 @@ bool JoystickController::claim(Device_t *dev, int type, const uint8_t *descripto
|
|||||||
|
|
||||||
queue_Data_Transfer(txpipe_, start_input, sizeof(start_input), this);
|
queue_Data_Transfer(txpipe_, start_input, sizeof(start_input), this);
|
||||||
memset(axis, 0, sizeof(axis)); // clear out any data.
|
memset(axis, 0, sizeof(axis)); // clear out any data.
|
||||||
|
joystickType = jtype; // remember we are an XBox One.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,6 +459,7 @@ void JoystickController::rx_data(const Transfer_t *transfer)
|
|||||||
// print("JoystickController::rx_data: ");
|
// print("JoystickController::rx_data: ");
|
||||||
// print_hexbytes((uint8_t*)transfer->buffer, transfer->length);
|
// print_hexbytes((uint8_t*)transfer->buffer, transfer->length);
|
||||||
axis_mask_ = 0x3f;
|
axis_mask_ = 0x3f;
|
||||||
|
axis_changed_mask_ = 0; // assume none for now
|
||||||
xbox1data20_t *xb1d = (xbox1data20_t *)transfer->buffer;
|
xbox1data20_t *xb1d = (xbox1data20_t *)transfer->buffer;
|
||||||
if ((xb1d->type == 0x20) && (transfer->length >= sizeof (xbox1data20_t))) {
|
if ((xb1d->type == 0x20) && (transfer->length >= sizeof (xbox1data20_t))) {
|
||||||
// We have a data transfer. Lets see what is new...
|
// We have a data transfer. Lets see what is new...
|
||||||
@ -309,6 +489,7 @@ void JoystickController::tx_data(const Transfer_t *transfer)
|
|||||||
void JoystickController::disconnect()
|
void JoystickController::disconnect()
|
||||||
{
|
{
|
||||||
axis_mask_ = 0;
|
axis_mask_ = 0;
|
||||||
|
axis_changed_mask_ = 0;
|
||||||
// TODO: free resources
|
// TODO: free resources
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +81,15 @@ getWheelH KEYWORD2
|
|||||||
joystickDataClear KEYWORD2
|
joystickDataClear KEYWORD2
|
||||||
getAxis KEYWORD2
|
getAxis KEYWORD2
|
||||||
axisMask KEYWORD2
|
axisMask KEYWORD2
|
||||||
|
axisChangedMask KEYWORD2
|
||||||
|
axisChangeNotifyMask KEYWORD2
|
||||||
|
userAxisMask KEYWORD2
|
||||||
|
setRumbleOn KEYWORD2
|
||||||
|
setLEDs KEYWORD2
|
||||||
|
joystickType KEYWORD2
|
||||||
|
PS3 LITERAL1
|
||||||
|
PS4 LITERAL1
|
||||||
|
XBOXONE LITERAL1
|
||||||
|
|
||||||
# USBSerial
|
# USBSerial
|
||||||
USBHOST_SERIAL_7E1 LITERAL1
|
USBHOST_SERIAL_7E1 LITERAL1
|
||||||
|
Loading…
Reference in New Issue
Block a user