Merge branch 'master' of github.com:felis/USB_Host_Shield_2.0

This commit is contained in:
Andrew J. Kroll 2018-01-13 22:37:46 -05:00
commit 8318e5eeba
4 changed files with 155 additions and 74 deletions

View file

@ -225,11 +225,11 @@ uint8_t BTD::Init(uint8_t parent __attribute__((unused)), uint8_t port __attribu
// First interface in the configuration must have Bluetooth assigned Class/Subclass/Protocol
// And 3 endpoints - interrupt-IN, bulk-IN, bulk-OUT, not necessarily in this order
for(uint8_t i = 0; i < num_of_conf; i++) {
if(VID == IOGEAR_GBU521_VID && PID == IOGEAR_GBU521_PID) {
ConfigDescParser<USB_CLASS_VENDOR_SPECIFIC, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this); // Needed for the IOGEAR GBU521
if((VID == IOGEAR_GBU521_VID && PID == IOGEAR_GBU521_PID) || (VID == BELKIN_F8T065BF_VID && PID == BELKIN_F8T065BF_PID)) {
ConfigDescParser<USB_CLASS_VENDOR_SPECIFIC, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this); // Workaround issue with some dongles
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
} else {
ConfigDescParser<USB_CLASS_WIRELESS_CTRL, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this);
ConfigDescParser<USB_CLASS_WIRELESS_CTRL, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this); // Set class id according to the specification
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
}
if(rcode) // Check error code

7
BTD.h
View file

@ -27,8 +27,11 @@
#define PS3NAVIGATION_PID 0x042F // Navigation controller
#define PS3MOVE_PID 0x03D5 // Motion controller
#define IOGEAR_GBU521_VID 0x0A5C // The IOGEAR GBU521 dongle does not presents itself correctly, so we have to check for it manually
// These dongles do not present themselves correctly, so we have to check for them manually
#define IOGEAR_GBU521_VID 0x0A5C
#define IOGEAR_GBU521_PID 0x21E8
#define BELKIN_F8T065BF_VID 0x050D
#define BELKIN_F8T065BF_PID 0x065A
/* Bluetooth dongle data taken from descriptors */
#define BULK_MAXPKTSIZE 64 // Max size for ACL data
@ -264,7 +267,7 @@ public:
* @return Returns true if the device's VID and PID matches this driver.
*/
virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) {
if(vid == IOGEAR_GBU521_VID && pid == IOGEAR_GBU521_PID)
if((vid == IOGEAR_GBU521_VID && pid == IOGEAR_GBU521_PID) || (vid == BELKIN_F8T065BF_VID && pid == BELKIN_F8T065BF_PID))
return true;
if(my_bdaddr[0] != 0x00 || my_bdaddr[1] != 0x00 || my_bdaddr[2] != 0x00 || my_bdaddr[3] != 0x00 || my_bdaddr[4] != 0x00 || my_bdaddr[5] != 0x00) { // Check if Bluetooth address is set
if(vid == PS3_VID && (pid == PS3_PID || pid == PS3NAVIGATION_PID || pid == PS3MOVE_PID))

View file

@ -27,8 +27,11 @@
XBOXONE::XBOXONE(USB *p) :
pUsb(p), // pointer to USB class instance - mandatory
bAddress(0), // device address - mandatory
bNumEP(1), // If config descriptor needs to be parsed
qNextPollTime(0), // Reset NextPollTime
pollInterval(0),
bPollEnable(false) { // don't start polling before dongle is connected
for(uint8_t i = 0; i < XBOX_MAX_ENDPOINTS; i++) {
for(uint8_t i = 0; i < XBOX_ONE_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].bmSndToggle = 0;
@ -46,8 +49,8 @@ uint8_t XBOXONE::Init(uint8_t parent, uint8_t port, bool lowspeed) {
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
uint16_t PID;
uint16_t VID;
uint16_t PID, VID;
uint8_t num_of_conf; // Number of configurations
// get memory address of USB device address pool
AddressPool &addrPool = pUsb->GetAddressPool();
@ -142,31 +145,30 @@ uint8_t XBOXONE::Init(uint8_t parent, uint8_t port, bool lowspeed) {
if(rcode)
goto FailSetDevTblEntry;
/* The application will work in reduced host mode, so we can save program and data
memory space. After verifying the VID we will use known values for the
configuration values for device, interface, endpoints and HID for the XBOXONE Controllers */
num_of_conf = udd->bNumConfigurations; // Number of configurations
/* Initialize data structures for endpoints of device */
epInfo[ XBOX_OUTPUT_PIPE ].epAddr = 0x01; // XBOX one output endpoint
epInfo[ XBOX_OUTPUT_PIPE ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
epInfo[ XBOX_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
epInfo[ XBOX_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
epInfo[ XBOX_OUTPUT_PIPE ].bmSndToggle = 0;
epInfo[ XBOX_OUTPUT_PIPE ].bmRcvToggle = 0;
epInfo[ XBOX_INPUT_PIPE ].epAddr = 0x01; // XBOX one input endpoint
epInfo[ XBOX_INPUT_PIPE ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
epInfo[ XBOX_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
epInfo[ XBOX_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
epInfo[ XBOX_INPUT_PIPE ].bmSndToggle = 0;
epInfo[ XBOX_INPUT_PIPE ].bmRcvToggle = 0;
USBTRACE2("NC:", num_of_conf);
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
// Check if attached device is a Xbox One controller and fill endpoint data structure
for(uint8_t i = 0; i < num_of_conf; i++) {
ConfigDescParser<0, 0, 0, 0> confDescrParser(this); // Allow all devices, as we have already verified that it is a Xbox One controller from the VID and PID
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
if(rcode) // Check error code
goto FailGetConfDescr;
if(bNumEP >= XBOX_ONE_MAX_ENDPOINTS) // All endpoints extracted
break;
}
if(bNumEP < XBOX_ONE_MAX_ENDPOINTS)
goto FailUnknownDevice;
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
if(rcode)
goto FailSetDevTblEntry;
delay(200); // Give time for address change
rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1);
rcode = pUsb->setConf(bAddress, epInfo[ XBOX_ONE_CONTROL_PIPE ].epAddr, bConfNum);
if(rcode)
goto FailSetConfDescr;
@ -176,7 +178,8 @@ uint8_t XBOXONE::Init(uint8_t parent, uint8_t port, bool lowspeed) {
delay(200); // let things settle
// initialize the controller for input
// Initialize the controller for input
uint8_t writeBuf[5];
writeBuf[0] = 0x05;
writeBuf[1] = 0x20;
writeBuf[2] = 0x00;
@ -204,6 +207,12 @@ FailSetDevTblEntry:
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
goto Fail;
#endif
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
@ -225,11 +234,53 @@ Fail:
return rcode;
}
/* Extracts endpoint information from config descriptor */
void XBOXONE::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
bConfNum = conf;
uint8_t index;
if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT) { // Interrupt endpoint
index = (pep->bEndpointAddress & 0x80) == 0x80 ? XBOX_ONE_INPUT_PIPE : XBOX_ONE_OUTPUT_PIPE; // Set the endpoint index
} else
return;
// Fill the rest of endpoint data structure
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
#ifdef EXTRADEBUG
PrintEndpointDescriptor(pep);
#endif
if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints
pollInterval = pep->bInterval;
bNumEP++;
}
void XBOXONE::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
#ifdef EXTRADEBUG
Notify(PSTR("\r\nEndpoint descriptor:"), 0x80);
Notify(PSTR("\r\nLength:\t\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
Notify(PSTR("\r\nType:\t\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
Notify(PSTR("\r\nAddress:\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
Notify(PSTR("\r\nAttributes:\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
#endif
}
/* Performs a cleanup after failed Init() attempt */
uint8_t XBOXONE::Release() {
XboxOneConnected = false;
pUsb->GetAddressPool().FreeAddress(bAddress);
bAddress = 0;
bAddress = 0; // Clear device address
bNumEP = 1; // Must have to be reset to 1
qNextPollTime = 0; // Reset next poll time
pollInterval = 0;
bPollEnable = false;
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nXbox One Controller Disconnected\r\n"), 0x80);
@ -238,28 +289,36 @@ uint8_t XBOXONE::Release() {
}
uint8_t XBOXONE::Poll() {
uint8_t rcode = 0;
if(!bPollEnable)
return 0;
uint16_t BUFFER_SIZE = EP_MAXPKTSIZE;
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ XBOX_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf);
if (!rcode) {
readReport();
#ifdef PRINTREPORT
printReport(); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox ONE Controller
if((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L) { // Do not poll if shorter than polling interval
qNextPollTime = (uint32_t)millis() + pollInterval; // Set new poll time
uint16_t length = (uint16_t)epInfo[ XBOX_ONE_INPUT_PIPE ].maxPktSize; // Read the maximum packet size from the endpoint
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ XBOX_ONE_INPUT_PIPE ].epAddr, &length, readBuf, pollInterval);
if(!rcode) {
readReport();
#ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send by the Xbox ONE Controller
for(uint8_t i = 0; i < length; i++) {
D_PrintHex<uint8_t > (readBuf[i], 0x80);
Notify(PSTR(" "), 0x80);
}
Notify(PSTR("\r\n"), 0x80);
#endif
}
}
#ifdef DEBUG_USB_HOST
else if (rcode != 0x04) { // not a matter of no update to send
Notify(PSTR("\r\nXbox One Poll Failed, error code: "), 0x80);
NotifyFail(rcode);
else if(rcode != hrNAK) { // Not a matter of no update to send
Notify(PSTR("\r\nXbox One Poll Failed, error code: "), 0x80);
NotifyFail(rcode);
}
#endif
return rcode;
}
return rcode;
}
void XBOXONE::readReport() {
if(readBuf == NULL)
return;
if(readBuf[0] == 0x07) {
// The XBOX button has a separate message
if(readBuf[4] == 1)
@ -302,25 +361,13 @@ void XBOXONE::readReport() {
// Handle click detection for triggers
if(triggerValue[0] != 0 && triggerValueOld[0] == 0)
L2Clicked = true;
L2Clicked = true;
triggerValueOld[0] = triggerValue[0];
if(triggerValue[1] != 0 && triggerValueOld[1] == 0)
R2Clicked = true;
R2Clicked = true;
triggerValueOld[1] = triggerValue[1];
}
void XBOXONE::printReport() { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox ONE Controller
#ifdef PRINTREPORT
if(readBuf == NULL)
return;
for(uint8_t i = 0; i < XBOX_REPORT_BUFFER_SIZE; i++) {
D_PrintHex<uint8_t > (readBuf[i], 0x80);
Notify(PSTR(" "), 0x80);
}
Notify(PSTR("\r\n"), 0x80);
#endif
}
uint16_t XBOXONE::getButtonPress(ButtonEnum b) {
if(b == L2) // These are analog buttons
return triggerValue[0];
@ -345,7 +392,7 @@ bool XBOXONE::getButtonClick(ButtonEnum b) {
}
uint16_t button = pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]);
bool click = (ButtonClickState & button);
ButtonClickState &= ~button; // clear "click" event
ButtonClickState &= ~button; // Clear "click" event
return click;
}
@ -355,7 +402,7 @@ int16_t XBOXONE::getAnalogHat(AnalogHatEnum a) {
/* Xbox Controller commands */
uint8_t XBOXONE::XboxCommand(uint8_t* data, uint16_t nbytes) {
uint8_t rcode = pUsb->outTransfer(bAddress, epInfo[ XBOX_OUTPUT_PIPE ].epAddr, nbytes, data);
uint8_t rcode = pUsb->outTransfer(bAddress, epInfo[ XBOX_ONE_OUTPUT_PIPE ].epAddr, nbytes, data);
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nXboxCommand, Return: "), 0x80);
D_PrintHex<uint8_t > (rcode, 0x80);
@ -364,7 +411,8 @@ uint8_t XBOXONE::XboxCommand(uint8_t* data, uint16_t nbytes) {
}
void XBOXONE::onInit() {
// a short buzz to show the controller is active
// A short buzz to show the controller is active
uint8_t writeBuf[11];
writeBuf[0] = 0x09;
writeBuf[1] = 0x08;
writeBuf[2] = 0x00;

View file

@ -26,15 +26,17 @@
#include "Usb.h"
#include "xboxEnums.h"
/* Data Xbox ONE taken from descriptors */
#define EP_MAXPKTSIZE 32 // max size for data via USB
/* Xbox One data taken from descriptors */
#define XBOX_ONE_EP_MAXPKTSIZE 64 // Max size for data via USB
/* Names we give to the 3 XboxONE pipes */
#define XBOX_CONTROL_PIPE 0
#define XBOX_OUTPUT_PIPE 1
#define XBOX_INPUT_PIPE 2
#define XBOX_ONE_CONTROL_PIPE 0
#define XBOX_ONE_OUTPUT_PIPE 1
#define XBOX_ONE_INPUT_PIPE 2
// PID and VID of the different devices - see: https://github.com/torvalds/linux/blob/master/drivers/input/joystick/xpad.c
#define XBOX_ONE_MAX_ENDPOINTS 3
// PID and VID of the different versions of the controller - see: https://github.com/torvalds/linux/blob/master/drivers/input/joystick/xpad.c
// Official controllers
#define XBOX_VID1 0x045E // Microsoft Corporation
@ -59,12 +61,8 @@
#define XBOX_ONE_PID11 0x542A // Xbox ONE spectra
#define XBOX_ONE_PID12 0x543A // PowerA Xbox One wired controller
#define XBOX_REPORT_BUFFER_SIZE 14 // Size of the input report buffer
#define XBOX_MAX_ENDPOINTS 3
/** This class implements support for a Xbox ONE controller connected via USB. */
class XBOXONE : public USBDeviceConfig {
class XBOXONE : public USBDeviceConfig, public UsbConfigXtracter {
public:
/**
* Constructor for the XBOXONE class.
@ -108,6 +106,14 @@ public:
return bPollEnable;
};
/**
* Read the poll interval taken from the endpoint descriptors.
* @return The poll interval in ms.
*/
uint8_t readPollInterval() {
return pollInterval;
};
/**
* Used by the USB core to check what this driver support.
* @param vid The device's VID.
@ -161,7 +167,32 @@ protected:
/** Device address. */
uint8_t bAddress;
/** Endpoint info structure. */
EpInfo epInfo[XBOX_MAX_ENDPOINTS];
EpInfo epInfo[XBOX_ONE_MAX_ENDPOINTS];
/** Configuration number. */
uint8_t bConfNum;
/** Total number of endpoints in the configuration. */
uint8_t bNumEP;
/** Next poll time based on poll interval taken from the USB descriptor. */
uint32_t qNextPollTime;
/** @name UsbConfigXtracter implementation */
/**
* UsbConfigXtracter implementation, used to extract endpoint information.
* @param conf Configuration value.
* @param iface Interface number.
* @param alt Alternate setting.
* @param proto Interface Protocol.
* @param ep Endpoint Descriptor.
*/
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
/**@}*/
/**
* Used to print the USB Endpoint Descriptor.
* @param ep_ptr Pointer to USB Endpoint Descriptor.
*/
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
private:
/**
@ -171,6 +202,7 @@ private:
void onInit();
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
uint8_t pollInterval;
bool bPollEnable;
/* Variables to store the buttons */
@ -184,11 +216,9 @@ private:
bool L2Clicked; // These buttons are analog, so we use we use these bools to check if they where clicked or not
bool R2Clicked;
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
uint8_t writeBuf[12]; // General purpose buffer for output data
uint8_t readBuf[XBOX_ONE_EP_MAXPKTSIZE]; // General purpose buffer for input data
void readReport(); // read incoming data
void printReport(); // print incoming date - Uncomment for debugging
void readReport(); // Used to read the incoming data
/* Private commands */
uint8_t XboxCommand(uint8_t* data, uint16_t nbytes);