1
0
mirror of https://github.com/gdsports/USBHost_t36 synced 2024-11-15 13:45:05 -05:00

Merge pull request #14 from KurtE/Joystick_More_Axis_Rumble

Joystick - USB enhance More Axis, Rumble, LEDS
This commit is contained in:
Paul Stoffregen 2018-01-14 19:31:25 -08:00 committed by GitHub
commit 84d1df0065
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 380 additions and 36 deletions

View File

@ -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 };
@ -783,9 +787,19 @@ public:
bool available() { return joystickEvent; } bool available() { return joystickEvent; }
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[];

View File

@ -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();
for (uint8_t i = 0; axis_mask != 0; i++, axis_mask >>= 1) { Serial.print(buttons, HEX);
if (axis_mask & 1) { //Serial.printf(" AMasks: %x %x:%x", axis_mask, (uint32_t)(user_axis_mask >> 32), (uint32_t)(user_axis_mask & 0xffffffff));
Serial.printf(" %d:%d", i, joystick1.getAxis(i)); //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) {
if (axis_mask & 1) {
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
View File

@ -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);

View File

@ -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;
anychange = true; axis_changed_mask_ |= (1 << i);
if (axis_changed_mask_ & axis_change_notify_mask_)
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,15 +348,12 @@ 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
// Lets do some verifications to make sure. // Lets do some verifications to make sure.
@ -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
} }

View File

@ -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