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