Joystick - USB enhance More Axis, Rumble, LEDSmain
@@ -603,7 +603,11 @@ class USBHIDParser : public USBDriver { | |||
public: | |||
USBHIDParser(USBHost &host) { init(); } | |||
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: | |||
enum { TOPUSAGE_LIST_LEN = 4 }; | |||
enum { USAGE_LIST_LEN = 24 }; | |||
@@ -783,9 +787,19 @@ public: | |||
bool available() { return joystickEvent; } | |||
void joystickDataClear(); | |||
uint32_t getButtons() { return buttons; } | |||
int getAxis(uint32_t index) { return (index < (sizeof(axis)/sizeof(axis[0]))) ? axis[index] : 0; } | |||
uint32_t axisMask() {return axis_mask_;} | |||
enum { AXIS_COUNT = 10 }; | |||
int getAxis(uint32_t index) { return (index < (sizeof(axis)/sizeof(axis[0]))) ? axis[index] : 0; } | |||
uint64_t axisMask() {return axis_mask_;} | |||
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: | |||
// From USBDriver | |||
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_end(); | |||
virtual void disconnect_collection(Device_t *dev); | |||
virtual bool hid_process_out_data(const Transfer_t *transfer); | |||
private: | |||
// Class specific | |||
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; | |||
volatile bool joystickEvent = false; | |||
uint32_t buttons = 0; | |||
int axis[AXIS_COUNT] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | |||
uint32_t axis_mask_ = 0; // which axis have valid data | |||
int axis[TOTAL_AXIS_COUNT] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | |||
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 | |||
uint8_t collections_claimed = 0; | |||
@@ -827,11 +859,13 @@ private: | |||
Pipe_t *rxpipe_; | |||
Pipe_t *txpipe_; | |||
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 | |||
typedef struct { | |||
uint16_t idVendor; | |||
uint16_t idProduct; | |||
joytype_t joyType; | |||
bool hidDevice; | |||
} product_vendor_mapping_t; | |||
static product_vendor_mapping_t pid_vid_mapping[]; | |||
@@ -9,7 +9,6 @@ USBHub hub1(myusb); | |||
USBHub hub2(myusb); | |||
KeyboardController keyboard1(myusb); | |||
KeyboardController keyboard2(myusb); | |||
//KeyboardHIDExtrasController hidextras(myusb); | |||
USBHIDParser hid1(myusb); | |||
USBHIDParser hid2(myusb); | |||
USBHIDParser hid3(myusb); | |||
@@ -17,6 +16,8 @@ USBHIDParser hid4(myusb); | |||
USBHIDParser hid5(myusb); | |||
MouseController mouse1(myusb); | |||
JoystickController joystick1(myusb); | |||
int user_axis[64]; | |||
uint32_t buttons_prev = 0; | |||
RawHIDController rawhid1(myusb); | |||
RawHIDController rawhid2(myusb, 0xffc90004); | |||
@@ -30,7 +31,11 @@ USBHIDInput *hiddrivers[] = {&mouse1, &joystick1, &rawhid1, &rawhid2}; | |||
#define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0])) | |||
const char * hid_driver_names[CNT_DEVICES] = {"Mouse1","Joystick1", "RawHid1", "RawHid2"}; | |||
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() | |||
{ | |||
@@ -54,6 +59,27 @@ void loop() | |||
{ | |||
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++) { | |||
if (*drivers[i] != driver_active[i]) { | |||
if (driver_active[i]) { | |||
@@ -109,14 +135,75 @@ void loop() | |||
mouse1.mouseDataClear(); | |||
} | |||
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(joystick1.getButtons(), HEX); | |||
for (uint8_t i = 0; axis_mask != 0; i++, axis_mask >>= 1) { | |||
if (axis_mask & 1) { | |||
Serial.printf(" %d:%d", i, joystick1.getAxis(i)); | |||
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) { | |||
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(); | |||
joystick1.joystickDataClear(); | |||
} |
@@ -205,13 +205,12 @@ void USBHIDParser::disconnect() | |||
// Called when the HID device sends a report | |||
void USBHIDParser::in_data(const Transfer_t *transfer) | |||
{ | |||
/*Serial.print("HID: "); | |||
/*Serial.printf("HID: "); | |||
uint8_t *pb = (uint8_t*)transfer->buffer; | |||
for (uint8_t i = 0; i < transfer->length; i++) { | |||
Serial.print(pb[i], HEX); | |||
Serial.print(" "); | |||
Serial.printf("%x ",pb[i]); | |||
} | |||
Serial.println(); */ | |||
Serial.printf("\n"); */ | |||
print("HID: "); | |||
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 (!tx1) { | |||
// 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; | |||
} | |||
if ((txstate & 3) == 3) return false; // both transmit buffers are full | |||
if (cb == -1) | |||
cb = out_size; | |||
uint8_t *p = tx1; | |||
if ((txstate & 1) == 0) { | |||
txstate |= 1; | |||
} else { | |||
if (!tx2) | |||
return false; // only one buffer | |||
txstate |= 2; | |||
p = tx2; | |||
} | |||
// copy the users data into our out going buffer | |||
memcpy(p, buffer, out_size); | |||
memcpy(p, buffer, cb); | |||
println("USBHIDParser Send packet"); | |||
print_hexbytes(buffer, out_size); | |||
queue_Data_Transfer(out_pipe, p, out_size, this); | |||
print_hexbytes(buffer, cb); | |||
queue_Data_Transfer(out_pipe, p, cb, this); | |||
println(" Queue_data transfer returned"); | |||
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 | |||
// 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_count = 0; | |||
uint16_t usage_page = 0; | |||
uint32_t last_usage = 0; | |||
int32_t logical_min = 0; | |||
int32_t logical_max = 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)) { | |||
// ordinary variable format | |||
uint32_t uindex = 0; | |||
uint32_t uindex_max = 0xffff; // assume no MAX | |||
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 | |||
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; | |||
} | |||
//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++) { | |||
uint32_t u; | |||
if (uminmax) { | |||
u = uindex; | |||
if (uindex < usage[1]) uindex++; | |||
if (uindex < uindex_max) uindex++; | |||
} else { | |||
u = usage[uindex++]; | |||
if (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; | |||
print(" usage = ", u, HEX); | |||
@@ -27,6 +27,18 @@ | |||
#define print USBHost::print_ | |||
#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() | |||
{ | |||
contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t)); | |||
@@ -36,6 +48,19 @@ void JoystickController::init() | |||
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... | |||
//***************************************************************************** | |||
@@ -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) | |||
@@ -90,6 +215,31 @@ hidclaim_t JoystickController::claim_collection(USBHIDParser *driver, Device_t * | |||
mydevice = dev; | |||
collections_claimed++; | |||
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; | |||
} | |||
@@ -97,7 +247,9 @@ void JoystickController::disconnect_collection(Device_t *dev) | |||
{ | |||
if (--collections_claimed == 0) { | |||
mydevice = NULL; | |||
driver_ = nullptr; | |||
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. | |||
if (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? | |||
} | |||
@@ -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() { | |||
joystickEvent = false; | |||
anychange = false; | |||
axis_changed_mask_ = 0; | |||
axis_mask_ = 0; | |||
} | |||
//***************************************************************************** | |||
// Support for Joysticks that are class specific and do not use HID | |||
// 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}; | |||
@@ -167,15 +348,12 @@ bool JoystickController::claim(Device_t *dev, int type, const uint8_t *descripto | |||
if (type != 0) return false; | |||
print_hexbytes(descriptors, len); | |||
uint8_t i = 0; | |||
for (; i < (sizeof(pid_vid_mapping)/sizeof(pid_vid_mapping[0])); i++) { | |||
if ((dev->idVendor == pid_vid_mapping[i].idVendor) && (dev->idProduct == pid_vid_mapping[i].idProduct)) { | |||
break; | |||
} | |||
} | |||
if (i == (sizeof(pid_vid_mapping)/sizeof(pid_vid_mapping[0]))) return false; // Not in our list | |||
JoystickController::joytype_t jtype = mapVIDPIDtoJoystickType(dev->idVendor, dev->idProduct, true); | |||
println("Jtype=", (uint8_t)jtype, DEC); | |||
if (jtype == UNKNOWN) | |||
return false; | |||
// 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 | |||
// 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); | |||
memset(axis, 0, sizeof(axis)); // clear out any data. | |||
joystickType = jtype; // remember we are an XBox One. | |||
return true; | |||
} | |||
@@ -280,6 +459,7 @@ void JoystickController::rx_data(const Transfer_t *transfer) | |||
// print("JoystickController::rx_data: "); | |||
// print_hexbytes((uint8_t*)transfer->buffer, transfer->length); | |||
axis_mask_ = 0x3f; | |||
axis_changed_mask_ = 0; // assume none for now | |||
xbox1data20_t *xb1d = (xbox1data20_t *)transfer->buffer; | |||
if ((xb1d->type == 0x20) && (transfer->length >= sizeof (xbox1data20_t))) { | |||
// 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() | |||
{ | |||
axis_mask_ = 0; | |||
axis_changed_mask_ = 0; | |||
// TODO: free resources | |||
} | |||
@@ -81,6 +81,15 @@ getWheelH KEYWORD2 | |||
joystickDataClear KEYWORD2 | |||
getAxis KEYWORD2 | |||
axisMask KEYWORD2 | |||
axisChangedMask KEYWORD2 | |||
axisChangeNotifyMask KEYWORD2 | |||
userAxisMask KEYWORD2 | |||
setRumbleOn KEYWORD2 | |||
setLEDs KEYWORD2 | |||
joystickType KEYWORD2 | |||
PS3 LITERAL1 | |||
PS4 LITERAL1 | |||
XBOXONE LITERAL1 | |||
# USBSerial | |||
USBHOST_SERIAL_7E1 LITERAL1 |