Browse Source

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
main
Kurt Eckhardt 7 years ago
parent
commit
c5edb1c25f
6 changed files with 404 additions and 176 deletions
  1. +77
    -30
      USBHost_t36.h
  2. +13
    -21
      examples/Mouse/Mouse.ino
  3. +221
    -1
      joystick.cpp
  4. +90
    -0
      keyboard.cpp
  5. +0
    -123
      keyboardHIDExtras.cpp
  6. +3
    -1
      keywords.txt

+ 77
- 30
USBHost_t36.h View File

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

+ 13
- 21
examples/Mouse/Mouse.ino View File

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

+ 221
- 1
joystick.cpp View File

@@ -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
- 0
keyboard.cpp View File

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

+ 0
- 123
keyboardHIDExtras.cpp View File

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




+ 3
- 1
keywords.txt View File

@@ -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…
Cancel
Save