mirror of
https://github.com/gdsports/USBHost_t36
synced 2024-12-21 23:08:55 -05:00
Add Xbox One controller support
While the other Joystick objects currently supported by the USB Host code are driven by HID data, the Xbox does not contain HID data and instead works at the top level. To handle this I made the Joystick object use multiple InHeritence like: class JoystickController : public USBDriver, public USBHIDInput This allowed me to have the object work either way. This did add some complexity in that some of the methods like is the object connected (The bool operator) had to be overwritten as both of the bases classes had it. In addition needed to update the other query functions to be able to grab the data from mydevice or device depending on which type of controller was connected. Since this looked like a valid way, I then merged the Keyboard Extras code that Keyboard and made it also do a similar multiple inheritance. In this case however I restricted the HID top level report handle code to only accept it if on the same object that claimed the keyboard. The mouse test app was updated as well
This commit is contained in:
parent
8aa67ff939
commit
c5edb1c25f
107
USBHost_t36.h
107
USBHost_t36.h
@ -635,7 +635,7 @@ private:
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
class KeyboardController : public USBDriver /* , public USBHIDInput */ {
|
||||
class KeyboardController : public USBDriver , public USBHIDInput {
|
||||
public:
|
||||
typedef union {
|
||||
struct {
|
||||
@ -651,8 +651,10 @@ typedef union {
|
||||
public:
|
||||
KeyboardController(USBHost &host) { init(); }
|
||||
KeyboardController(USBHost *host) { init(); }
|
||||
int available();
|
||||
int read();
|
||||
|
||||
// Some methods are in both public classes so we need to figure out which one to use
|
||||
operator bool() { return (device != nullptr); }
|
||||
// Main boot keyboard functions.
|
||||
uint16_t getKey() { return keyCode; }
|
||||
uint8_t getModifiers() { return modifiers; }
|
||||
uint8_t getOemKey() { return keyOEM; }
|
||||
@ -667,6 +669,13 @@ public:
|
||||
void numLock(bool f);
|
||||
void capsLock(bool f);
|
||||
void scrollLock(bool f);
|
||||
|
||||
// Added for extras information.
|
||||
void attachExtrasPress(void (*f)(uint32_t top, uint16_t code)) { extrasKeyPressedFunction = f; }
|
||||
void attachExtrasRelease(void (*f)(uint32_t top, uint16_t code)) { extrasKeyReleasedFunction = f; }
|
||||
enum {MAX_KEYS_DOWN=4};
|
||||
|
||||
|
||||
protected:
|
||||
virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len);
|
||||
virtual void control(const Transfer_t *transfer);
|
||||
@ -674,6 +683,14 @@ protected:
|
||||
static void callback(const Transfer_t *transfer);
|
||||
void new_data(const Transfer_t *transfer);
|
||||
void init();
|
||||
|
||||
protected: // HID functions for extra keyboard data.
|
||||
virtual hidclaim_t claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage);
|
||||
virtual void hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax);
|
||||
virtual void hid_input_data(uint32_t usage, int32_t value);
|
||||
virtual void hid_input_end();
|
||||
virtual void disconnect_collection(Device_t *dev);
|
||||
|
||||
private:
|
||||
void update();
|
||||
uint16_t convert_to_unicode(uint32_t mod, uint32_t key);
|
||||
@ -692,38 +709,19 @@ private:
|
||||
Pipe_t mypipes[2] __attribute__ ((aligned(32)));
|
||||
Transfer_t mytransfers[4] __attribute__ ((aligned(32)));
|
||||
strbuf_t mystring_bufs[1];
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
class KeyboardHIDExtrasController : public USBHIDInput {
|
||||
public:
|
||||
KeyboardHIDExtrasController(USBHost &host) { USBHIDParser::driver_ready_for_hid_collection(this); }
|
||||
void clear() { event_ = false;}
|
||||
bool available() { return event_; }
|
||||
void attachPress(void (*f)(uint32_t top, uint16_t code)) { keyPressedFunction = f; }
|
||||
void attachRelease(void (*f)(uint32_t top, uint16_t code)) { keyReleasedFunction = f; }
|
||||
enum {MAX_KEYS_DOWN=4};
|
||||
// uint32_t buttons() { return buttons_; }
|
||||
protected:
|
||||
virtual hidclaim_t claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage);
|
||||
virtual void hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax);
|
||||
virtual void hid_input_data(uint32_t usage, int32_t value);
|
||||
virtual void hid_input_end();
|
||||
virtual void disconnect_collection(Device_t *dev);
|
||||
private:
|
||||
void (*keyPressedFunction)(uint32_t top, uint16_t code);
|
||||
void (*keyReleasedFunction)(uint32_t top, uint16_t code);
|
||||
// Added to process secondary HID data.
|
||||
void (*extrasKeyPressedFunction)(uint32_t top, uint16_t code);
|
||||
void (*extrasKeyReleasedFunction)(uint32_t top, uint16_t code);
|
||||
uint32_t topusage_ = 0; // What top report am I processing?
|
||||
uint8_t collections_claimed_ = 0;
|
||||
volatile bool event_ = false;
|
||||
volatile bool hid_input_begin_ = false;
|
||||
volatile bool hid_input_data_ = false; // did we receive any valid data with report?
|
||||
uint8_t count_keys_down_ = 0;
|
||||
uint16_t keys_down[MAX_KEYS_DOWN];
|
||||
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
class MouseController : public USBHIDInput {
|
||||
public:
|
||||
@ -754,27 +752,76 @@ private:
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
class JoystickController : public USBHIDInput {
|
||||
class JoystickController : public USBDriver, public USBHIDInput {
|
||||
public:
|
||||
JoystickController(USBHost &host) { USBHIDParser::driver_ready_for_hid_collection(this); }
|
||||
JoystickController(USBHost &host) { init(); }
|
||||
|
||||
uint16_t idVendor();
|
||||
uint16_t idProduct();
|
||||
|
||||
const uint8_t *manufacturer();
|
||||
const uint8_t *product();
|
||||
const uint8_t *serialNumber();
|
||||
operator bool() { return ((device != nullptr) || (mydevice != nullptr)); } // override as in both USBDriver and in USBHIDInput
|
||||
|
||||
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 };
|
||||
protected:
|
||||
// From USBDriver
|
||||
virtual bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len);
|
||||
virtual void control(const Transfer_t *transfer);
|
||||
virtual void disconnect();
|
||||
|
||||
// From USBHIDInput
|
||||
virtual hidclaim_t claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage);
|
||||
virtual void hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax);
|
||||
virtual void hid_input_data(uint32_t usage, int32_t value);
|
||||
virtual void hid_input_end();
|
||||
virtual void disconnect_collection(Device_t *dev);
|
||||
private:
|
||||
uint8_t collections_claimed = 0;
|
||||
|
||||
// Class specific
|
||||
void init();
|
||||
|
||||
bool anychange = false;
|
||||
volatile bool joystickEvent = false;
|
||||
uint32_t buttons = 0;
|
||||
int16_t axis[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 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
|
||||
|
||||
// Used by HID code
|
||||
uint8_t collections_claimed = 0;
|
||||
|
||||
// Used by USBDriver code
|
||||
static void rx_callback(const Transfer_t *transfer);
|
||||
static void tx_callback(const Transfer_t *transfer);
|
||||
void rx_data(const Transfer_t *transfer);
|
||||
void tx_data(const Transfer_t *transfer);
|
||||
|
||||
Pipe_t mypipes[3] __attribute__ ((aligned(32)));
|
||||
Transfer_t mytransfers[7] __attribute__ ((aligned(32)));
|
||||
strbuf_t mystring_bufs[1];
|
||||
|
||||
uint16_t rx_size_ = 0;
|
||||
uint16_t tx_size_ = 0;
|
||||
Pipe_t *rxpipe_;
|
||||
Pipe_t *txpipe_;
|
||||
uint8_t rxbuf_[64]; // receive circular buffer
|
||||
|
||||
// Mapping table to say which devices we handle
|
||||
typedef struct {
|
||||
uint16_t idVendor;
|
||||
uint16_t idProduct;
|
||||
} product_vendor_mapping_t;
|
||||
static product_vendor_mapping_t pid_vid_mapping[];
|
||||
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
class MIDIDevice : public USBDriver {
|
||||
|
@ -7,11 +7,9 @@
|
||||
USBHost myusb;
|
||||
USBHub hub1(myusb);
|
||||
USBHub hub2(myusb);
|
||||
USBHub hub3(myusb);
|
||||
USBHub hub4(myusb);
|
||||
KeyboardController keyboard1(myusb);
|
||||
KeyboardController keyboard2(myusb);
|
||||
KeyboardHIDExtrasController hidextras(myusb);
|
||||
//KeyboardHIDExtrasController hidextras(myusb);
|
||||
USBHIDParser hid1(myusb);
|
||||
USBHIDParser hid2(myusb);
|
||||
USBHIDParser hid3(myusb);
|
||||
@ -22,9 +20,9 @@ JoystickController joystick1(myusb);
|
||||
RawHIDController rawhid1(myusb);
|
||||
RawHIDController rawhid2(myusb, 0xffc90004);
|
||||
|
||||
USBDriver *drivers[] = {&hub1, &hub2, &hub3, &hub4, &keyboard1, &keyboard2, &hid1, &hid2, &hid3, &hid4, &hid5};
|
||||
USBDriver *drivers[] = {&hub1, &hub2,&keyboard1, &keyboard2, &joystick1, &hid1, &hid2, &hid3, &hid4, &hid5};
|
||||
#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0]))
|
||||
const char * driver_names[CNT_DEVICES] = {"Hub1","Hub2", "Hub3", "Hub4" "KB1", "KB2", "HID1", "HID2", "HID3", "HID4", "HID5" };
|
||||
const char * driver_names[CNT_DEVICES] = {"Hub1","Hub2", "KB1", "KB2", "JOY1D", "HID1", "HID2", "HID3", "HID4", "HID5"};
|
||||
bool driver_active[CNT_DEVICES] = {false, false, false, false};
|
||||
|
||||
// Lets also look at HID Input devices
|
||||
@ -42,8 +40,10 @@ void setup()
|
||||
myusb.begin();
|
||||
keyboard1.attachPress(OnPress);
|
||||
keyboard2.attachPress(OnPress);
|
||||
hidextras.attachPress(OnHIDExtrasPress);
|
||||
hidextras.attachRelease(OnHIDExtrasRelease);
|
||||
keyboard1.attachExtrasPress(OnHIDExtrasPress);
|
||||
keyboard1.attachExtrasRelease(OnHIDExtrasRelease);
|
||||
keyboard2.attachExtrasPress(OnHIDExtrasPress);
|
||||
keyboard2.attachExtrasRelease(OnHIDExtrasRelease);
|
||||
|
||||
rawhid1.attachReceive(OnReceiveHidData);
|
||||
rawhid2.attachReceive(OnReceiveHidData);
|
||||
@ -109,22 +109,14 @@ void loop()
|
||||
mouse1.mouseDataClear();
|
||||
}
|
||||
if (joystick1.available()) {
|
||||
uint32_t axis_mask = joystick1.axisMask();
|
||||
Serial.print("Joystick: buttons = ");
|
||||
Serial.print(joystick1.getButtons(), HEX);
|
||||
Serial.print(", X = ");
|
||||
Serial.print(joystick1.getAxis(0));
|
||||
Serial.print(", Y = ");
|
||||
Serial.print(joystick1.getAxis(1));
|
||||
Serial.print(", Z = ");
|
||||
Serial.print(joystick1.getAxis(2));
|
||||
Serial.print(", Rz = ");
|
||||
Serial.print(joystick1.getAxis(5));
|
||||
Serial.print(", Rx = ");
|
||||
Serial.print(joystick1.getAxis(3));
|
||||
Serial.print(", Ry = ");
|
||||
Serial.print(joystick1.getAxis(4));
|
||||
Serial.print(", Hat = ");
|
||||
Serial.print(joystick1.getAxis(9));
|
||||
for (uint8_t i = 0; axis_mask != 0; i++, axis_mask >>= 1) {
|
||||
if (axis_mask & 1) {
|
||||
Serial.printf(" %d:%d", i, joystick1.getAxis(i));
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
joystick1.joystickDataClear();
|
||||
}
|
||||
|
222
joystick.cpp
222
joystick.cpp
@ -24,7 +24,62 @@
|
||||
#include <Arduino.h>
|
||||
#include "USBHost_t36.h" // Read this header first for key info
|
||||
|
||||
#define print USBHost::print_
|
||||
#define println USBHost::println_
|
||||
|
||||
void JoystickController::init()
|
||||
{
|
||||
contribute_Pipes(mypipes, sizeof(mypipes)/sizeof(Pipe_t));
|
||||
contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t));
|
||||
contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t));
|
||||
driver_ready_for_device(this);
|
||||
USBHIDParser::driver_ready_for_hid_collection(this);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// Some simple query functions depend on which interface we are using...
|
||||
//*****************************************************************************
|
||||
|
||||
uint16_t JoystickController::idVendor()
|
||||
{
|
||||
if (device != nullptr) return device->idVendor;
|
||||
if (mydevice != nullptr) return mydevice->idVendor;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t JoystickController::idProduct()
|
||||
{
|
||||
if (device != nullptr) return device->idProduct;
|
||||
if (mydevice != nullptr) return mydevice->idProduct;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint8_t *JoystickController::manufacturer()
|
||||
{
|
||||
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_MAN]];
|
||||
if ((mydevice != nullptr) && (mydevice->strbuf != nullptr)) return &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_MAN]];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const uint8_t *JoystickController::product()
|
||||
{
|
||||
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_PROD]];
|
||||
if ((mydevice != nullptr) && (mydevice->strbuf != nullptr)) return &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_PROD]];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const uint8_t *JoystickController::serialNumber()
|
||||
{
|
||||
if ((device != nullptr) && (device->strbuf != nullptr)) return &device->strbuf->buffer[device->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]];
|
||||
if ((mydevice != nullptr) && (mydevice->strbuf != nullptr)) return &mydevice->strbuf->buffer[mydevice->strbuf->iStrings[strbuf_t::STR_ID_SERIAL]];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
// Support for Joysticks that USe HID data.
|
||||
//*****************************************************************************
|
||||
|
||||
hidclaim_t JoystickController::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage)
|
||||
{
|
||||
@ -42,6 +97,7 @@ void JoystickController::disconnect_collection(Device_t *dev)
|
||||
{
|
||||
if (--collections_claimed == 0) {
|
||||
mydevice = NULL;
|
||||
axis_mask_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,8 +126,9 @@ void JoystickController::hid_input_data(uint32_t usage, int32_t value)
|
||||
}
|
||||
} else if (usage_page == 1 && usage >= 0x30 && usage <= 0x39) {
|
||||
// TODO: need scaling of value to consistent API, 16 bit signed?
|
||||
// TODO: many joysticks repeat slider usage. Detect & map to axes?
|
||||
// TODO: many joysticks repeat slider usage. Detect & map to axis?
|
||||
uint32_t i = usage - 0x30;
|
||||
axis_mask_ |= (1 << i); // Keep record of which axis we have data on.
|
||||
if (axis[i] != value) {
|
||||
axis[i] = value;
|
||||
anychange = true;
|
||||
@ -92,4 +149,167 @@ void JoystickController::joystickDataClear() {
|
||||
anychange = false;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// 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} };
|
||||
|
||||
static uint8_t start_input[] = {0x05, 0x20, 0x00, 0x01, 0x00};
|
||||
|
||||
bool JoystickController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len)
|
||||
{
|
||||
println("JoystickController claim this=", (uint32_t)this, HEX);
|
||||
|
||||
// only claim at device level
|
||||
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
|
||||
|
||||
// 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.
|
||||
|
||||
if (len < 9+7+7) return false;
|
||||
|
||||
uint32_t count_end_points = descriptors[4];
|
||||
if (count_end_points < 2) return false;
|
||||
if (descriptors[5] != 0xff) return false; // bInterfaceClass, 3 = HID
|
||||
uint32_t rxep = 0;
|
||||
uint32_t txep = 0;
|
||||
rx_size_ = 0;
|
||||
tx_size_ = 0;
|
||||
uint32_t descriptor_index = 9;
|
||||
while (count_end_points-- && ((rxep == 0) || txep == 0)) {
|
||||
if (descriptors[descriptor_index] != 7) return false; // length 7
|
||||
if (descriptors[descriptor_index+1] != 5) return false; // ep desc
|
||||
if ((descriptors[descriptor_index+3] == 3) // Type 3...
|
||||
&& (descriptors[descriptor_index+4] <= 64)
|
||||
&& (descriptors[descriptor_index+5] == 0)) {
|
||||
// have a bulk EP size
|
||||
if (descriptors[descriptor_index+2] & 0x80 ) {
|
||||
rxep = descriptors[descriptor_index+2];
|
||||
rx_size_ = descriptors[descriptor_index+4];
|
||||
} else {
|
||||
txep = descriptors[descriptor_index+2];
|
||||
tx_size_ = descriptors[descriptor_index+4];
|
||||
}
|
||||
}
|
||||
descriptor_index += 7; // setup to look at next one...
|
||||
}
|
||||
if ((rxep == 0) || (txep == 0)) return false; // did not find two end points.
|
||||
print("JoystickController, rxep=", rxep & 15);
|
||||
print("(", rx_size_);
|
||||
print("), txep=", txep);
|
||||
print("(", tx_size_);
|
||||
println(")");
|
||||
rxpipe_ = new_Pipe(dev, 2, rxep & 15, 1, rx_size_);
|
||||
if (!rxpipe_) return false;
|
||||
txpipe_ = new_Pipe(dev, 2, txep, 0, tx_size_);
|
||||
if (!txpipe_) {
|
||||
//free_Pipe(rxpipe_);
|
||||
return false;
|
||||
}
|
||||
rxpipe_->callback_function = rx_callback;
|
||||
queue_Data_Transfer(rxpipe_, rxbuf_, rx_size_, this);
|
||||
|
||||
txpipe_->callback_function = tx_callback;
|
||||
|
||||
queue_Data_Transfer(txpipe_, start_input, sizeof(start_input), this);
|
||||
memset(axis, 0, sizeof(axis)); // clear out any data.
|
||||
return true;
|
||||
}
|
||||
|
||||
void JoystickController::control(const Transfer_t *transfer)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/************************************************************/
|
||||
// Interrupt-based Data Movement
|
||||
/************************************************************/
|
||||
|
||||
void JoystickController::rx_callback(const Transfer_t *transfer)
|
||||
{
|
||||
if (!transfer->driver) return;
|
||||
((JoystickController *)(transfer->driver))->rx_data(transfer);
|
||||
}
|
||||
|
||||
void JoystickController::tx_callback(const Transfer_t *transfer)
|
||||
{
|
||||
if (!transfer->driver) return;
|
||||
((JoystickController *)(transfer->driver))->tx_data(transfer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************************************************************/
|
||||
// Interrupt-based Data Movement
|
||||
// XBox one input data when type == 0x20
|
||||
// Information came from several places on the web including:
|
||||
// https://github.com/quantus/xbox-one-controller-protocol
|
||||
/************************************************************/
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
uint8_t const_0;
|
||||
uint16_t id;
|
||||
// From online references button order:
|
||||
// sync, dummy, start, back, a, b, x, y
|
||||
// dpad up, down left, right
|
||||
// lb, rb, left stick, right stick
|
||||
// Axis:
|
||||
// lt, rt, lx, xy, rx, ry
|
||||
//
|
||||
uint16_t buttons;
|
||||
int16_t axis[6];
|
||||
} xbox1data20_t;
|
||||
|
||||
static const uint8_t xbox_axis_order_mapping[] = {4, 5, 0, 1, 2, 3};
|
||||
|
||||
void JoystickController::rx_data(const Transfer_t *transfer)
|
||||
{
|
||||
// print("JoystickController::rx_data: ");
|
||||
// print_hexbytes((uint8_t*)transfer->buffer, transfer->length);
|
||||
axis_mask_ = 0x3f;
|
||||
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...
|
||||
if (xb1d->buttons != buttons) {
|
||||
buttons = xb1d->buttons;
|
||||
anychange = true;
|
||||
}
|
||||
for (uint8_t i = 0; i < sizeof (xbox_axis_order_mapping); i++) {
|
||||
// The first two values were unsigned.
|
||||
int axis_value = (i < 2)? (int)(uint16_t)xb1d->axis[i] : xb1d->axis[i];
|
||||
if (axis_value != axis[xbox_axis_order_mapping[i]]) {
|
||||
axis[xbox_axis_order_mapping[i]] = axis_value;
|
||||
anychange = true;
|
||||
}
|
||||
}
|
||||
joystickEvent = true;
|
||||
}
|
||||
|
||||
|
||||
queue_Data_Transfer(rxpipe_, rxbuf_, rx_size_, this);
|
||||
}
|
||||
|
||||
void JoystickController::tx_data(const Transfer_t *transfer)
|
||||
{
|
||||
}
|
||||
|
||||
void JoystickController::disconnect()
|
||||
{
|
||||
axis_mask_ = 0;
|
||||
// TODO: free resources
|
||||
}
|
||||
|
||||
|
||||
|
90
keyboard.cpp
90
keyboard.cpp
@ -98,6 +98,7 @@ void KeyboardController::init()
|
||||
contribute_Transfers(mytransfers, sizeof(mytransfers)/sizeof(Transfer_t));
|
||||
contribute_String_Buffers(mystring_bufs, sizeof(mystring_bufs)/sizeof(strbuf_t));
|
||||
driver_ready_for_device(this);
|
||||
USBHIDParser::driver_ready_for_hid_collection(this);
|
||||
}
|
||||
|
||||
bool KeyboardController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len)
|
||||
@ -326,13 +327,102 @@ void KeyboardController::updateLEDS() {
|
||||
queue_Control_Transfer(device, &setup, &leds_.byte, this);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Keyboard Extras - Combined from other object
|
||||
//=============================================================================
|
||||
|
||||
#define TOPUSAGE_SYS_CONTROL 0x10080
|
||||
#define TOPUSAGE_CONSUMER_CONTROL 0x0c0001
|
||||
|
||||
hidclaim_t KeyboardController::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage)
|
||||
{
|
||||
// Lets try to claim a few specific Keyboard related collection/reports
|
||||
//Serial.printf("KBH Claim %x\n", topusage);
|
||||
if ((topusage != TOPUSAGE_SYS_CONTROL)
|
||||
&& (topusage != TOPUSAGE_CONSUMER_CONTROL)
|
||||
) return CLAIM_NO;
|
||||
// only claim from one physical device
|
||||
//Serial.println("KeyboardController claim collection");
|
||||
// Lets only claim if this is the same device as claimed Keyboard...
|
||||
if (dev != device) return CLAIM_NO;
|
||||
if (mydevice != NULL && dev != mydevice) return CLAIM_NO;
|
||||
mydevice = dev;
|
||||
collections_claimed_++;
|
||||
return CLAIM_REPORT;
|
||||
}
|
||||
|
||||
void KeyboardController::disconnect_collection(Device_t *dev)
|
||||
{
|
||||
if (--collections_claimed_ == 0) {
|
||||
mydevice = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardController::hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax)
|
||||
{
|
||||
//Serial.printf("KPC:hid_input_begin TUSE: %x TYPE: %x Range:%x %x\n", topusage, type, lgmin, lgmax);
|
||||
topusage_ = topusage; // remember which report we are processing.
|
||||
hid_input_begin_ = true;
|
||||
hid_input_data_ = false;
|
||||
}
|
||||
|
||||
void KeyboardController::hid_input_data(uint32_t usage, int32_t value)
|
||||
{
|
||||
// Hack ignore 0xff00 high words as these are user values...
|
||||
if ((usage & 0xffff0000) == 0xff000000) return;
|
||||
//Serial.printf("KeyboardController: topusage= %x usage=%X, value=%d\n", topusage_, usage, value);
|
||||
|
||||
// See if the value is in our keys_down list
|
||||
usage &= 0xffff; // only keep the actual key
|
||||
if (usage == 0) return; // lets not process 0, if only 0 happens, we will handle it on the end to remove existing pressed items.
|
||||
|
||||
// Remember if we have received any logical key up events. Some keyboard appear to send them
|
||||
// others do no...
|
||||
hid_input_data_ = true;
|
||||
|
||||
uint8_t key_index;
|
||||
for (key_index = 0; key_index < count_keys_down_; key_index++) {
|
||||
if (keys_down[key_index] == usage) {
|
||||
if (value) return; // still down
|
||||
|
||||
if (extrasKeyReleasedFunction) {
|
||||
extrasKeyReleasedFunction(topusage_, usage);
|
||||
}
|
||||
|
||||
// Remove from list
|
||||
count_keys_down_--;
|
||||
for (;key_index < count_keys_down_; key_index++) {
|
||||
keys_down[key_index] = keys_down[key_index+1];
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Was not in list
|
||||
if (!value) return; // still 0
|
||||
if (extrasKeyPressedFunction) {
|
||||
extrasKeyPressedFunction(topusage_, usage);
|
||||
}
|
||||
if (count_keys_down_ < MAX_KEYS_DOWN) {
|
||||
keys_down[count_keys_down_++] = usage;
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardController::hid_input_end()
|
||||
{
|
||||
//Serial.println("KPC:hid_input_end");
|
||||
if (hid_input_begin_) {
|
||||
|
||||
// See if we received any data from parser if not, assume all keys released...
|
||||
if (!hid_input_data_ ) {
|
||||
if (extrasKeyReleasedFunction) {
|
||||
while (count_keys_down_) {
|
||||
count_keys_down_--;
|
||||
extrasKeyReleasedFunction(topusage_, keys_down[count_keys_down_]);
|
||||
}
|
||||
}
|
||||
count_keys_down_ = 0;
|
||||
}
|
||||
|
||||
hid_input_begin_ = false;
|
||||
}
|
||||
}
|
||||
|
@ -1,123 +0,0 @@
|
||||
/* USB keyboard power Host for Teensy 3.6
|
||||
* Copyright 2017 Paul Stoffregen (paul@pjrc.com)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "USBHost_t36.h" // Read this header first for key info
|
||||
|
||||
#define TOPUSAGE_SYS_CONTROL 0x10080
|
||||
#define TOPUSAGE_CONSUMER_CONTROL 0x0c0001
|
||||
|
||||
hidclaim_t KeyboardHIDExtrasController::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage)
|
||||
{
|
||||
// Lets try to claim a few specific Keyboard related collection/reports
|
||||
//Serial.printf("KBH Claim %x\n", topusage);
|
||||
if ((topusage != TOPUSAGE_SYS_CONTROL)
|
||||
&& (topusage != TOPUSAGE_CONSUMER_CONTROL)
|
||||
) return CLAIM_NO;
|
||||
// only claim from one physical device
|
||||
//Serial.println("KeyboardHIDExtrasController claim collection");
|
||||
if (mydevice != NULL && dev != mydevice) return CLAIM_NO;
|
||||
mydevice = dev;
|
||||
collections_claimed_++;
|
||||
return CLAIM_REPORT;
|
||||
}
|
||||
|
||||
void KeyboardHIDExtrasController::disconnect_collection(Device_t *dev)
|
||||
{
|
||||
if (--collections_claimed_ == 0) {
|
||||
mydevice = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardHIDExtrasController::hid_input_begin(uint32_t topusage, uint32_t type, int lgmin, int lgmax)
|
||||
{
|
||||
//Serial.printf("KPC:hid_input_begin TUSE: %x TYPE: %x Range:%x %x\n", topusage, type, lgmin, lgmax);
|
||||
topusage_ = topusage; // remember which report we are processing.
|
||||
hid_input_begin_ = true;
|
||||
hid_input_data_ = false;
|
||||
}
|
||||
|
||||
void KeyboardHIDExtrasController::hid_input_data(uint32_t usage, int32_t value)
|
||||
{
|
||||
// Hack ignore 0xff00 high words as these are user values...
|
||||
if ((usage & 0xffff0000) == 0xff000000) return;
|
||||
//Serial.printf("KeyboardHIDExtrasController: topusage= %x usage=%X, value=%d\n", topusage_, usage, value);
|
||||
|
||||
// See if the value is in our keys_down list
|
||||
usage &= 0xffff; // only keep the actual key
|
||||
if (usage == 0) return; // lets not process 0, if only 0 happens, we will handle it on the end to remove existing pressed items.
|
||||
|
||||
// Remember if we have received any logical key up events. Some keyboard appear to send them
|
||||
// others do no...
|
||||
hid_input_data_ = true;
|
||||
|
||||
uint8_t key_index;
|
||||
for (key_index = 0; key_index < count_keys_down_; key_index++) {
|
||||
if (keys_down[key_index] == usage) {
|
||||
if (value) return; // still down
|
||||
|
||||
if (keyReleasedFunction) {
|
||||
keyReleasedFunction(topusage_, usage);
|
||||
}
|
||||
|
||||
// Remove from list
|
||||
count_keys_down_--;
|
||||
for (;key_index < count_keys_down_; key_index++) {
|
||||
keys_down[key_index] = keys_down[key_index+1];
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Was not in list
|
||||
if (!value) return; // still 0
|
||||
if (keyPressedFunction) {
|
||||
keyPressedFunction(topusage_, usage);
|
||||
}
|
||||
if (count_keys_down_ < MAX_KEYS_DOWN) {
|
||||
keys_down[count_keys_down_++] = usage;
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardHIDExtrasController::hid_input_end()
|
||||
{
|
||||
//Serial.println("KPC:hid_input_end");
|
||||
if (hid_input_begin_) {
|
||||
|
||||
// See if we received any data from parser if not, assume all keys released...
|
||||
if (!hid_input_data_ ) {
|
||||
if (keyPressedFunction) {
|
||||
while (count_keys_down_) {
|
||||
count_keys_down_--;
|
||||
keyReleasedFunction(topusage_, keys_down[count_keys_down_]);
|
||||
}
|
||||
}
|
||||
count_keys_down_ = 0;
|
||||
}
|
||||
|
||||
event_ = true;
|
||||
hid_input_begin_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -8,7 +8,6 @@ MIDIDevice KEYWORD1
|
||||
USBSerial KEYWORD1
|
||||
AntPlus KEYWORD1
|
||||
JoystickController KEYWORD1
|
||||
KeyboardHIDExtrasController KEYWORD1
|
||||
RawHIDController KEYWORD1
|
||||
|
||||
# Common Functions
|
||||
@ -25,6 +24,8 @@ getModifiers KEYWORD2
|
||||
getOemKey KEYWORD2
|
||||
attachPress KEYWORD2
|
||||
attachRelease KEYWORD2
|
||||
attachExtrasPress KEYWORD2
|
||||
attachExtrasRelease KEYWORD2
|
||||
LEDS KEYWORD2
|
||||
updateLEDS KEYWORD2
|
||||
numLock KEYWORD2
|
||||
@ -79,6 +80,7 @@ getWheelH KEYWORD2
|
||||
# JoystickController
|
||||
joystickDataClear KEYWORD2
|
||||
getAxis KEYWORD2
|
||||
axisMask KEYWORD2
|
||||
|
||||
# USBSerial
|
||||
USBHOST_SERIAL_7E1 LITERAL1
|
||||
|
Loading…
Reference in New Issue
Block a user