diff --git a/README.md b/README.md index a4ef7a85..680e376d 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,8 @@ For more information about the hardware see the [Hardware Manual](http://www.cir * Developer of the [BTD](#bluetooth-libraries), [BTHID](#bthid-library), [SPP](#spp-library), [PS4](#ps4-library), [PS3](#ps3-library), [Wii](#wii-library), [Xbox](#xbox-library), and [PSBuzz](#ps-buzz-library) libraries * __Andrew Kroll__ - * Major contributor to mass storage code +* __guruthree__ + * [Xbox ONE](#xbox-one-library) controller support # Donate @@ -47,6 +49,7 @@ Help yourself by helping us support you! Many thousands of hours have been spent * [Xbox Libraries](#xbox-libraries) * [Xbox library](#xbox-library) * [Xbox 360 Library](#xbox-360-library) + * [Xbox ONE Library](#xbox-one-library) * [Wii library](#wii-library) * [PS Buzz Library](#ps-buzz-library) * [Interface modifications](#interface-modifications) @@ -229,6 +232,14 @@ All the information regarding the Xbox 360 controller protocol are form these si * * +#### Xbox ONE Library + +An Xbox ONE controller is supported via USB in the [XBOXONE](XBOXONE.cpp) class. It is heavily based on the 360 library above. In addition to cross referencing the above, information on the protocol was found at: + +* +* +* + ### [Wii library](Wii.cpp) The [Wii](Wii.cpp) library support the Wiimote, but also the Nunchuch and Motion Plus extensions via Bluetooth. The Wii U Pro Controller is also supported via Bluetooth. @@ -322,4 +333,4 @@ LeftHatX: 0 LeftHatY: 0 RightHatX: 0 RightHatY: 0 LeftHatX: 0 LeftHatY: 0 RightHatX: 0 RightHatY: 0 ``` -* This means that your dongle does not support 2.0+EDR, so you will need another dongle. Please see the following [list](https://github.com/felis/USB_Host_Shield_2.0/wiki/Bluetooth-dongles) for tested working dongles. \ No newline at end of file +* This means that your dongle does not support 2.0+EDR, so you will need another dongle. Please see the following [list](https://github.com/felis/USB_Host_Shield_2.0/wiki/Bluetooth-dongles) for tested working dongles. diff --git a/XBOXONE.cpp b/XBOXONE.cpp new file mode 100644 index 00000000..2159c052 --- /dev/null +++ b/XBOXONE.cpp @@ -0,0 +1,374 @@ +/* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved. + Copyright (C) 2015 guruthree + + This software may be distributed and modified under the terms of the GNU + General Public License version 2 (GPL2) as published by the Free Software + Foundation and appearing in the file GPL2.TXT included in the packaging of + this file. Please note that GPL2 Section 2[b] requires that all works based + on this software must also be made publicly available under the terms of + the GPL2 ("Copyleft"). + + Contact information + ------------------- + + Kristian Lauszus, TKJ Electronics + Web : http://www.tkjelectronics.com + e-mail : kristianl@tkjelectronics.com + + guruthree + Web : https://github.com/guruthree/ + */ + +#include "XBOXONE.h" +// To enable serial debugging see "settings.h" +//#define EXTRADEBUG // Uncomment to get even more debugging data +//#define PRINTREPORT // Uncomment to print the report send by the Xbox ONE Controller + +XBOXONE::XBOXONE(USB *p) : +pUsb(p), // pointer to USB class instance - mandatory +bAddress(0), // device address - mandatory +bPollEnable(false) { // don't start polling before dongle is connected + for(uint8_t i = 0; i < XBOX_MAX_ENDPOINTS; i++) { + epInfo[i].epAddr = 0; + epInfo[i].maxPktSize = (i) ? 0 : 8; + epInfo[i].epAttribs = 0; + epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; + } + + if(pUsb) // register in USB subsystem + pUsb->RegisterDeviceClass(this); //set devConfig[] entry +} + +uint8_t XBOXONE::Init(uint8_t parent, uint8_t port, bool lowspeed) { + uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)]; + USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast(buf); + uint8_t rcode; + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + uint16_t PID; + uint16_t VID; + + // get memory address of USB device address pool + AddressPool &addrPool = pUsb->GetAddressPool(); +#ifdef EXTRADEBUG + Notify(PSTR("\r\nXBOXONE Init"), 0x80); +#endif + // check if address has already been assigned to an instance + if(bAddress) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nAddress in use"), 0x80); +#endif + return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; + } + + // Get pointer to pseudo device with address 0 assigned + p = addrPool.GetUsbDevicePtr(0); + + if(!p) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nAddress not found"), 0x80); +#endif + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + } + + if(!p->epinfo) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nepinfo is null"), 0x80); +#endif + return USB_ERROR_EPINFO_IS_NULL; + } + + // Save old pointer to EP_RECORD of address 0 + oldep_ptr = p->epinfo; + + // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence + p->epinfo = epInfo; + + p->lowspeed = lowspeed; + + // Get device descriptor + rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data + // Restore p->epinfo + p->epinfo = oldep_ptr; + + if(rcode) + goto FailGetDevDescr; + + VID = udd->idVendor; + PID = udd->idProduct; + + if(!VIDPIDOK(VID, PID)) // Check VID + goto FailUnknownDevice; + + // Allocate new address according to device class + bAddress = addrPool.AllocAddress(parent, false, port); + + if(!bAddress) + return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; + + // Extract Max Packet Size from device descriptor + epInfo[0].maxPktSize = udd->bMaxPacketSize0; + + // Assign new address to the device + rcode = pUsb->setAddr(0, 0, bAddress); + if(rcode) { + p->lowspeed = false; + addrPool.FreeAddress(bAddress); + bAddress = 0; +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nsetAddr: "), 0x80); + D_PrintHex (rcode, 0x80); +#endif + return rcode; + } +#ifdef EXTRADEBUG + Notify(PSTR("\r\nAddr: "), 0x80); + D_PrintHex (bAddress, 0x80); +#endif + //delay(300); // Spec says you should wait at least 200ms + + p->lowspeed = false; + + //get pointer to assigned address record + p = addrPool.GetUsbDevicePtr(bAddress); + if(!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + p->lowspeed = lowspeed; + + // Assign epInfo to epinfo pointer - only EP0 is known + rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); + 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 */ + + /* 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; + + rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo); + if(rcode) + goto FailSetDevTblEntry; + + delay(200); // Give time for address change + + rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1); + if(rcode) + goto FailSetConfDescr; + +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nXbox One Controller Connected\r\n"), 0x80); +#endif + + delay(200); // let things settle + + // initialize the controller for input + writeBuf[0] = 0x05; + writeBuf[1] = 0x20; + rcode = XboxCommand(writeBuf, 2); + if (rcode) + goto Fail; + + onInit(); + XboxOneConnected = true; + bPollEnable = true; + return 0; // Successful configuration + + /* Diagnostic messages */ +FailGetDevDescr: +#ifdef DEBUG_USB_HOST + NotifyFailGetDevDescr(); + goto Fail; +#endif + +FailSetDevTblEntry: +#ifdef DEBUG_USB_HOST + NotifyFailSetDevTblEntry(); + goto Fail; +#endif + +FailSetConfDescr: +#ifdef DEBUG_USB_HOST + NotifyFailSetConfDescr(); +#endif + goto Fail; + +FailUnknownDevice: +#ifdef DEBUG_USB_HOST + NotifyFailUnknownDevice(VID, PID); +#endif + rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + +Fail: +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nXbox One Init Failed, error code: "), 0x80); + NotifyFail(rcode); +#endif + Release(); + return rcode; +} + +/* Performs a cleanup after failed Init() attempt */ +uint8_t XBOXONE::Release() { + XboxOneConnected = false; + pUsb->GetAddressPool().FreeAddress(bAddress); + bAddress = 0; + bPollEnable = false; +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nXbox One Controller Disconnected\r\n"), 0x80); +#endif + return 0; +} + +uint8_t XBOXONE::Poll() { + 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 +#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); + } +#endif + return rcode; +} + +void XBOXONE::readReport() { + if(readBuf == NULL) + return; + if(readBuf[0] == 0x07) { + // The XBOX button has a separate message + if(readBuf[4] == 1) + ButtonState |= XBOX_BUTTONS[XBOX]; + else + ButtonState &= ~XBOX_BUTTONS[XBOX]; + } + if(readBuf[0] != 0x20) { // Check if it's the correct report, otherwise return - the controller also sends different status reports +#ifdef EXTRADEBUG + Notify(PSTR("\r\nXbox Poll: "), 0x80); + D_PrintHex (readBuf[0], 0x80); // 0x03 is a heart beat report! +#endif + return; + } + + uint16_t xbox = ButtonState & XBOX_BUTTONS[XBOX]; // Since the XBOX button is separate, save it and add it back in + // xbox button from before, dpad, abxy, start/back, sync, stick click, shoulder buttons + ButtonState = xbox | (((uint16_t)readBuf[5] & 0xF) << 8) | (readBuf[4] & 0xF0) | (((uint16_t)readBuf[4] & 0x0C) << 10) | ((readBuf[4] & 0x01) << 3) | (((uint16_t)readBuf[5] & 0xC0) << 8) | ((readBuf[5] & 0x30) >> 4); + + triggerValue[0] = (uint16_t)(((uint16_t)readBuf[7] << 8) | readBuf[6]); + triggerValue[1] = (uint16_t)(((uint16_t)readBuf[9] << 8) | readBuf[8]); + + hatValue[LeftHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]); + hatValue[LeftHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]); + hatValue[RightHatX] = (int16_t)(((uint16_t)readBuf[15] << 8) | readBuf[14]); + hatValue[RightHatY] = (int16_t)(((uint16_t)readBuf[17] << 8) | readBuf[16]); + + //Notify(PSTR("\r\nButtonState"), 0x80); + //PrintHex(ButtonState, 0x80); + + if(ButtonState != OldButtonState) { + ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable + OldButtonState = ButtonState; + } + + // Handle click detection for triggers + if(triggerValue[0] != 0 && triggerValueOld[0] == 0) + L2Clicked = true; + triggerValueOld[0] = triggerValue[0]; + if(triggerValue[1] != 0 && triggerValueOld[1] == 0) + 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 (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]; + else if(b == R2) + return triggerValue[1]; + return (bool)(ButtonState & ((uint16_t)pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]))); +} + +bool XBOXONE::getButtonClick(ButtonEnum b) { + if(b == L2) { + if(L2Clicked) { + L2Clicked = false; + return true; + } + return false; + } else if(b == R2) { + if(R2Clicked) { + R2Clicked = false; + return true; + } + return false; + } + uint16_t button = pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]); + bool click = (ButtonClickState & button); + ButtonClickState &= ~button; // clear "click" event + return click; +} + +int16_t XBOXONE::getAnalogHat(AnalogHatEnum a) { + return hatValue[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); +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nXboxCommand, Return: "), 0x80); + D_PrintHex (rcode, 0x80); +#endif + return rcode; +} + +void XBOXONE::onInit() { + // a short buzz to show the controller is active + writeBuf[0] = 0x09; + writeBuf[1] = 0x08; + writeBuf[2] = 0x00; + writeBuf[3] = 0x09; + writeBuf[4] = 0x00; + writeBuf[5] = 0x0f; + writeBuf[6] = 0x04; + writeBuf[7] = 0x04; + writeBuf[8] = 0x20; + writeBuf[9] = 0x20; + writeBuf[10] = 0x80; + XboxCommand(writeBuf, 11); + + if(pFuncOnInit) + pFuncOnInit(); // Call the user function +} diff --git a/XBOXONE.h b/XBOXONE.h new file mode 100644 index 00000000..02efbf21 --- /dev/null +++ b/XBOXONE.h @@ -0,0 +1,172 @@ +/* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved. + Copyright (C) 2015 guruthree + + This software may be distributed and modified under the terms of the GNU + General Public License version 2 (GPL2) as published by the Free Software + Foundation and appearing in the file GPL2.TXT included in the packaging of + this file. Please note that GPL2 Section 2[b] requires that all works based + on this software must also be made publicly available under the terms of + the GPL2 ("Copyleft"). + + Contact information + ------------------- + + Kristian Lauszus, TKJ Electronics + Web : http://www.tkjelectronics.com + e-mail : kristianl@tkjelectronics.com + + guruthree + Web : https://github.com/guruthree/ + */ + + +#ifndef _xboxone_h_ +#define _xboxone_h_ + +#include "Usb.h" +#include "xboxEnums.h" + +/* Data Xbox ONE taken from descriptors */ +#define EP_MAXPKTSIZE 32 // 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 + +// PID and VID of the different devices +#define XBOX_VID 0x045E // Microsoft Corporation +#define XBOX_ONE_PID 0x02D1 // Microsoft 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 { +public: + /** + * Constructor for the XBOXONE class. + * @param pUsb Pointer to USB class instance. + */ + XBOXONE(USB *pUsb); + + /** @name USBDeviceConfig implementation */ + /** + * Initialize the Xbox Controller. + * @param parent Hub number. + * @param port Port number on the hub. + * @param lowspeed Speed of the device. + * @return 0 on success. + */ + virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed); + /** + * Release the USB device. + * @return 0 on success. + */ + virtual uint8_t Release(); + /** + * Poll the USB Input endpoins and run the state machines. + * @return 0 on success. + */ + virtual uint8_t Poll(); + + /** + * Get the device address. + * @return The device address. + */ + virtual uint8_t GetAddress() { + return bAddress; + }; + + /** + * Used to check if the controller has been initialized. + * @return True if it's ready. + */ + virtual bool isReady() { + return bPollEnable; + }; + + /** + * Used by the USB core to check what this driver support. + * @param vid The device's VID. + * @param pid The device's PID. + * @return Returns true if the device's VID and PID matches this driver. + */ + virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) { + return (vid == XBOX_VID && pid == XBOX_ONE_PID); + }; + /**@}*/ + + /** @name Xbox Controller functions */ + /** + * getButtonPress(ButtonEnum b) will return true as long as the button is held down. + * + * While getButtonClick(ButtonEnum b) will only return it once. + * + * So you instance if you need to increase a variable once you would use getButtonClick(ButtonEnum b), + * but if you need to drive a robot forward you would use getButtonPress(ButtonEnum b). + * @param b ::ButtonEnum to read. + * @return getButtonClick(ButtonEnum b) will return a bool, while getButtonPress(ButtonEnum b) will return a word if reading ::L2 or ::R2. + */ + uint16_t getButtonPress(ButtonEnum b); + bool getButtonClick(ButtonEnum b); + + /** + * Return the analog value from the joysticks on the controller. + * @param a Either ::LeftHatX, ::LeftHatY, ::RightHatX or ::RightHatY. + * @return Returns a signed 16-bit integer. + */ + int16_t getAnalogHat(AnalogHatEnum a); + + /** + * Used to call your own function when the controller is successfully initialized. + * @param funcOnInit Function to call. + */ + void attachOnInit(void (*funcOnInit)(void)) { + pFuncOnInit = funcOnInit; + }; + /**@}*/ + + /** True if a Xbox ONE controller is connected. */ + bool XboxOneConnected; + +protected: + /** Pointer to USB class instance. */ + USB *pUsb; + /** Device address. */ + uint8_t bAddress; + /** Endpoint info structure. */ + EpInfo epInfo[XBOX_MAX_ENDPOINTS]; + +private: + /** + * Called when the controller is successfully initialized. + * Use attachOnInit(void (*funcOnInit)(void)) to call your own function. + */ + void onInit(); + void (*pFuncOnInit)(void); // Pointer to function called in onInit() + + bool bPollEnable; + + /* Variables to store the buttons */ + uint16_t ButtonState; + uint16_t OldButtonState; + uint16_t ButtonClickState; + int16_t hatValue[4]; + uint16_t triggerValue[2]; + uint16_t triggerValueOld[2]; + + 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 + + void readReport(); // read incoming data + void printReport(); // print incoming date - Uncomment for debugging + + /* Private commands */ + uint8_t XboxCommand(uint8_t* data, uint16_t nbytes); +}; +#endif diff --git a/examples/Xbox/XBOXONE/XBOXONE.ino b/examples/Xbox/XBOXONE/XBOXONE.ino new file mode 100644 index 00000000..9526f53d --- /dev/null +++ b/examples/Xbox/XBOXONE/XBOXONE.ino @@ -0,0 +1,106 @@ +/* + Example sketch for the Xbox ONE USB library - by guruthree, based on work by + Kristian Lauszus. + */ + +#include +// Satisfy IDE, which only needs to see the include statment in the ino. +#ifdef dobogusinclude +#include +#endif + +USB Usb; +XBOXONE Xbox(&Usb); + +void setup() { + Serial.begin(115200); + while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection + if (Usb.Init() == -1) { + Serial.print(F("\r\nOSC did not start")); + while (1); //halt + } + Serial.print(F("\r\nXBOX USB Library Started")); +} +void loop() { + Usb.Task(); + if (Xbox.XboxOneConnected) { + if (Xbox.getAnalogHat(LeftHatX) > 7500 || Xbox.getAnalogHat(LeftHatX) < -7500 || Xbox.getAnalogHat(LeftHatY) > 7500 || Xbox.getAnalogHat(LeftHatY) < -7500 || Xbox.getAnalogHat(RightHatX) > 7500 || Xbox.getAnalogHat(RightHatX) < -7500 || Xbox.getAnalogHat(RightHatY) > 7500 || Xbox.getAnalogHat(RightHatY) < -7500) { + if (Xbox.getAnalogHat(LeftHatX) > 7500 || Xbox.getAnalogHat(LeftHatX) < -7500) { + Serial.print(F("LeftHatX: ")); + Serial.print(Xbox.getAnalogHat(LeftHatX)); + Serial.print("\t"); + } + if (Xbox.getAnalogHat(LeftHatY) > 7500 || Xbox.getAnalogHat(LeftHatY) < -7500) { + Serial.print(F("LeftHatY: ")); + Serial.print(Xbox.getAnalogHat(LeftHatY)); + Serial.print("\t"); + } + if (Xbox.getAnalogHat(RightHatX) > 7500 || Xbox.getAnalogHat(RightHatX) < -7500) { + Serial.print(F("RightHatX: ")); + Serial.print(Xbox.getAnalogHat(RightHatX)); + Serial.print("\t"); + } + if (Xbox.getAnalogHat(RightHatY) > 7500 || Xbox.getAnalogHat(RightHatY) < -7500) { + Serial.print(F("RightHatY: ")); + Serial.print(Xbox.getAnalogHat(RightHatY)); + } + Serial.println(); + } + + if (Xbox.getButtonPress(L2) > 0 || Xbox.getButtonPress(R2) > 0) { + if (Xbox.getButtonPress(L2) > 0) { + Serial.print(F("L2: ")); + Serial.print(Xbox.getButtonPress(L2)); + Serial.print("\t"); + } + if (Xbox.getButtonPress(R2) > 0) { + Serial.print(F("R2: ")); + Serial.print(Xbox.getButtonPress(R2)); + Serial.print("\t"); + } + Serial.println(); + } + + if (Xbox.getButtonClick(UP)) + Serial.println(F("Up")); + if (Xbox.getButtonClick(DOWN)) + Serial.println(F("Down")); + if (Xbox.getButtonClick(LEFT)) + Serial.println(F("Left")); + if (Xbox.getButtonClick(RIGHT)) + Serial.println(F("Right")); + + if (Xbox.getButtonClick(START)) + Serial.println(F("Start")); + if (Xbox.getButtonClick(BACK)) + Serial.println(F("Back")); + if (Xbox.getButtonClick(XBOX)) + Serial.println(F("Xbox")); + if (Xbox.getButtonClick(SYNC)) + Serial.println(F("Sync")); + + if (Xbox.getButtonClick(L1)) + Serial.println(F("L1")); + if (Xbox.getButtonClick(R1)) + Serial.println(F("R1")); + if (Xbox.getButtonClick(L2)) + Serial.println(F("L2")); + if (Xbox.getButtonClick(R2)) + Serial.println(F("R2")); + if (Xbox.getButtonClick(L3)) + Serial.println(F("L3")); + if (Xbox.getButtonClick(R3)) + Serial.println(F("R3")); + + + if (Xbox.getButtonClick(A)) + Serial.println(F("A")); + if (Xbox.getButtonClick(B)) + Serial.println(F("B")); + if (Xbox.getButtonClick(X)) + Serial.println(F("X")); + if (Xbox.getButtonClick(Y)) + Serial.println(F("Y")); + } + delay(1); +} diff --git a/examples/cdc_XR21B1411/XR_terminal/__XR_terminal.ino b/examples/cdc_XR21B1411/XR_terminal/XR_terminal.ino similarity index 100% rename from examples/cdc_XR21B1411/XR_terminal/__XR_terminal.ino rename to examples/cdc_XR21B1411/XR_terminal/XR_terminal.ino diff --git a/examples/testusbhostFAT/Makefile b/examples/testusbhostFAT/Makefile index 232d338e..8a12ddc0 100644 --- a/examples/testusbhostFAT/Makefile +++ b/examples/testusbhostFAT/Makefile @@ -2,13 +2,16 @@ # These are set for a mega 1280 + quadram plus my serial patch. # If you lack quadram, or want to disable LFN, just change _FS_TINY=1 _USE_LFN=0 # -# If your board is a mega 2560 uncomment the following two lines -# BOARD = mega2560 -# PROGRAMMER = wiring -# ...and then comment out the following two lines +# If your board is a mega 2560 comment out the following two lines BOARD = mega + +BOARD_SUB = mega.menu.cpu.atmega1280 PROGRAMMER = arduino +# ...and then uncomment out the following two lines +#BOARD_SUB = mega.menu.cpu.atmega2560 +#PROGRAMMER = wiring + #BOARD = teensypp2 #BOARD = teensy3 #BOARD = teensy31 @@ -53,6 +56,9 @@ LIB_DIRS += ../testusbhostFAT/generic_storage LIB_DIRS += ../testusbhostFAT/RTClib LIB_DIRS += $(ARD_HOME)/libraries/Wire LIB_DIRS += $(ARD_HOME)/libraries/Wire/utility +LIB_DIRS += $(ARD_HOME)/hardware/arduino/$(BUILD_ARCH)/libraries/Wire +LIB_DIRS += $(ARD_HOME)/hardware/arduino/$(BUILD_ARCH)/libraries/Wire/utility +LIB_DIRS += $(ARD_HOME)/hardware/arduino/$(BUILD_ARCH)/libraries/SPI # And finally, the part that brings everything together for you. include Arduino_Makefile_master/_Makefile.master diff --git a/examples/testusbhostFAT/generic_storage b/examples/testusbhostFAT/generic_storage index 9233df8b..77762338 160000 --- a/examples/testusbhostFAT/generic_storage +++ b/examples/testusbhostFAT/generic_storage @@ -1 +1 @@ -Subproject commit 9233df8bc2cd0c16d363c8e298398b6eaefad257 +Subproject commit 77762338286535dabb9c94b87060e33e487ff0f3 diff --git a/examples/testusbhostFAT/testusbhostFAT.ino b/examples/testusbhostFAT/testusbhostFAT.ino old mode 100755 new mode 100644 index fa4a0bdf..e8b9cd35 --- a/examples/testusbhostFAT/testusbhostFAT.ino +++ b/examples/testusbhostFAT/testusbhostFAT.ino @@ -38,9 +38,9 @@ //#define _FS_TINY 1 //#define _USE_LFN 3 -//#define EXT_RAM_STACK 1 -//#define EXT_RAM_HEAP 1 //#define _MAX_SS 512 + + ///////////////////////////////////////////////////////////// // End of Arduino IDE specific information // ///////////////////////////////////////////////////////////// @@ -48,25 +48,36 @@ // You can set this to 0 if you are not using a USB hub. // It will save a little bit of flash and RAM. // Set to 1 if you want to use a hub. -#define WANT_HUB_TEST 0 +#define WANT_HUB_TEST 1 +// this is for XMEM2 +#define EXT_RAM_STACK 1 +#define EXT_RAM_HEAP 1 +#define LOAD_XMEM + +#if defined(CORE_TEENSY) && !defined(_AVR_) +#include +#include +#endif #if defined(__AVR__) #include -#else -#include +#include +#elif defined(ARDUINO_ARCH_SAM) +#include #endif + #if WANT_HUB_TEST #include #endif -#include +#include +#define LOAD_RTCLIB +#include #include #include #include #include #include -#include -#include #include #if defined(__AVR__) static FILE tty_stdio; @@ -113,14 +124,15 @@ static uint8_t My_Buff_x[mbxs]; /* File read buffer */ #define prescale256 ((1 << WGM12) | (1 << CS12)) #define prescale1024 ((1 << WGM12) | (1 << CS12) | (1 << CS10)) -extern "C" unsigned int freeHeap(); - +extern "C" { + extern unsigned int freeHeap(); +} static int tty_stderr_putc(char c, FILE *t) { USB_HOST_SERIAL.write(c); return 0; } -static int tty_stderr_flush(FILE *t) { +static int __attribute__((unused)) tty_stderr_flush(FILE *t) { USB_HOST_SERIAL.flush(); return 0; } @@ -135,14 +147,16 @@ static int tty_std_getc(FILE *t) { return Serial.read(); } -static int tty_std_flush(FILE *t) { +static int __attribute__((unused)) tty_std_flush(FILE *t) { Serial.flush(); return 0; } #else +// Supposedly the DUE has stdio already pointing to serial... +#if !defined(ARDUINO_ARCH_SAM) +// But newlib needs this... extern "C" { - int _write(int fd, const char *ptr, int len) { int j; for(j = 0; j < len; j++) { @@ -176,6 +190,7 @@ extern "C" { return (fd < 3) ? 1 : 0; } } +#endif // !defined(ARDUINO_ARCH_SAM) #endif void setup() { @@ -187,7 +202,7 @@ void setup() { } // Set this to higher values to enable more debug information // minimum 0x00, maximum 0xff - UsbDEBUGlvl = 0x51; + UsbDEBUGlvl = 0x81; #if !defined(CORE_TEENSY) && defined(__AVR__) // make LED pin as an output: @@ -455,14 +470,14 @@ void loop() { } // This is horrible, and needs to be moved elsewhere! for(int B = 0; B < MAX_USB_MS_DRIVERS; B++) { - if(!partsready && (UHS_USB_Storage[B]->GetAddress() != NULL)) { + if((!partsready) && (UHS_USB_BulkOnly[B]->GetAddress())) { // Build a list. - int ML = UHS_USB_Storage[B]->GetbMaxLUN(); + int ML = UHS_USB_BulkOnly[B]->GetbMaxLUN(); //printf("MAXLUN = %i\r\n", ML); ML++; for(int i = 0; i < ML; i++) { - if(UHS_USB_Storage[B]->LUNIsGood(i)) { + if(UHS_USB_BulkOnly[B]->LUNIsGood(i)) { partsready = true; ((pvt_t *)(sto[i].private_data))->lun = i; ((pvt_t *)(sto[i].private_data))->B = B; @@ -471,8 +486,8 @@ void loop() { sto[i].Status = *UHS_USB_BulkOnly_Status; sto[i].Initialize = *UHS_USB_BulkOnly_Initialize; sto[i].Commit = *UHS_USB_BulkOnly_Commit; - sto[i].TotalSectors = UHS_USB_Storage[B]->GetCapacity(i); - sto[i].SectorSize = UHS_USB_Storage[B]->GetSectorSize(i); + sto[i].TotalSectors = UHS_USB_BulkOnly[B]->GetCapacity(i); + sto[i].SectorSize = UHS_USB_BulkOnly[B]->GetSectorSize(i); printf_P(PSTR("LUN:\t\t%u\r\n"), i); printf_P(PSTR("Total Sectors:\t%08lx\t%lu\r\n"), sto[i].TotalSectors, sto[i].TotalSectors); printf_P(PSTR("Sector Size:\t%04x\t\t%u\r\n"), sto[i].SectorSize, sto[i].SectorSize); @@ -525,7 +540,7 @@ void loop() { if(Fats[0] != NULL) { struct Pvt * p; p = ((struct Pvt *)(Fats[0]->storage->private_data)); - if(!UHS_USB_Storage[p->B]->LUNIsGood(p->lun)) { + if(!UHS_USB_BulkOnly[p->B]->LUNIsGood(p->lun)) { // media change #if !defined(CORE_TEENSY) && defined(__AVR__) fadeAmount = 80; @@ -719,4 +734,3 @@ failed: } } } - diff --git a/keywords.txt b/keywords.txt index 178d52d8..bbbfb03e 100644 --- a/keywords.txt +++ b/keywords.txt @@ -192,6 +192,7 @@ RumbleLow LITERAL1 #################################################### XBOXUSB KEYWORD1 +XBOXONE KEYWORD1 XBOXOLD KEYWORD1 XBOXRECV KEYWORD1 @@ -207,6 +208,7 @@ buttonChanged KEYWORD2 XboxReceiverConnected KEYWORD2 Xbox360Connected KEYWORD2 +XboxOneConnected KEYWORD2 #################################################### # Constants and enums (LITERAL1) diff --git a/library.properties b/library.properties new file mode 100644 index 00000000..345b35f3 --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=USB Host Shield Library 2.0 +version=1.0.0 +author=Oleg Mazurov (Circuits@Home) , Kristian Lauszus (TKJ Electronics) , Andrew Kroll , Alexei Glushchenko (Circuits@Home)  +maintainer=Oleg Mazurov (Circuits@Home) , Kristian Lauszus (TKJ Electronics) , Andrew Kroll +sentence=Revision 2.0 of MAX3421E-based USB Host Shield Library. +paragraph=Supports HID devices, FTDI, ADK, ACM, PL2303, Bluetooth HID devices, SPP communication and mass storage devices. Furthermore it supports PS3, PS4, PS Buzz, Wii and Xbox controllers. +category=Other +url=https://github.com/felis/USB_Host_Shield_2.0 +architectures=* \ No newline at end of file