From e9bd896ca2a8bc40bd3e6e628446d53a65e96837 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Fri, 10 Jan 2014 17:44:51 +0100 Subject: [PATCH 01/42] Added support for the PS4 controller via Bluetooth --- BTD.cpp | 43 ++++--- BTD.h | 3 + BTHID.cpp | 4 +- PS4BT.cpp | 117 +++++++++++++++++++ PS4BT.h | 176 +++++++++++++++++++++++++++++ controllerEnums.h | 6 + examples/Bluetooth/PS4BT/PS4BT.ino | 98 ++++++++++++++++ keywords.txt | 7 +- 8 files changed, 438 insertions(+), 16 deletions(-) create mode 100644 PS4BT.cpp create mode 100644 PS4BT.h create mode 100644 examples/Bluetooth/PS4BT/PS4BT.ino diff --git a/BTD.cpp b/BTD.cpp index 7fc278da..b646b160 100755 --- a/BTD.cpp +++ b/BTD.cpp @@ -302,6 +302,7 @@ void BTD::Initialize() { incomingWii = false; connectToHIDDevice = false; incomingHIDDevice = false; + incomingPS4 = false; bAddress = 0; // Clear device address bNumEP = 1; // Must have to be reset to 1 qNextPollTime = 0; // Reset next poll time @@ -434,7 +435,6 @@ void BTD::HCI_event_task() { #endif for(uint8_t i = 0; i < hcibuf[2]; i++) { uint8_t offset = 8 * hcibuf[2] + 3 * i; - uint8_t classOfDevice[3]; for(uint8_t j = 0; j < 3; j++) classOfDevice[j] = hcibuf[j + 4 + offset]; @@ -450,12 +450,14 @@ void BTD::HCI_event_task() { hci_set_flag(HCI_FLAG_DEVICE_FOUND); break; - } else if(pairWithHIDDevice && (classOfDevice[1] & 0x05) && (classOfDevice[0] & 0xC0)) { // Check if it is a mouse or keyboard - see: http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html + } else if(pairWithHIDDevice && (classOfDevice[1] & 0x05) && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad - see: http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html #ifdef DEBUG_USB_HOST if(classOfDevice[0] & 0x80) Notify(PSTR("\r\nMouse found"), 0x80); if(classOfDevice[0] & 0x40) Notify(PSTR("\r\nKeyboard found"), 0x80); + if(classOfDevice[0] & 0x08) + Notify(PSTR("\r\nGamepad found"), 0x80); #endif for(uint8_t j = 0; j < 6; j++) @@ -516,23 +518,28 @@ void BTD::HCI_event_task() { for(uint8_t i = 0; i < 6; i++) disc_bdaddr[i] = hcibuf[i + 2]; - if((hcibuf[9] & 0x05) && (hcibuf[8] & 0xC0)) { // Check if it is a mouse or keyboard + for(uint8_t i = 0; i < 3; i++) + classOfDevice[i] = hcibuf[i + 8]; + + if((classOfDevice[1] & 0x05) && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad #ifdef DEBUG_USB_HOST - if(hcibuf[8] & 0x80) + if(classOfDevice[0] & 0x80) Notify(PSTR("\r\nMouse is connecting"), 0x80); - if(hcibuf[8] & 0x40) + if(classOfDevice[0] & 0x40) Notify(PSTR("\r\nKeyboard is connecting"), 0x80); + if(classOfDevice[0] & 0x08) + Notify(PSTR("\r\nGamepad is connecting"), 0x80); #endif incomingHIDDevice = true; } #ifdef EXTRADEBUG Notify(PSTR("\r\nClass of device: "), 0x80); - D_PrintHex (hcibuf[10], 0x80); + D_PrintHex (classOfDevice[2], 0x80); Notify(PSTR(" "), 0x80); - D_PrintHex (hcibuf[9], 0x80); + D_PrintHex (classOfDevice[1], 0x80); Notify(PSTR(" "), 0x80); - D_PrintHex (hcibuf[8], 0x80); + D_PrintHex (classOfDevice[0], 0x80); #endif hci_set_flag(HCI_FLAG_INCOMING_REQUEST); break; @@ -816,6 +823,12 @@ void BTD::HCI_task() { wiiUProController = false; } } + if(classOfDevice[2] == 0 && classOfDevice[1] == 0x25 && classOfDevice[0] == 0x08 && strncmp((const char*)remote_name, "Wireless Controller", 19) == 0) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nPS4 controller is connecting"), 0x80); +#endif + incomingPS4 = true; + } if(pairWithWii && motionPlusInside) hci_state = HCI_CONNECT_DEVICE_STATE; else { @@ -835,6 +848,9 @@ void BTD::HCI_task() { } D_PrintHex (disc_bdaddr[0], 0x80); #endif + if(incomingPS4) + connectToHIDDevice = true; // We should always connect to the PS4 controller + // Clear these flags for a new connection l2capConnectionClaimed = false; sdpConnectionClaimed = false; @@ -866,6 +882,7 @@ void BTD::HCI_task() { connectToWii = incomingWii = pairWithWii = false; connectToHIDDevice = incomingHIDDevice = pairWithHIDDevice = false; + incomingPS4 = false; hci_state = HCI_SCANNING_STATE; } @@ -967,7 +984,7 @@ void BTD::hci_accept_connection() { hcibuf[6] = disc_bdaddr[3]; hcibuf[7] = disc_bdaddr[4]; hcibuf[8] = disc_bdaddr[5]; - hcibuf[9] = 0x00; //switch role to master + hcibuf[9] = 0x00; // Switch role to master HCI_Command(hcibuf, 10); } @@ -983,10 +1000,10 @@ void BTD::hci_remote_name() { hcibuf[6] = disc_bdaddr[3]; hcibuf[7] = disc_bdaddr[4]; hcibuf[8] = disc_bdaddr[5]; - hcibuf[9] = 0x01; //Page Scan Repetition Mode - hcibuf[10] = 0x00; //Reserved - hcibuf[11] = 0x00; //Clock offset - low byte - hcibuf[12] = 0x00; //Clock offset - high byte + hcibuf[9] = 0x01; // Page Scan Repetition Mode + hcibuf[10] = 0x00; // Reserved + hcibuf[11] = 0x00; // Clock offset - low byte + hcibuf[12] = 0x00; // Clock offset - high byte HCI_Command(hcibuf, 13); } diff --git a/BTD.h b/BTD.h index bacd38c3..0fa6de70 100755 --- a/BTD.h +++ b/BTD.h @@ -571,6 +571,9 @@ private: uint8_t pollInterval; bool bPollEnable; + bool incomingPS4; // True if a PS4 controller is connecting + uint8_t classOfDevice[3]; // Class of device of last device + /* Variables used by high level HCI task */ uint8_t hci_state; //current state of bluetooth hci connection uint16_t hci_counter; // counter used for bluetooth hci reset loops diff --git a/BTHID.cpp b/BTHID.cpp index 3a84ed2d..d6accb58 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -192,14 +192,14 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { case 0x01: // Keyboard events if(pRptParser[KEYBOARD_PARSER_ID]) { uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); - pRptParser[KEYBOARD_PARSER_ID]->Parse(reinterpret_cast(this), 0, (uint8_t)length, &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance + pRptParser[KEYBOARD_PARSER_ID]->Parse(reinterpret_cast(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance } break; case 0x02: // Mouse events if(pRptParser[MOUSE_PARSER_ID]) { uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); - pRptParser[MOUSE_PARSER_ID]->Parse(reinterpret_cast(this), 0, (uint8_t)length, &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance + pRptParser[MOUSE_PARSER_ID]->Parse(reinterpret_cast(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance } break; #ifdef DEBUG_USB_HOST diff --git a/PS4BT.cpp b/PS4BT.cpp new file mode 100644 index 00000000..abab9cfc --- /dev/null +++ b/PS4BT.cpp @@ -0,0 +1,117 @@ +/* Copyright (C) 2014 Kristian Lauszus, TKJ Electronics. All rights reserved. + + 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 + */ + +#include "PS4BT.h" + +// To enable serial debugging see "settings.h" +//#define PRINTREPORT // Uncomment to print the report send by the PS4 Controller + +/** Buttons on the controller */ +const uint8_t PS4_BUTTONS[] PROGMEM = { + DPAD_UP, // UP + DPAD_RIGHT, // RIGHT + DPAD_DOWN, // DOWN + DPAD_LEFT, // LEFT + + 0x0C, // SHARE + 0x0D, // OPTIONS + 0x0E, // L3 + 0x0F, // R3 + + 0x0A, // L2 + 0x0B, // R2 + 0x08, // L1 + 0x09, // R1 + + 0x07, // TRIANGLE + 0x06, // CIRCLE + 0x05, // CROSS + 0x04, // SQUARE + + 0x10, // PS + 0x11, // KEYPAD +}; + +/** Analog buttons on the controller */ +const uint8_t PS4_ANALOG_BUTTONS[] PROGMEM = { + 0, 0, 0, 0, 0, 0, 0, 0, // Skip UP_ANALOG, RIGHT_ANALOG, DOWN_ANALOG, LEFT_ANALOG, SELECT, L3, R3 and START + 0, // L2_ANALOG + 1, // R2_ANALOG +}; + +bool PS4BT::checkDpad(PS4Buttons ps4Buttons, DPADEnum b) { + return ps4Buttons.dpad == b; +} + +bool PS4BT::getButtonPress(ButtonEnum b) { + uint8_t button = pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]); + if (b < 4) // Dpad + return checkDpad(ps4Data.btn, (DPADEnum)button); + else { + uint8_t index = button < 8 ? 0 : button < 16 ? 1 : 2; + uint8_t mask = (1 << (button - 8 * index)); + return ps4Data.btn.val[index] & mask; + } +} + +bool PS4BT::getButtonClick(ButtonEnum b) { + uint8_t button = pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]); + if (b < 4) { // Dpad + if (checkDpad(buttonClickState, (DPADEnum)button)) { + buttonClickState.dpad = DPAD_OFF; + return true; + } + return false; + } else { + uint8_t index = button < 8 ? 0 : button < 16 ? 1 : 2; + uint8_t mask = (1 << (button - 8 * index)); + + bool click = buttonClickState.val[index] & mask; + buttonClickState.val[index] &= ~mask; // Clear "click" event + return click; + } +} + +uint8_t PS4BT::getAnalogButton(ButtonEnum a) { + return (uint8_t)(ps4Data.trigger[pgm_read_byte(&PS4_ANALOG_BUTTONS[(uint8_t)a])]); +} + +uint8_t PS4BT::getAnalogHat(AnalogHatEnum a) { + return ps4Data.hatValue[(uint8_t)a]; +} + +void PS4BT::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) { + if (len == sizeof(PS4Data) && buf) { + memcpy(&ps4Data, buf, len); + + for (uint8_t i = 0; i < sizeof(ps4Data.btn); i++) { + if (ps4Data.btn.val[i] != oldButtonState.val[i]) { + buttonClickState.val[i] = ps4Data.btn.val[i] & ~oldButtonState.val[i]; // Update click state variable + oldButtonState.val[i] = ps4Data.btn.val[i]; + if (i == 0) + buttonClickState.dpad = ps4Data.btn.dpad; // The DPAD buttons does not set the different bits, but set a value corresponding to the buttons pressed + } + } +#ifdef PRINTREPORT + for (uint8_t i = 0; i < len; i++) { + D_PrintHex (buf[i], 0x80); + Notify(PSTR(" "), 0x80); + } + Notify(PSTR("\r\n"), 0x80); +#endif + } +} \ No newline at end of file diff --git a/PS4BT.h b/PS4BT.h new file mode 100644 index 00000000..207cec4f --- /dev/null +++ b/PS4BT.h @@ -0,0 +1,176 @@ +/* Copyright (C) 2014 Kristian Lauszus, TKJ Electronics. All rights reserved. + + 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 + */ + +#ifndef _ps4bt_h_ +#define _ps4bt_h_ + +#include "BTHID.h" +#include "PS3Enums.h" + +enum DPADEnum { + DPAD_UP = 0x0, + DPAD_UP_RIGHT = 0x1, + DPAD_RIGHT = 0x2, + DPAD_RIGHT_DOWN = 0x3, + DPAD_DOWN = 0x4, + DPAD_DOWN_LEFT = 0x5, + DPAD_LEFT = 0x6, + DPAD_LEFT_UP = 0x7, + DPAD_OFF = 0x8, +}; + +union PS4Buttons { + struct { + uint8_t dpad : 4; + uint8_t square : 1; + uint8_t cross : 1; + uint8_t circle : 1; + uint8_t triangle : 1; + + uint8_t l1 : 1; + uint8_t r1 : 1; + uint8_t l2 : 1; + uint8_t r2 : 1; + uint8_t share : 1; + uint8_t options : 1; + uint8_t l3 : 1; + uint8_t r3 : 1; + + uint8_t ps : 1; + uint8_t keypad : 1; + uint8_t dummy : 6; + }; + uint8_t val[3]; +}; + +struct PS4Data { + uint8_t hatValue[4]; + PS4Buttons btn; + uint8_t trigger[2]; +}; + +/** This BluetoothService class implements support for the PS4 controller via Bluetooth. */ +class PS4BT : public HIDReportParser { +public: + /** + * Constructor for the PS4BT class. + * @param p Pointer to the BTD class instance. + */ + PS4BT(BTHID *p) : + pBthid(p) { + pBthid->SetReportParser(KEYBOARD_PARSER_ID, this); + Reset(); + }; + + virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); + + /** @name PS4 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 getButtonPress(ButtonEnum b) will return a true as long as a button is held down, while getButtonClick(ButtonEnum b) will return true once for each button press. + */ + bool getButtonPress(ButtonEnum b); + bool getButtonClick(ButtonEnum b); + /**@}*/ + /** @name PS4 Controller functions */ + /** + * Used to get the analog value from button presses. + * @param a The ::ButtonEnum to read. + * The supported buttons are: + * ::UP, ::RIGHT, ::DOWN, ::LEFT, ::L1, ::L2, ::R1, ::R2, + * ::TRIANGLE, ::CIRCLE, ::CROSS, ::SQUARE, and ::T. + * @return Analog value in the range of 0-255. + */ + uint8_t getAnalogButton(ButtonEnum a); + + /** + * Used to read the analog joystick. + * @param a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY. + * @return Return the analog value in the range of 0-255. + */ + uint8_t getAnalogHat(AnalogHatEnum a); + /**@}*/ + + /** True if a device is connected */ + bool connected() { + if (pBthid) + return pBthid->connected; + return false; + }; + + /** Used this to disconnect the devices. */ + void disconnect() { + if (pBthid) + pBthid->disconnect(); + }; + + /** Call this to start the paring sequence with a device */ + void pair(void) { + if (pBthid) + pBthid->pair(); + }; + + void Reset() { + uint8_t i; + for (0; i < sizeof(ps4Data.hatValue); i++) + ps4Data.hatValue[i] = 127; + for (0; i < sizeof(PS4Buttons); i++) { + ps4Data.btn.val[i] = 0; + oldButtonState.val[i] = 0; + } + for (0; i < sizeof(ps4Data.trigger); i++) + ps4Data.trigger[i] = 0; + + ps4Data.btn.dpad = DPAD_OFF; + oldButtonState.dpad = DPAD_OFF; + buttonClickState.dpad = DPAD_OFF; + }; + + /** + * Used to call your own function when the device is successfully initialized. + * @param funcOnInit Function to call. + */ + void attachOnInit(void (*funcOnInit)(void)) { + pFuncOnInit = funcOnInit; + }; + +private: + /** + * Called when a device is successfully initialized. + * Use attachOnInit(void (*funcOnInit)(void)) to call your own function. + * This is useful for instance if you want to set the LEDs in a specific way. + */ + void onInit() { + Reset(); + if(pFuncOnInit) + pFuncOnInit(); // Call the user function + }; + void (*pFuncOnInit)(void); // Pointer to function called in onInit() + + bool checkDpad(PS4Buttons ps4Buttons, DPADEnum b); // Used to check PS4 DPAD buttons + + BTHID *pBthid; // Pointer to BTHID instance + PS4Data ps4Data; + PS4Buttons oldButtonState, buttonClickState; +}; +#endif \ No newline at end of file diff --git a/controllerEnums.h b/controllerEnums.h index b5129725..700e50a2 100644 --- a/controllerEnums.h +++ b/controllerEnums.h @@ -94,6 +94,12 @@ enum ButtonEnum { T = 18, // Covers 12 bits - we only need to read the top 8 /**@}*/ + /** PS4 controllers buttons - SHARE and OPTIONS are present instead of SELECT and START */ + SHARE = 4, + OPTIONS = 5, + KEYPAD = 17, + /**@}*/ + /**@{*/ /** Xbox buttons */ BACK = 4, diff --git a/examples/Bluetooth/PS4BT/PS4BT.ino b/examples/Bluetooth/PS4BT/PS4BT.ino new file mode 100644 index 00000000..220014e2 --- /dev/null +++ b/examples/Bluetooth/PS4BT/PS4BT.ino @@ -0,0 +1,98 @@ +/* + Example sketch for the PS4 Bluetooth library - developed by Kristian Lauszus + For more information visit my blog: http://blog.tkjelectronics.dk/ or + send me an e-mail: kristianl@tkjelectronics.com + */ + +#include +#include + +// Satisfy IDE, which only needs to see the include statment in the ino. +#ifdef dobogusinclude +#include +#endif + +USB Usb; +//USBHub Hub1(&Usb); // Some dongles have a hub inside +BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so + +/* You can create the instance of the BTHID class in two ways */ +// This will start an inquiry and then pair with the PS4 controller - you only have to do this once +BTHID bthid(&Btd, PAIR); + +// After that you can simply create the instance like so and then press the PS button on the device +//BTHID bthid(&Btd); + +PS4BT PS4(&bthid); // You should not modify this instance + +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\nPS4 Bluetooth Library Started")); +} +void loop() { + Usb.Task(); + + if (PS4.connected()) { + if (PS4.getAnalogHat(LeftHatX) > 137 || PS4.getAnalogHat(LeftHatX) < 117 || PS4.getAnalogHat(LeftHatY) > 137 || PS4.getAnalogHat(LeftHatY) < 117 || PS4.getAnalogHat(RightHatX) > 137 || PS4.getAnalogHat(RightHatX) < 117 || PS4.getAnalogHat(RightHatY) > 137 || PS4.getAnalogHat(RightHatY) < 117) { + Serial.print(F("\r\nLeftHatX: ")); + Serial.print(PS4.getAnalogHat(LeftHatX)); + Serial.print(F("\tLeftHatY: ")); + Serial.print(PS4.getAnalogHat(LeftHatY)); + Serial.print(F("\tRightHatX: ")); + Serial.print(PS4.getAnalogHat(RightHatX)); + Serial.print(F("\tRightHatY: ")); + Serial.print(PS4.getAnalogHat(RightHatY)); + } + + if (PS4.getAnalogButton(L2) || PS4.getAnalogButton(R2)) { // These are the only analog buttons on the PS4 controller + Serial.print(F("\r\nL2: ")); + Serial.print(PS4.getAnalogButton(L2)); + Serial.print(F("\tR2: ")); + Serial.print(PS4.getAnalogButton(R2)); + } + if (PS4.getButtonClick(PS)) { + Serial.print(F("\r\nPS")); + PS4.disconnect(); + } + else { + if (PS4.getButtonClick(TRIANGLE)) + Serial.print(F("\r\nTraingle")); + if (PS4.getButtonClick(CIRCLE)) + Serial.print(F("\r\nCircle")); + if (PS4.getButtonClick(CROSS)) + Serial.print(F("\r\nCross")); + if (PS4.getButtonClick(SQUARE)) + Serial.print(F("\r\nSquare")); + + if (PS4.getButtonClick(UP)) + Serial.print(F("\r\nUp")); + if (PS4.getButtonClick(RIGHT)) + Serial.print(F("\r\nRight")); + if (PS4.getButtonClick(DOWN)) + Serial.print(F("\r\nDown")); + if (PS4.getButtonClick(LEFT)) + Serial.print(F("\r\nLeft")); + + if (PS4.getButtonClick(L1)) + Serial.print(F("\r\nL1")); + if (PS4.getButtonClick(L3)) + Serial.print(F("\r\nL3")); + if (PS4.getButtonClick(R1)) + Serial.print(F("\r\nR1")); + if (PS4.getButtonClick(R3)) + Serial.print(F("\r\nR3")); + + if (PS4.getButtonClick(SHARE)) + Serial.print(F("\r\nShare")); + if (PS4.getButtonClick(OPTIONS)) + Serial.print(F("\r\nOptions")); + if (PS4.getButtonClick(KEYPAD)) + Serial.print(F("\r\nKeypad")); + } + } +} diff --git a/keywords.txt b/keywords.txt index 1c987a4e..4f3cd1a9 100644 --- a/keywords.txt +++ b/keywords.txt @@ -25,13 +25,14 @@ BTD KEYWORD1 Task KEYWORD2 #################################################### -# Syntax Coloring Map For PS3 Bluetooth/USB Library +# Syntax Coloring Map For PS3/PS4 Bluetooth/USB Library #################################################### #################################################### # Datatypes (KEYWORD1) #################################################### +PS4BT KEYWORD1 PS3BT KEYWORD1 PS3USB KEYWORD1 @@ -118,6 +119,10 @@ PS LITERAL1 MOVE LITERAL1 T LITERAL1 +SHARE LITERAL1 +OPTIONS LITERAL1 +KEYPAD LITERAL1 + LeftHatX LITERAL1 LeftHatY LITERAL1 RightHatX LITERAL1 From 3ea4b073f53ebeb6732afdd6767c5cb0610c46c5 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Fri, 10 Jan 2014 18:15:12 +0100 Subject: [PATCH 02/42] Updated documentation typo --- XBOXRECV.h | 2 +- XBOXUSB.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/XBOXRECV.h b/XBOXRECV.h index 41ebef47..c3964991 100644 --- a/XBOXRECV.h +++ b/XBOXRECV.h @@ -173,7 +173,7 @@ public: */ void setRumbleOn(uint8_t lValue, uint8_t rValue, uint8_t controller = 0); /** - * Set LED value. Without using the ::LEDEnum or ::LEDMode enum. + * Set LED value. Without using the ::LEDEnum or ::LEDModeEnum. * @param value See: * setLedOff(uint8_t controller), setLedOn(uint8_t controller, LED l), * setLedBlink(uint8_t controller, LED l), and setLedMode(uint8_t controller, LEDMode lm). diff --git a/XBOXUSB.h b/XBOXUSB.h index 2b358fad..c18ea248 100644 --- a/XBOXUSB.h +++ b/XBOXUSB.h @@ -149,7 +149,7 @@ public: */ void setRumbleOn(uint8_t lValue, uint8_t rValue); /** - * Set LED value. Without using the ::LEDEnum or ::LEDMode enum. + * Set LED value. Without using the ::LEDEnum or ::LEDModeEnum. * @param value See: * setLedOff(), setLedOn(LEDEnum l), * setLedBlink(LEDEnum l), and setLedMode(LEDModeEnum lm). @@ -172,7 +172,7 @@ public: void setLedBlink(LEDEnum l); /** * Used to set special LED modes supported by the Xbox controller. - * @param lm See ::LEDMode. + * @param lm See ::LEDModeEnum. */ void setLedMode(LEDModeEnum lm); From 50561533255416f80525a2cb5c7c58902daabd84 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Fri, 10 Jan 2014 18:23:22 +0100 Subject: [PATCH 03/42] Updated comment --- PS4BT.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/PS4BT.h b/PS4BT.h index 207cec4f..d6db3d2b 100644 --- a/PS4BT.h +++ b/PS4BT.h @@ -63,7 +63,10 @@ struct PS4Data { uint8_t trigger[2]; }; -/** This BluetoothService class implements support for the PS4 controller via Bluetooth. */ +/** + * This class implements support for the PS4 controller via Bluetooth. + * It uses the BTHID class for all the Bluetooth communication. + */ class PS4BT : public HIDReportParser { public: /** From 22efbd4d603c6fcb6281607080326ea2bfaf8727 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 12 Jan 2014 16:05:17 +0100 Subject: [PATCH 04/42] Added information about the PS4 library --- README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 95ba475a..640c6764 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ For more information about the hardware see the [Hardware Manual](http://www.cir * __Alexei Glushchenko, Circuits@Home__ - * Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries * __Kristian Lauszus, TKJ Electronics__ - - * Developer of the [BTD](#bluetooth-libraries), [BTHID](#bthid-library), [SPP](#spp-library), [PS3](#ps3-library), [Wii](#wii-library), and [Xbox](#xbox-library) libraries + * Developer of the [BTD](#bluetooth-libraries), [BTHID](#bthid-library), [SPP](#spp-library), [PS4](#ps4-library), [PS3](#ps3-library), [Wii](#wii-library), and [Xbox](#xbox-library) libraries * __Andrew Kroll__ - * Major contributor to mass storage code @@ -97,6 +97,8 @@ Currently HID mice and keyboards are supported. It uses the standard Boot protocol by default, but it is also able to use the Report protocol as well. You would simply have to call ```setProtocolMode()``` and then parse ```HID_RPT_PROTOCOL``` as an argument. You will then have to modify the parser for your device. See the example: [BTHID.ino](examples/Bluetooth/BTHID/BTHID.ino) for more information. +The [PS4 library](#ps4-library) also uses this class to handle all Bluetooth communication. + ### [SPP library](SPP.cpp) SPP stands for "Serial Port Profile" and is a Bluetooth protocol that implements a virtual comport which allows you to send data back and forth from your computer/phone to your Arduino via Bluetooth. @@ -112,6 +114,20 @@ More information can be found at these blog posts: To implement the SPP protocol I used a Bluetooth sniffing tool called [PacketLogger](http://www.tkjelectronics.com/uploads/PacketLogger.zip) developed by Apple. It enables me to see the Bluetooth communication between my Mac and any device. +### PS4 Library + +This is the [PS4BT](PS4BT.cpp) library. It works with the official Sony PS4 controller via Bluetooth. + +The [PS4BT.ino](examples/Bluetooth/PS4BT/PS4BT.ino) example shows how to easily read the buttons and joysticks on the controller. + +I still have not figured out how to read the touchpad, turn rumble on and off and set the color of the light, but hopefully I will figure that out soon. + +Before you can use the PS4 controller you will need to pair with it. + +Simply create the BTHID instance like so: ```BTHID bthid(&Btd, PAIR);``` and then hold down the PS and Share button at the same time, the PS4 controller will then start to blink rapidly indicating that it is in paring mode. + +It should then automatically pair the dongle with your controller. This only have to be done once. + ### PS3 Library These libraries consist of the [PS3BT](PS3BT.cpp) and [PS3USB](PS3USB.cpp). These libraries allows you to use a Dualshock 3, Navigation or a Motion controller with the USB Host Shield both via Bluetooth and USB. From 7469ff099e612e3d348b882a9fae37f5d5c280e4 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 12 Jan 2014 16:31:47 +0100 Subject: [PATCH 05/42] Typos, whitespace and some other cleanup stuff --- BTD.cpp | 8 +++--- BTD.h | 34 ++++++++++++------------ PS4BT.cpp | 12 ++++----- examples/Bluetooth/BTHID/BTHID.ino | 10 +++---- examples/Bluetooth/PS3BT/PS3BT.ino | 4 +-- examples/Bluetooth/PS3Multi/PS3Multi.ino | 2 +- examples/Bluetooth/PS3SPP/PS3SPP.ino | 4 +-- examples/Bluetooth/PS4BT/PS4BT.ino | 1 + 8 files changed, 38 insertions(+), 37 deletions(-) diff --git a/BTD.cpp b/BTD.cpp index b646b160..9b0d8ab5 100755 --- a/BTD.cpp +++ b/BTD.cpp @@ -36,7 +36,7 @@ qNextPollTime(0), // Reset NextPollTime pollInterval(0), bPollEnable(false) // Don't start polling before dongle is connected { - for(uint8_t i = 0; i < BTD_NUMSERVICES; i++) + for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) btService[i] = NULL; Initialize(); // Set all variables, endpoint structs etc. to default values @@ -293,7 +293,7 @@ void BTD::Initialize() { epInfo[i].epAttribs = 0; epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; } - for(i = 0; i < BTD_NUMSERVICES; i++) { + for(i = 0; i < BTD_NUM_SERVICES; i++) { if(btService[i]) btService[i]->Reset(); // Reset all Bluetooth services } @@ -898,7 +898,7 @@ void BTD::ACL_event_task() { if(!rcode) { // Check for errors if(length > 0) { // Check if any data was read - for(uint8_t i = 0; i < BTD_NUMSERVICES; i++) { + for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) { if(btService[i]) btService[i]->ACLData(l2capinbuf); } @@ -910,7 +910,7 @@ void BTD::ACL_event_task() { D_PrintHex (rcode, 0x80); } #endif - for(uint8_t i = 0; i < BTD_NUMSERVICES; i++) + for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) if(btService[i]) btService[i]->Run(); } diff --git a/BTD.h b/BTD.h index 0fa6de70..609b8c2a 100755 --- a/BTD.h +++ b/BTD.h @@ -187,7 +187,7 @@ #define WI_PROTOCOL_BT 0x01 // Bluetooth Programming Interface #define BTD_MAX_ENDPOINTS 4 -#define BTD_NUMSERVICES 4 // Max number of Bluetooth services - if you need more than 4 simply increase this number +#define BTD_NUM_SERVICES 4 // Max number of Bluetooth services - if you need more than 4 simply increase this number #define PAIR 1 @@ -237,7 +237,7 @@ public: /** @name USBDeviceConfig implementation */ /** - * Address assignment and basic initilization is done here. + * Address assignment and basic initialization is done here. * @param parent Hub number. * @param port Port number on the hub. * @param lowspeed Speed of the device. @@ -258,7 +258,7 @@ public: */ virtual uint8_t Release(); /** - * Poll the USB Input endpoins and run the state machines. + * Poll the USB Input endpoints and run the state machines. * @return 0 on success. */ virtual uint8_t Poll(); @@ -320,18 +320,18 @@ public: /** Disconnects both the L2CAP Channel and the HCI Connection for all Bluetooth services. */ void disconnect() { - for(uint8_t i = 0; i < BTD_NUMSERVICES; i++) + for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) if(btService[i]) btService[i]->disconnect(); }; /** - * Register bluetooth dongle members/services. + * Register Bluetooth dongle members/services. * @param pService Pointer to BluetoothService class instance. - * @return The serice ID on succes or -1 on fail. + * @return The service ID on success or -1 on fail. */ int8_t registerServiceClass(BluetoothService *pService) { - for(uint8_t i = 0; i < BTD_NUMSERVICES; i++) { + for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) { if(!btService[i]) { btService[i] = pService; return i; // Return ID @@ -501,7 +501,7 @@ public: pairWithWii = true; hci_state = HCI_CHECK_DEVICE_SERVICE; }; - /** Used to only send the ACL data to the wiimote. */ + /** Used to only send the ACL data to the Wiimote. */ bool connectToWii; /** True if a Wiimote is connecting. */ bool incomingWii; @@ -517,7 +517,7 @@ public: pairWithHIDDevice = true; hci_state = HCI_CHECK_DEVICE_SERVICE; }; - /** Used to only send the ACL data to the wiimote. */ + /** Used to only send the ACL data to the Wiimote. */ bool connectToHIDDevice; /** True if a Wiimote is connecting. */ bool incomingHIDDevice; @@ -564,7 +564,7 @@ protected: private: void Initialize(); // Set all variables, endpoint structs etc. to default values - BluetoothService* btService[BTD_NUMSERVICES]; + BluetoothService *btService[BTD_NUM_SERVICES]; uint16_t PID, VID; // PID and VID of device connected @@ -575,15 +575,15 @@ private: uint8_t classOfDevice[3]; // Class of device of last device /* Variables used by high level HCI task */ - uint8_t hci_state; //current state of bluetooth hci connection - uint16_t hci_counter; // counter used for bluetooth hci reset loops - uint16_t hci_num_reset_loops; // this value indicate how many times it should read before trying to reset - uint16_t hci_event_flag; // hci flags of received bluetooth events + uint8_t hci_state; // Current state of Bluetooth HCI connection + uint16_t hci_counter; // Counter used for Bluetooth HCI reset loops + uint16_t hci_num_reset_loops; // This value indicate how many times it should read before trying to reset + uint16_t hci_event_flag; // HCI flags of received Bluetooth events uint8_t inquiry_counter; - uint8_t hcibuf[BULK_MAXPKTSIZE]; //General purpose buffer for hci data - uint8_t l2capinbuf[BULK_MAXPKTSIZE]; //General purpose buffer for l2cap in data - uint8_t l2capoutbuf[14]; //General purpose buffer for l2cap out data + uint8_t hcibuf[BULK_MAXPKTSIZE]; // General purpose buffer for HCI data + uint8_t l2capinbuf[BULK_MAXPKTSIZE]; // General purpose buffer for L2CAP in data + uint8_t l2capoutbuf[14]; // General purpose buffer for L2CAP out data /* State machines */ void HCI_event_task(); // Poll the HCI event pipe diff --git a/PS4BT.cpp b/PS4BT.cpp index abab9cfc..1459761e 100644 --- a/PS4BT.cpp +++ b/PS4BT.cpp @@ -48,9 +48,9 @@ const uint8_t PS4_BUTTONS[] PROGMEM = { /** Analog buttons on the controller */ const uint8_t PS4_ANALOG_BUTTONS[] PROGMEM = { - 0, 0, 0, 0, 0, 0, 0, 0, // Skip UP_ANALOG, RIGHT_ANALOG, DOWN_ANALOG, LEFT_ANALOG, SELECT, L3, R3 and START - 0, // L2_ANALOG - 1, // R2_ANALOG + 0, 0, 0, 0, 0, 0, 0, 0, // Skip UP, RIGHT, DOWN, LEFT, SHARE, OPTIONS, L3, and R3 + 0, // L2 + 1, // R2 }; bool PS4BT::checkDpad(PS4Buttons ps4Buttons, DPADEnum b) { @@ -59,7 +59,7 @@ bool PS4BT::checkDpad(PS4Buttons ps4Buttons, DPADEnum b) { bool PS4BT::getButtonPress(ButtonEnum b) { uint8_t button = pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]); - if (b < 4) // Dpad + if (b <= LEFT) // Dpad return checkDpad(ps4Data.btn, (DPADEnum)button); else { uint8_t index = button < 8 ? 0 : button < 16 ? 1 : 2; @@ -70,7 +70,7 @@ bool PS4BT::getButtonPress(ButtonEnum b) { bool PS4BT::getButtonClick(ButtonEnum b) { uint8_t button = pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]); - if (b < 4) { // Dpad + if (b <= LEFT) { // Dpad if (checkDpad(buttonClickState, (DPADEnum)button)) { buttonClickState.dpad = DPAD_OFF; return true; @@ -87,7 +87,7 @@ bool PS4BT::getButtonClick(ButtonEnum b) { } uint8_t PS4BT::getAnalogButton(ButtonEnum a) { - return (uint8_t)(ps4Data.trigger[pgm_read_byte(&PS4_ANALOG_BUTTONS[(uint8_t)a])]); + return ps4Data.trigger[pgm_read_byte(&PS4_ANALOG_BUTTONS[(uint8_t)a])]; } uint8_t PS4BT::getAnalogHat(AnalogHatEnum a) { diff --git a/examples/Bluetooth/BTHID/BTHID.ino b/examples/Bluetooth/BTHID/BTHID.ino index a38411b5..fcfd686a 100644 --- a/examples/Bluetooth/BTHID/BTHID.ino +++ b/examples/Bluetooth/BTHID/BTHID.ino @@ -20,7 +20,7 @@ BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so /* You can create the instance of the class in two ways */ // This will start an inquiry and then pair with your device - you only have to do this once // If you are using a Bluetooth keyboard, then you should type in the password on the keypad and then press enter -BTHID hid(&Btd, PAIR, "0000"); +BTHID bthid(&Btd, PAIR, "0000"); // After that you can simply create the instance like so and then press any button on the device //BTHID hid(&Btd); @@ -36,13 +36,13 @@ void setup() { while (1); // Halt } - hid.SetReportParser(KEYBOARD_PARSER_ID, (HIDReportParser*)&keyboardPrs); - hid.SetReportParser(MOUSE_PARSER_ID, (HIDReportParser*)&mousePrs); + bthid.SetReportParser(KEYBOARD_PARSER_ID, (HIDReportParser*)&keyboardPrs); + bthid.SetReportParser(MOUSE_PARSER_ID, (HIDReportParser*)&mousePrs); // If "Boot Protocol Mode" does not work, then try "Report Protocol Mode" // If that does not work either, then uncomment PRINTREPORT in BTHID.cpp to see the raw report - hid.setProtocolMode(HID_BOOT_PROTOCOL); // Boot Protocol Mode - //hid.setProtocolMode(HID_RPT_PROTOCOL); // Report Protocol Mode + bthid.setProtocolMode(HID_BOOT_PROTOCOL); // Boot Protocol Mode + //bthid.setProtocolMode(HID_RPT_PROTOCOL); // Report Protocol Mode Serial.print(F("\r\nHID Bluetooth Library Started")); } diff --git a/examples/Bluetooth/PS3BT/PS3BT.ino b/examples/Bluetooth/PS3BT/PS3BT.ino index 3cb0ae7a..982eb384 100644 --- a/examples/Bluetooth/PS3BT/PS3BT.ino +++ b/examples/Bluetooth/PS3BT/PS3BT.ino @@ -17,7 +17,7 @@ USB Usb; BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so /* You can create the instance of the class in two ways */ PS3BT PS3(&Btd); // This will just create the instance -//PS3BT PS3(&Btd,0x00,0x15,0x83,0x3D,0x0A,0x57); // This will also store the bluetooth address - this can be obtained from the dongle when running the sketch +//PS3BT PS3(&Btd, 0x00, 0x15, 0x83, 0x3D, 0x0A, 0x57); // This will also store the bluetooth address - this can be obtained from the dongle when running the sketch boolean printTemperature; boolean printAngle; @@ -52,7 +52,7 @@ void loop() { if (PS3.getAnalogButton(L2) || PS3.getAnalogButton(R2)) { Serial.print(F("\r\nL2: ")); Serial.print(PS3.getAnalogButton(L2)); - if (!PS3.PS3NavigationConnected) { + if (PS3.PS3Connected) { Serial.print(F("\tR2: ")); Serial.print(PS3.getAnalogButton(R2)); } diff --git a/examples/Bluetooth/PS3Multi/PS3Multi.ino b/examples/Bluetooth/PS3Multi/PS3Multi.ino index 9ce39857..23e8cd9a 100644 --- a/examples/Bluetooth/PS3Multi/PS3Multi.ino +++ b/examples/Bluetooth/PS3Multi/PS3Multi.ino @@ -56,7 +56,7 @@ void loop() { if (PS3[i]->getAnalogButton(L2) || PS3[i]->getAnalogButton(R2)) { Serial.print(F("\r\nL2: ")); Serial.print(PS3[i]->getAnalogButton(L2)); - if (!PS3[i]->PS3NavigationConnected) { + if (PS3[i]->PS3Connected) { Serial.print(F("\tR2: ")); Serial.print(PS3[i]->getAnalogButton(R2)); } diff --git a/examples/Bluetooth/PS3SPP/PS3SPP.ino b/examples/Bluetooth/PS3SPP/PS3SPP.ino index 6bc7afc6..440ea79e 100644 --- a/examples/Bluetooth/PS3SPP/PS3SPP.ino +++ b/examples/Bluetooth/PS3SPP/PS3SPP.ino @@ -26,7 +26,7 @@ BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so SPP SerialBT(&Btd); // This will set the name to the defaults: "Arduino" and the pin to "0000" //SPP SerialBTBT(&Btd,"Lauszus's Arduino","0000"); // You can also set the name and pin like so PS3BT PS3(&Btd); // This will just create the instance -//PS3BT PS3(&Btd,0x00,0x15,0x83,0x3D,0x0A,0x57); // This will also store the bluetooth address - this can be obtained from the dongle when running the sketch +//PS3BT PS3(&Btd, 0x00, 0x15, 0x83, 0x3D, 0x0A, 0x57); // This will also store the bluetooth address - this can be obtained from the dongle when running the sketch boolean firstMessage = true; String output = ""; // We will store the data in this string @@ -77,7 +77,7 @@ void loop() { output += "\r\n"; output += "L2: "; output += PS3.getAnalogButton(L2); - if (!PS3.PS3NavigationConnected) { + if (PS3.PS3Connected) { output += "\tR2: "; output += PS3.getAnalogButton(R2); } diff --git a/examples/Bluetooth/PS4BT/PS4BT.ino b/examples/Bluetooth/PS4BT/PS4BT.ino index 220014e2..6715b904 100644 --- a/examples/Bluetooth/PS4BT/PS4BT.ino +++ b/examples/Bluetooth/PS4BT/PS4BT.ino @@ -18,6 +18,7 @@ BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so /* You can create the instance of the BTHID class in two ways */ // This will start an inquiry and then pair with the PS4 controller - you only have to do this once +// You will need to hold down the PS and Share button at the same time, the PS4 controller will then start to blink rapidly indicating that it is in paring mode BTHID bthid(&Btd, PAIR); // After that you can simply create the instance like so and then press the PS button on the device From c163228063e327616ed0be00812d08094388048c Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 12 Jan 2014 16:33:19 +0100 Subject: [PATCH 06/42] Renamed KEYPAD to TOUCHPAD --- PS4BT.cpp | 2 +- PS4BT.h | 2 +- controllerEnums.h | 2 +- examples/Bluetooth/PS4BT/PS4BT.ino | 4 ++-- keywords.txt | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/PS4BT.cpp b/PS4BT.cpp index 1459761e..a49195a2 100644 --- a/PS4BT.cpp +++ b/PS4BT.cpp @@ -43,7 +43,7 @@ const uint8_t PS4_BUTTONS[] PROGMEM = { 0x04, // SQUARE 0x10, // PS - 0x11, // KEYPAD + 0x11, // TOUCHPAD }; /** Analog buttons on the controller */ diff --git a/PS4BT.h b/PS4BT.h index d6db3d2b..379565d4 100644 --- a/PS4BT.h +++ b/PS4BT.h @@ -51,7 +51,7 @@ union PS4Buttons { uint8_t r3 : 1; uint8_t ps : 1; - uint8_t keypad : 1; + uint8_t touchpad : 1; uint8_t dummy : 6; }; uint8_t val[3]; diff --git a/controllerEnums.h b/controllerEnums.h index 700e50a2..2cc0b789 100644 --- a/controllerEnums.h +++ b/controllerEnums.h @@ -97,7 +97,7 @@ enum ButtonEnum { /** PS4 controllers buttons - SHARE and OPTIONS are present instead of SELECT and START */ SHARE = 4, OPTIONS = 5, - KEYPAD = 17, + TOUCHPAD = 17, /**@}*/ /**@{*/ diff --git a/examples/Bluetooth/PS4BT/PS4BT.ino b/examples/Bluetooth/PS4BT/PS4BT.ino index 6715b904..bf068876 100644 --- a/examples/Bluetooth/PS4BT/PS4BT.ino +++ b/examples/Bluetooth/PS4BT/PS4BT.ino @@ -92,8 +92,8 @@ void loop() { Serial.print(F("\r\nShare")); if (PS4.getButtonClick(OPTIONS)) Serial.print(F("\r\nOptions")); - if (PS4.getButtonClick(KEYPAD)) - Serial.print(F("\r\nKeypad")); + if (PS4.getButtonClick(TOUCHPAD)) + Serial.print(F("\r\nTouchpad")); } } } diff --git a/keywords.txt b/keywords.txt index 4f3cd1a9..a60fe5d8 100644 --- a/keywords.txt +++ b/keywords.txt @@ -121,7 +121,7 @@ T LITERAL1 SHARE LITERAL1 OPTIONS LITERAL1 -KEYPAD LITERAL1 +TOUCHPAD LITERAL1 LeftHatX LITERAL1 LeftHatY LITERAL1 From eea5c44b962baa5929363886e8788d6de7668d5a Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 12 Jan 2014 17:20:18 +0100 Subject: [PATCH 07/42] Now onInit() works with the PS4 library as well --- BTHID.cpp | 5 +++++ BTHID.h | 30 +++++++++++++++++++++++++++++- PS4BT.h | 34 +++++++++++++++++++--------------- 3 files changed, 53 insertions(+), 16 deletions(-) diff --git a/BTHID.cpp b/BTHID.cpp index d6accb58..19cf024e 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -46,6 +46,11 @@ void BTHID::Reset() { activeConnection = false; l2cap_event_flag = 0; // Reset flags l2cap_state = L2CAP_WAIT; + + for(uint8_t i = 0; i < BTHID_NUM_SERVICES; i++) { + if(bthidService[i]) + bthidService[i]->Reset(); + } } void BTHID::disconnect() { // Use this void to disconnect the device diff --git a/BTHID.h b/BTHID.h index 3e9c0394..e4df8384 100644 --- a/BTHID.h +++ b/BTHID.h @@ -25,6 +25,14 @@ #define MOUSE_PARSER_ID 1 #define NUM_PARSERS 2 +#define BTHID_NUM_SERVICES 4 // Max number of Bluetooth HID services - if you need more than 4 simply increase this number + +class BTHIDService { +public: + virtual void onInit(); + virtual void Reset(); +}; + /** This BluetoothService class implements support for the HID keyboard and mice. */ class BTHID : public BluetoothService { public: @@ -106,10 +114,25 @@ public: pFuncOnInit = funcOnInit; }; + /** + * Register Bluetooth HID services. + * @param pService Pointer to BTHIDService class instance. + * @return The service ID on success or -1 on fail. + */ + int8_t registerServiceClass(BTHIDService *pService) { + for(uint8_t i = 0; i < BTHID_NUM_SERVICES; i++) { + if(!bthidService[i]) { + bthidService[i] = pService; + return i; // Return ID + } + } + return -1; // ErrorregisterServiceClass + }; + private: BTD *pBtd; // Pointer to BTD instance - HIDReportParser *pRptParser[NUM_PARSERS]; // Pointer to HIDReportParsers. + BTHIDService *bthidService[BTHID_NUM_SERVICES]; /** Set report protocol. */ void setProtocol(); @@ -123,6 +146,11 @@ private: void onInit() { if(pFuncOnInit) pFuncOnInit(); // Call the user function + + for(uint8_t i = 0; i < BTHID_NUM_SERVICES; i++) { + if(bthidService[i]) + bthidService[i]->onInit(); + } }; void (*pFuncOnInit)(void); // Pointer to function called in onInit() diff --git a/PS4BT.h b/PS4BT.h index 379565d4..3810225f 100644 --- a/PS4BT.h +++ b/PS4BT.h @@ -67,15 +67,16 @@ struct PS4Data { * This class implements support for the PS4 controller via Bluetooth. * It uses the BTHID class for all the Bluetooth communication. */ -class PS4BT : public HIDReportParser { +class PS4BT : public HIDReportParser, public BTHIDService { public: /** * Constructor for the PS4BT class. - * @param p Pointer to the BTD class instance. + * @param p Pointer to the BTHID class instance. */ PS4BT(BTHID *p) : pBthid(p) { pBthid->SetReportParser(KEYBOARD_PARSER_ID, this); + pBthid->registerServiceClass(this); // Register it as a Bluetooth HID service Reset(); }; @@ -133,7 +134,17 @@ public: pBthid->pair(); }; - void Reset() { + /** + * Used to call your own function when the device is successfully initialized. + * @param funcOnInit Function to call. + */ + void attachOnInit(void (*funcOnInit)(void)) { + pFuncOnInit = funcOnInit; + }; + + /** @name BTHIDService implementation */ + /** Used to reset the different buffers to there default values */ + virtual void Reset() { uint8_t i; for (0; i < sizeof(ps4Data.hatValue); i++) ps4Data.hatValue[i] = 127; @@ -149,25 +160,18 @@ public: buttonClickState.dpad = DPAD_OFF; }; - /** - * Used to call your own function when the device is successfully initialized. - * @param funcOnInit Function to call. - */ - void attachOnInit(void (*funcOnInit)(void)) { - pFuncOnInit = funcOnInit; - }; - -private: /** * Called when a device is successfully initialized. * Use attachOnInit(void (*funcOnInit)(void)) to call your own function. * This is useful for instance if you want to set the LEDs in a specific way. */ - void onInit() { - Reset(); - if(pFuncOnInit) + virtual void onInit() { + if (pFuncOnInit) pFuncOnInit(); // Call the user function }; + /**@}*/ + +private: void (*pFuncOnInit)(void); // Pointer to function called in onInit() bool checkDpad(PS4Buttons ps4Buttons, DPADEnum b); // Used to check PS4 DPAD buttons From 3dd5b1ab1c4d4746609757ac9e0bf91dd167e59e Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 12 Jan 2014 18:15:13 +0100 Subject: [PATCH 08/42] Handle DPAD properly on the PS4 controller The DPAD got separate values for each case - see: DPADEnum in PS4BT.h. --- PS4BT.cpp | 61 +++++++++++++++++++++++++++++++++++++------------------ PS4BT.h | 6 ++++-- 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/PS4BT.cpp b/PS4BT.cpp index a49195a2..48f9f921 100644 --- a/PS4BT.cpp +++ b/PS4BT.cpp @@ -53,14 +53,25 @@ const uint8_t PS4_ANALOG_BUTTONS[] PROGMEM = { 1, // R2 }; -bool PS4BT::checkDpad(PS4Buttons ps4Buttons, DPADEnum b) { - return ps4Buttons.dpad == b; +bool PS4BT::checkDpad(DPADEnum b) { + switch (b) { + case DPAD_UP: + return ps4Data.btn.dpad == DPAD_LEFT_UP || ps4Data.btn.dpad == DPAD_UP || ps4Data.btn.dpad == DPAD_UP_RIGHT; + case DPAD_RIGHT: + return ps4Data.btn.dpad == DPAD_UP_RIGHT || ps4Data.btn.dpad == DPAD_RIGHT || ps4Data.btn.dpad == DPAD_RIGHT_DOWN; + case DPAD_DOWN: + return ps4Data.btn.dpad == DPAD_RIGHT_DOWN || ps4Data.btn.dpad == DPAD_DOWN || ps4Data.btn.dpad == DPAD_DOWN_LEFT; + case DPAD_LEFT: + return ps4Data.btn.dpad == DPAD_DOWN_LEFT || ps4Data.btn.dpad == DPAD_LEFT || ps4Data.btn.dpad == DPAD_LEFT_UP; + default: + return false; + } } bool PS4BT::getButtonPress(ButtonEnum b) { uint8_t button = pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]); if (b <= LEFT) // Dpad - return checkDpad(ps4Data.btn, (DPADEnum)button); + return checkDpad((DPADEnum)button); else { uint8_t index = button < 8 ? 0 : button < 16 ? 1 : 2; uint8_t mask = (1 << (button - 8 * index)); @@ -69,21 +80,18 @@ bool PS4BT::getButtonPress(ButtonEnum b) { } bool PS4BT::getButtonClick(ButtonEnum b) { - uint8_t button = pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]); - if (b <= LEFT) { // Dpad - if (checkDpad(buttonClickState, (DPADEnum)button)) { - buttonClickState.dpad = DPAD_OFF; - return true; - } - return false; - } else { - uint8_t index = button < 8 ? 0 : button < 16 ? 1 : 2; - uint8_t mask = (1 << (button - 8 * index)); - - bool click = buttonClickState.val[index] & mask; - buttonClickState.val[index] &= ~mask; // Clear "click" event - return click; + uint8_t mask, index = 0; + if (b <= LEFT) // Dpad + mask = 1 << b; + else { + uint8_t button = pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]); + index = button < 8 ? 0 : button < 16 ? 1 : 2; + mask = (1 << (button - 8 * index)); } + + bool click = buttonClickState.val[index] & mask; + buttonClickState.val[index] &= ~mask; // Clear "click" event + return click; } uint8_t PS4BT::getAnalogButton(ButtonEnum a) { @@ -99,11 +107,24 @@ void PS4BT::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) { memcpy(&ps4Data, buf, len); for (uint8_t i = 0; i < sizeof(ps4Data.btn); i++) { - if (ps4Data.btn.val[i] != oldButtonState.val[i]) { + if (ps4Data.btn.val[i] != oldButtonState.val[i]) { // Check if anything has changed buttonClickState.val[i] = ps4Data.btn.val[i] & ~oldButtonState.val[i]; // Update click state variable oldButtonState.val[i] = ps4Data.btn.val[i]; - if (i == 0) - buttonClickState.dpad = ps4Data.btn.dpad; // The DPAD buttons does not set the different bits, but set a value corresponding to the buttons pressed + if (i == 0) { // The DPAD buttons does not set the different bits, but set a value corresponding to the buttons pressed, we will simply set the bits ourself + uint8_t newDpad = 0; + if (checkDpad(DPAD_UP)) + newDpad |= 1 << UP; + if (checkDpad(DPAD_RIGHT)) + newDpad |= 1 << RIGHT; + if (checkDpad(DPAD_DOWN)) + newDpad |= 1 << DOWN; + if (checkDpad(DPAD_LEFT)) + newDpad |= 1 << LEFT; + if (newDpad != oldDpad) { + buttonClickState.dpad = newDpad & ~oldDpad; // Override values + oldDpad = newDpad; + } + } } } #ifdef PRINTREPORT diff --git a/PS4BT.h b/PS4BT.h index 3810225f..dcf910e2 100644 --- a/PS4BT.h +++ b/PS4BT.h @@ -157,7 +157,8 @@ public: ps4Data.btn.dpad = DPAD_OFF; oldButtonState.dpad = DPAD_OFF; - buttonClickState.dpad = DPAD_OFF; + buttonClickState.dpad = 0; + oldDpad = 0; }; /** @@ -174,10 +175,11 @@ public: private: void (*pFuncOnInit)(void); // Pointer to function called in onInit() - bool checkDpad(PS4Buttons ps4Buttons, DPADEnum b); // Used to check PS4 DPAD buttons + bool checkDpad(DPADEnum b); // Used to check PS4 DPAD buttons BTHID *pBthid; // Pointer to BTHID instance PS4Data ps4Data; PS4Buttons oldButtonState, buttonClickState; + uint8_t oldDpad; }; #endif \ No newline at end of file From 6ae41c436f1d50f1911f149e10c3fab18e845d49 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 12 Jan 2014 19:26:19 +0100 Subject: [PATCH 09/42] Fixed include --- PS4BT.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PS4BT.h b/PS4BT.h index dcf910e2..d328188b 100644 --- a/PS4BT.h +++ b/PS4BT.h @@ -19,7 +19,7 @@ #define _ps4bt_h_ #include "BTHID.h" -#include "PS3Enums.h" +#include "controllerEnums.h" enum DPADEnum { DPAD_UP = 0x0, From 2e4f9c852d29aab8b19c9f44bd30e4158f9c4a0c Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Tue, 14 Jan 2014 23:56:17 +0100 Subject: [PATCH 10/42] Added information about powered hub to FAQ --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 640c6764..157e84f4 100644 --- a/README.md +++ b/README.md @@ -236,4 +236,5 @@ All the information about the Wii controllers are from these sites: > When I plug my device into the USB connector nothing happens? -Try to connect a external power supply to the Arduino - this solves the problem in most cases. \ No newline at end of file +* Try to connect a external power supply to the Arduino - this solves the problem in most cases. +* You can also use a powered hub between the device and the USB Host Shield. You should then include the USB hub library: ```#include ``` and create the instance like so: ```USBHub Hub1(&Usb);```. \ No newline at end of file From 0c0541344752c9778e328ea17995c8ddc889b503 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Thu, 16 Jan 2014 18:56:42 +0100 Subject: [PATCH 11/42] Remote name buffer should be a char array --- BTD.cpp | 5 +---- BTD.h | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/BTD.cpp b/BTD.cpp index 9b0d8ab5..4de668d9 100755 --- a/BTD.cpp +++ b/BTD.cpp @@ -796,11 +796,8 @@ void BTD::HCI_task() { if(hci_check_flag(HCI_FLAG_REMOTE_NAME_COMPLETE)) { #ifdef DEBUG_USB_HOST Notify(PSTR("\r\nRemote Name: "), 0x80); - for(uint8_t i = 0; i < 30; i++) { - if(remote_name[i] == '\0') // End of string - break; + for(uint8_t i = 0; i < strlen(remote_name); i++) Notifyc(remote_name[i], 0x80); - } #endif if(strncmp((const char*)remote_name, "Nintendo", 8) == 0) { incomingWii = true; diff --git a/BTD.h b/BTD.h index 609b8c2a..3a639abb 100755 --- a/BTD.h +++ b/BTD.h @@ -488,7 +488,7 @@ public: /** Last incoming devices Bluetooth address. */ uint8_t disc_bdaddr[6]; /** First 30 chars of last remote name. */ - uint8_t remote_name[30]; + char remote_name[30]; /** * The supported HCI Version read from the Bluetooth dongle. * Used by the PS3BT library to check the HCI Version of the Bluetooth dongle, From da2ee954453f48a815a33105fa6e060e52f421cb Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sat, 18 Jan 2014 22:36:01 +0100 Subject: [PATCH 12/42] Added support for the PS4 controller via USB Also improved the PS4BT library --- BTHID.cpp | 19 +-- BTHID.h | 44 +++--- PS3Enums.h | 6 - PS4BT.h | 155 +++--------------- PS4BT.cpp => PS4Parser.cpp | 97 ++++-------- PS4Parser.h | 246 +++++++++++++++++++++++++++++ PS4USB.h | 87 ++++++++++ README.md | 12 +- controllerEnums.h | 6 + examples/Bluetooth/PS4BT/PS4BT.ino | 8 +- examples/PS4USB/PS4USB.ino | 107 +++++++++++++ hiduniversal.cpp | 14 +- hiduniversal.h | 11 ++ keywords.txt | 10 +- 14 files changed, 573 insertions(+), 249 deletions(-) rename PS4BT.cpp => PS4Parser.cpp (51%) create mode 100644 PS4Parser.h create mode 100644 PS4USB.h create mode 100644 examples/PS4USB/PS4USB.ino diff --git a/BTHID.cpp b/BTHID.cpp index 19cf024e..64d3a812 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -46,11 +46,7 @@ void BTHID::Reset() { activeConnection = false; l2cap_event_flag = 0; // Reset flags l2cap_state = L2CAP_WAIT; - - for(uint8_t i = 0; i < BTHID_NUM_SERVICES; i++) { - if(bthidService[i]) - bthidService[i]->Reset(); - } + ResetBTHID(); } void BTHID::disconnect() { // Use this void to disconnect the device @@ -193,19 +189,18 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { } #endif if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT + uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); + ParseBTHID(this, (uint8_t)(length - 1), &l2capinbuf[9]); + switch(l2capinbuf[9]) { - case 0x01: // Keyboard events - if(pRptParser[KEYBOARD_PARSER_ID]) { - uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); + case 0x01: // Keyboard or Joystick events + if(pRptParser[KEYBOARD_PARSER_ID]) pRptParser[KEYBOARD_PARSER_ID]->Parse(reinterpret_cast(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance - } break; case 0x02: // Mouse events - if(pRptParser[MOUSE_PARSER_ID]) { - uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); + if(pRptParser[MOUSE_PARSER_ID]) pRptParser[MOUSE_PARSER_ID]->Parse(reinterpret_cast(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance - } break; #ifdef DEBUG_USB_HOST default: diff --git a/BTHID.h b/BTHID.h index e4df8384..0dcd6a1e 100644 --- a/BTHID.h +++ b/BTHID.h @@ -25,14 +25,6 @@ #define MOUSE_PARSER_ID 1 #define NUM_PARSERS 2 -#define BTHID_NUM_SERVICES 4 // Max number of Bluetooth HID services - if you need more than 4 simply increase this number - -class BTHIDService { -public: - virtual void onInit(); - virtual void Reset(); -}; - /** This BluetoothService class implements support for the HID keyboard and mice. */ class BTHID : public BluetoothService { public: @@ -56,7 +48,6 @@ public: virtual void Reset(); /** Used this to disconnect the devices. */ virtual void disconnect(); - /**@}*/ /** @@ -114,25 +105,30 @@ public: pFuncOnInit = funcOnInit; }; +protected: + /** @name Overridable functions */ /** - * Register Bluetooth HID services. - * @param pService Pointer to BTHIDService class instance. - * @return The service ID on success or -1 on fail. + * Used to parse Bluetooth HID data to any class that inherits this class. + * @param bthid Pointer to this class. + * @param len The length of the incoming data. + * @param buf Pointer to the data buffer. */ - int8_t registerServiceClass(BTHIDService *pService) { - for(uint8_t i = 0; i < BTHID_NUM_SERVICES; i++) { - if(!bthidService[i]) { - bthidService[i] = pService; - return i; // Return ID - } - } - return -1; // ErrorregisterServiceClass + virtual void ParseBTHID(BTHID *bthid, uint8_t len, uint8_t *buf) { + return; }; + /** Called when a device is connected */ + virtual void OnInitBTHID() { + return; + }; + /** Used to reset any buffers in the class that inherits this */ + virtual void ResetBTHID() { + return; + } + /**@}*/ private: BTD *pBtd; // Pointer to BTD instance HIDReportParser *pRptParser[NUM_PARSERS]; // Pointer to HIDReportParsers. - BTHIDService *bthidService[BTHID_NUM_SERVICES]; /** Set report protocol. */ void setProtocol(); @@ -146,11 +142,7 @@ private: void onInit() { if(pFuncOnInit) pFuncOnInit(); // Call the user function - - for(uint8_t i = 0; i < BTHID_NUM_SERVICES; i++) { - if(bthidService[i]) - bthidService[i]->onInit(); - } + OnInitBTHID(); }; void (*pFuncOnInit)(void); // Pointer to function called in onInit() diff --git a/PS3Enums.h b/PS3Enums.h index befb087e..dca5bebe 100644 --- a/PS3Enums.h +++ b/PS3Enums.h @@ -174,12 +174,6 @@ enum SensorEnum { mYmove = 50, }; -/** Used to get the angle calculated using the accelerometer. */ -enum AngleEnum { - Pitch = 0x01, - Roll = 0x02, -}; - enum StatusEnum { // Note that the location is shifted 9 when it's connected via USB // Byte location | bit location diff --git a/PS4BT.h b/PS4BT.h index d328188b..a723cec8 100644 --- a/PS4BT.h +++ b/PS4BT.h @@ -19,119 +19,53 @@ #define _ps4bt_h_ #include "BTHID.h" -#include "controllerEnums.h" - -enum DPADEnum { - DPAD_UP = 0x0, - DPAD_UP_RIGHT = 0x1, - DPAD_RIGHT = 0x2, - DPAD_RIGHT_DOWN = 0x3, - DPAD_DOWN = 0x4, - DPAD_DOWN_LEFT = 0x5, - DPAD_LEFT = 0x6, - DPAD_LEFT_UP = 0x7, - DPAD_OFF = 0x8, -}; - -union PS4Buttons { - struct { - uint8_t dpad : 4; - uint8_t square : 1; - uint8_t cross : 1; - uint8_t circle : 1; - uint8_t triangle : 1; - - uint8_t l1 : 1; - uint8_t r1 : 1; - uint8_t l2 : 1; - uint8_t r2 : 1; - uint8_t share : 1; - uint8_t options : 1; - uint8_t l3 : 1; - uint8_t r3 : 1; - - uint8_t ps : 1; - uint8_t touchpad : 1; - uint8_t dummy : 6; - }; - uint8_t val[3]; -}; - -struct PS4Data { - uint8_t hatValue[4]; - PS4Buttons btn; - uint8_t trigger[2]; -}; +#include "PS4Parser.h" /** * This class implements support for the PS4 controller via Bluetooth. * It uses the BTHID class for all the Bluetooth communication. */ -class PS4BT : public HIDReportParser, public BTHIDService { +class PS4BT : public BTHID, public PS4Parser { public: /** * Constructor for the PS4BT class. * @param p Pointer to the BTHID class instance. */ - PS4BT(BTHID *p) : - pBthid(p) { - pBthid->SetReportParser(KEYBOARD_PARSER_ID, this); - pBthid->registerServiceClass(this); // Register it as a Bluetooth HID service - Reset(); + PS4BT(BTD *p, bool pair = false, const char *pin = "0000") : + BTHID(p, pair, pin) { + PS4Parser::Reset(); }; - virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); - - /** @name PS4 Controller functions */ + /** @name BTHID implementation */ /** - * 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 getButtonPress(ButtonEnum b) will return a true as long as a button is held down, while getButtonClick(ButtonEnum b) will return true once for each button press. + * Used to parse Bluetooth HID data. + * @param bthid Pointer to the BTHID class. + * @param len The length of the incoming data. + * @param buf Pointer to the data buffer. */ - bool getButtonPress(ButtonEnum b); - bool getButtonClick(ButtonEnum b); - /**@}*/ - /** @name PS4 Controller functions */ - /** - * Used to get the analog value from button presses. - * @param a The ::ButtonEnum to read. - * The supported buttons are: - * ::UP, ::RIGHT, ::DOWN, ::LEFT, ::L1, ::L2, ::R1, ::R2, - * ::TRIANGLE, ::CIRCLE, ::CROSS, ::SQUARE, and ::T. - * @return Analog value in the range of 0-255. - */ - uint8_t getAnalogButton(ButtonEnum a); + virtual void ParseBTHID(BTHID *bthid, uint8_t len, uint8_t *buf) { + PS4Parser::Parse(len, buf); + }; /** - * Used to read the analog joystick. - * @param a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY. - * @return Return the analog value in the range of 0-255. + * Called when a device is successfully initialized. + * Use attachOnInit(void (*funcOnInit)(void)) to call your own function. + * This is useful for instance if you want to set the LEDs in a specific way. */ - uint8_t getAnalogHat(AnalogHatEnum a); + virtual void OnInitBTHID() { + if (pFuncOnInit) + pFuncOnInit(); // Call the user function + }; + + /** Used to reset the different buffers to there default values */ + virtual void ResetBTHID() { + PS4Parser::Reset(); + }; /**@}*/ /** True if a device is connected */ bool connected() { - if (pBthid) - return pBthid->connected; - return false; - }; - - /** Used this to disconnect the devices. */ - void disconnect() { - if (pBthid) - pBthid->disconnect(); - }; - - /** Call this to start the paring sequence with a device */ - void pair(void) { - if (pBthid) - pBthid->pair(); + BTHID::connected; }; /** @@ -142,44 +76,7 @@ public: pFuncOnInit = funcOnInit; }; - /** @name BTHIDService implementation */ - /** Used to reset the different buffers to there default values */ - virtual void Reset() { - uint8_t i; - for (0; i < sizeof(ps4Data.hatValue); i++) - ps4Data.hatValue[i] = 127; - for (0; i < sizeof(PS4Buttons); i++) { - ps4Data.btn.val[i] = 0; - oldButtonState.val[i] = 0; - } - for (0; i < sizeof(ps4Data.trigger); i++) - ps4Data.trigger[i] = 0; - - ps4Data.btn.dpad = DPAD_OFF; - oldButtonState.dpad = DPAD_OFF; - buttonClickState.dpad = 0; - oldDpad = 0; - }; - - /** - * Called when a device is successfully initialized. - * Use attachOnInit(void (*funcOnInit)(void)) to call your own function. - * This is useful for instance if you want to set the LEDs in a specific way. - */ - virtual void onInit() { - if (pFuncOnInit) - pFuncOnInit(); // Call the user function - }; - /**@}*/ - private: void (*pFuncOnInit)(void); // Pointer to function called in onInit() - - bool checkDpad(DPADEnum b); // Used to check PS4 DPAD buttons - - BTHID *pBthid; // Pointer to BTHID instance - PS4Data ps4Data; - PS4Buttons oldButtonState, buttonClickState; - uint8_t oldDpad; }; #endif \ No newline at end of file diff --git a/PS4BT.cpp b/PS4Parser.cpp similarity index 51% rename from PS4BT.cpp rename to PS4Parser.cpp index 48f9f921..16c1ee3d 100644 --- a/PS4BT.cpp +++ b/PS4Parser.cpp @@ -15,78 +15,45 @@ e-mail : kristianl@tkjelectronics.com */ -#include "PS4BT.h" +#include "PS4Parser.h" // To enable serial debugging see "settings.h" //#define PRINTREPORT // Uncomment to print the report send by the PS4 Controller -/** Buttons on the controller */ -const uint8_t PS4_BUTTONS[] PROGMEM = { - DPAD_UP, // UP - DPAD_RIGHT, // RIGHT - DPAD_DOWN, // DOWN - DPAD_LEFT, // LEFT - - 0x0C, // SHARE - 0x0D, // OPTIONS - 0x0E, // L3 - 0x0F, // R3 - - 0x0A, // L2 - 0x0B, // R2 - 0x08, // L1 - 0x09, // R1 - - 0x07, // TRIANGLE - 0x06, // CIRCLE - 0x05, // CROSS - 0x04, // SQUARE - - 0x10, // PS - 0x11, // TOUCHPAD -}; - -/** Analog buttons on the controller */ -const uint8_t PS4_ANALOG_BUTTONS[] PROGMEM = { - 0, 0, 0, 0, 0, 0, 0, 0, // Skip UP, RIGHT, DOWN, LEFT, SHARE, OPTIONS, L3, and R3 - 0, // L2 - 1, // R2 -}; - -bool PS4BT::checkDpad(DPADEnum b) { - switch (b) { - case DPAD_UP: - return ps4Data.btn.dpad == DPAD_LEFT_UP || ps4Data.btn.dpad == DPAD_UP || ps4Data.btn.dpad == DPAD_UP_RIGHT; - case DPAD_RIGHT: - return ps4Data.btn.dpad == DPAD_UP_RIGHT || ps4Data.btn.dpad == DPAD_RIGHT || ps4Data.btn.dpad == DPAD_RIGHT_DOWN; - case DPAD_DOWN: - return ps4Data.btn.dpad == DPAD_RIGHT_DOWN || ps4Data.btn.dpad == DPAD_DOWN || ps4Data.btn.dpad == DPAD_DOWN_LEFT; - case DPAD_LEFT: - return ps4Data.btn.dpad == DPAD_DOWN_LEFT || ps4Data.btn.dpad == DPAD_LEFT || ps4Data.btn.dpad == DPAD_LEFT_UP; - default: - return false; - } +bool PS4Parser::checkDpad(ButtonEnum b) { + switch (b) { + case UP: + return ps4Data.btn.dpad == DPAD_LEFT_UP || ps4Data.btn.dpad == DPAD_UP || ps4Data.btn.dpad == DPAD_UP_RIGHT; + case RIGHT: + return ps4Data.btn.dpad == DPAD_UP_RIGHT || ps4Data.btn.dpad == DPAD_RIGHT || ps4Data.btn.dpad == DPAD_RIGHT_DOWN; + case DOWN: + return ps4Data.btn.dpad == DPAD_RIGHT_DOWN || ps4Data.btn.dpad == DPAD_DOWN || ps4Data.btn.dpad == DPAD_DOWN_LEFT; + case LEFT: + return ps4Data.btn.dpad == DPAD_DOWN_LEFT || ps4Data.btn.dpad == DPAD_LEFT || ps4Data.btn.dpad == DPAD_LEFT_UP; + default: + return false; + } } -bool PS4BT::getButtonPress(ButtonEnum b) { - uint8_t button = pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]); +bool PS4Parser::getButtonPress(ButtonEnum b) { if (b <= LEFT) // Dpad - return checkDpad((DPADEnum)button); + return checkDpad(b); else { + uint8_t button = pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]); uint8_t index = button < 8 ? 0 : button < 16 ? 1 : 2; - uint8_t mask = (1 << (button - 8 * index)); + uint8_t mask = 1 << (button - 8 * index); return ps4Data.btn.val[index] & mask; } } -bool PS4BT::getButtonClick(ButtonEnum b) { +bool PS4Parser::getButtonClick(ButtonEnum b) { uint8_t mask, index = 0; if (b <= LEFT) // Dpad mask = 1 << b; else { uint8_t button = pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]); index = button < 8 ? 0 : button < 16 ? 1 : 2; - mask = (1 << (button - 8 * index)); + mask = 1 << (button - 8 * index); } bool click = buttonClickState.val[index] & mask; @@ -94,17 +61,21 @@ bool PS4BT::getButtonClick(ButtonEnum b) { return click; } -uint8_t PS4BT::getAnalogButton(ButtonEnum a) { - return ps4Data.trigger[pgm_read_byte(&PS4_ANALOG_BUTTONS[(uint8_t)a])]; +uint8_t PS4Parser::getAnalogButton(ButtonEnum a) { + if (a == L2) // These are the only analog buttons on the controller + return ps4Data.trigger[0]; + else if (a == R2) + return ps4Data.trigger[1]; + return 0; } -uint8_t PS4BT::getAnalogHat(AnalogHatEnum a) { +uint8_t PS4Parser::getAnalogHat(AnalogHatEnum a) { return ps4Data.hatValue[(uint8_t)a]; } -void PS4BT::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) { - if (len == sizeof(PS4Data) && buf) { - memcpy(&ps4Data, buf, len); +void PS4Parser::Parse(uint8_t len, uint8_t *buf) { + if (len > 0 && buf) { + memcpy(&ps4Data, buf, min(len, sizeof(ps4Data))); for (uint8_t i = 0; i < sizeof(ps4Data.btn); i++) { if (ps4Data.btn.val[i] != oldButtonState.val[i]) { // Check if anything has changed @@ -112,13 +83,13 @@ void PS4BT::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) { oldButtonState.val[i] = ps4Data.btn.val[i]; if (i == 0) { // The DPAD buttons does not set the different bits, but set a value corresponding to the buttons pressed, we will simply set the bits ourself uint8_t newDpad = 0; - if (checkDpad(DPAD_UP)) + if (checkDpad(UP)) newDpad |= 1 << UP; - if (checkDpad(DPAD_RIGHT)) + if (checkDpad(RIGHT)) newDpad |= 1 << RIGHT; - if (checkDpad(DPAD_DOWN)) + if (checkDpad(DOWN)) newDpad |= 1 << DOWN; - if (checkDpad(DPAD_LEFT)) + if (checkDpad(LEFT)) newDpad |= 1 << LEFT; if (newDpad != oldDpad) { buttonClickState.dpad = newDpad & ~oldDpad; // Override values diff --git a/PS4Parser.h b/PS4Parser.h new file mode 100644 index 00000000..738cf89b --- /dev/null +++ b/PS4Parser.h @@ -0,0 +1,246 @@ +/* Copyright (C) 2014 Kristian Lauszus, TKJ Electronics. All rights reserved. + + 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 + */ + +#ifndef _ps4parser_h_ +#define _ps4parser_h_ + +#include "hid.h" +#include "controllerEnums.h" + +/** Buttons on the controller */ +const uint8_t PS4_BUTTONS[] PROGMEM = { + UP, // UP + RIGHT, // RIGHT + DOWN, // DOWN + LEFT, // LEFT + + 0x0C, // SHARE + 0x0D, // OPTIONS + 0x0E, // L3 + 0x0F, // R3 + + 0x0A, // L2 + 0x0B, // R2 + 0x08, // L1 + 0x09, // R1 + + 0x07, // TRIANGLE + 0x06, // CIRCLE + 0x05, // CROSS + 0x04, // SQUARE + + 0x10, // PS + 0x11, // TOUCHPAD +}; + +union PS4Buttons { + struct { + uint8_t dpad : 4; + uint8_t square : 1; + uint8_t cross : 1; + uint8_t circle : 1; + uint8_t triangle : 1; + + uint8_t l1 : 1; + uint8_t r1 : 1; + uint8_t l2 : 1; + uint8_t r2 : 1; + uint8_t share : 1; + uint8_t options : 1; + uint8_t l3 : 1; + uint8_t r3 : 1; + + uint8_t ps : 1; + uint8_t touchpad : 1; + uint8_t timestamp : 6; // Only available via USB + }; + uint8_t val[3]; +}; + +struct touchpadXY { + uint8_t dummy; // I can not figure out what this data is for, it seems to change randomly, maybe a timestamp? + struct { + struct { + uint8_t counter : 7; // Increments every time a finger is touching the touchpad + uint8_t touching : 1; // The top bit is cleared if the finger is touching the touchpad + }; + struct { + uint16_t x : 12; + uint16_t y : 12; + }; + } finger[2]; // 0 = first finger, 1 = second finger +}; + +struct PS4Data { + /* Button and joystick values */ + uint8_t report_id; // Always 0x01 + uint8_t hatValue[4]; + PS4Buttons btn; + uint8_t trigger[2]; + + // I still need to figure out how to make the PS4 controller send out the rest of the data via Bluetooth + + /* Gyro and accelerometer values */ + uint8_t dummy[3]; // First two looks random, while the third one might be some kind of status + int16_t gyroY, gyroZ, gyroX; + int16_t accX, accZ, accY; + + /* The rest is data for the touchpad */ + uint8_t dummy2[9]; // Byte 5 looks like some kind of status (maybe battery status), bit 1 of byte 9 is set every time a finger is moving around the touchpad + touchpadXY xy[3]; // It looks like it sends out three coordinates each time, this is possible because the microcontroller inside the PS4 controller is much faster than the Bluetooth connection. + // The last data is read from the last position in the array while the oldest measurement is from the first position. + // The first position will also keep it's value after the finger is released, while the other two will set them to zero. + // Note that if you read fast enough from the device, then only the first one will contain any data. + + // The last three bytes are always: 0x00, 0x80, 0x00 +}; + +enum DPADEnum { + DPAD_UP = 0x0, + DPAD_UP_RIGHT = 0x1, + DPAD_RIGHT = 0x2, + DPAD_RIGHT_DOWN = 0x3, + DPAD_DOWN = 0x4, + DPAD_DOWN_LEFT = 0x5, + DPAD_LEFT = 0x6, + DPAD_LEFT_UP = 0x7, + DPAD_OFF = 0x8, +}; + +enum PS4SensorEnum { + gX, gY, gZ, /** Gyro values */ + aX, aY, aZ, /** Accelerometer values */ +}; + +/** This class parses all the data sent by the PS4 controller */ +class PS4Parser { +public: + /** Constructor for the PS4Parser class. */ + PS4Parser() { + Reset(); + }; + + /** @name PS4 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 getButtonPress(ButtonEnum b) will return a true as long as a button is held down, while getButtonClick(ButtonEnum b) will return true once for each button press. + */ + bool getButtonPress(ButtonEnum b); + bool getButtonClick(ButtonEnum b); + /**@}*/ + /** @name PS4 Controller functions */ + /** + * Used to get the analog value from button presses. + * @param a The ::ButtonEnum to read. + * The supported buttons are: + * ::UP, ::RIGHT, ::DOWN, ::LEFT, ::L1, ::L2, ::R1, ::R2, + * ::TRIANGLE, ::CIRCLE, ::CROSS, ::SQUARE, and ::T. + * @return Analog value in the range of 0-255. + */ + uint8_t getAnalogButton(ButtonEnum a); + + /** + * Used to read the analog joystick. + * @param a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY. + * @return Return the analog value in the range of 0-255. + */ + uint8_t getAnalogHat(AnalogHatEnum a); + /**@}*/ + + /** @name Only available via USB at the moment */ + uint16_t getX(uint8_t finger = 0, uint8_t xyId = 0) { + return ps4Data.xy[xyId].finger[finger].x; + }; + + uint16_t getY(uint8_t finger = 0, uint8_t xyId = 0) { + return ps4Data.xy[xyId].finger[finger].y; + }; + + uint8_t isTouching(uint8_t finger = 0, uint8_t xyId = 0) { + return !(ps4Data.xy[xyId].finger[finger].touching); // The bit is cleared every time when a finger is touching the touchpad + }; + + uint8_t getTouchCounter(uint8_t finger = 0, uint8_t xyId = 0) { + return ps4Data.xy[xyId].finger[finger].counter; + }; + + double getAngle(AngleEnum a) { + if(a == Pitch) + return (atan2(ps4Data.accY, ps4Data.accZ) + PI) * RAD_TO_DEG; + else + return (atan2(ps4Data.accX, ps4Data.accZ) + PI) * RAD_TO_DEG; + }; + + int16_t getSensor(PS4SensorEnum a) { + switch(a) { + case gX: + return ps4Data.gyroX; + case gY: + return ps4Data.gyroY; + case gZ: + return ps4Data.gyroZ; + case aX: + return ps4Data.accX; + case aY: + return ps4Data.accY; + case aZ: + return ps4Data.accZ; + default: + return 0; + } + }; + /**@}*/ + + /** Used to reset the different buffers to their default values */ + void Reset() { + uint8_t i; + for (i = 0; i < sizeof(ps4Data.hatValue); i++) + ps4Data.hatValue[i] = 127; + for (i = 0; i < sizeof(PS4Buttons); i++) { + ps4Data.btn.val[i] = 0; + oldButtonState.val[i] = 0; + } + for (i = 0; i < sizeof(ps4Data.trigger); i++) + ps4Data.trigger[i] = 0; + for (i = 0; i < sizeof(ps4Data.xy)/sizeof(ps4Data.xy[0]); i++) { + for (uint8_t j = 0; j < sizeof(ps4Data.xy[0].finger)/sizeof(ps4Data.xy[0].finger[0]); j++) + ps4Data.xy[i].finger[j].touching = 1; // The bit is cleared if the finger is touching the touchpad + } + + ps4Data.btn.dpad = DPAD_OFF; + oldButtonState.dpad = DPAD_OFF; + buttonClickState.dpad = 0; + oldDpad = 0; + }; + +protected: + void Parse(uint8_t len, uint8_t *buf); + +private: + bool checkDpad(ButtonEnum b); // Used to check PS4 DPAD buttons + + PS4Data ps4Data; + PS4Buttons oldButtonState, buttonClickState; + uint8_t oldDpad; +}; +#endif \ No newline at end of file diff --git a/PS4USB.h b/PS4USB.h new file mode 100644 index 00000000..a009071c --- /dev/null +++ b/PS4USB.h @@ -0,0 +1,87 @@ +/* Copyright (C) 2014 Kristian Lauszus, TKJ Electronics. All rights reserved. + + 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 + */ + +#ifndef _ps4usb_h_ +#define _ps4usb_h_ + +#include "hiduniversal.h" +#include "PS4Parser.h" + +#define PS4_VID 0x054C // Sony Corporation +#define PS4_PID 0x05C4 // PS4 Controller + +/** + * This class implements support for the PS4 controller via USB. + * It uses the HIDUniversal class for all the USB communication. + */ +class PS4USB : public HIDUniversal, public PS4Parser { +public: + /** + * Constructor for the PS4USB class. + * @param p Pointer to the HIDUniversal class instance. + */ + PS4USB(USB *p) : + HIDUniversal(p) { + PS4Parser::Reset(); + }; + + /** @name HIDUniversal implementation */ + /** + * Used to parse USB HID data. + * @param hid Pointer to the HID class. + * @param is_rpt_id Only used for Hubs. + * @param len The length of the incoming data. + * @param buf Pointer to the data buffer. + */ + virtual void ParseHIDData(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) { + if (HIDUniversal::VID == PS4_VID && HIDUniversal::PID == PS4_PID) + PS4Parser::Parse(len, buf); + }; + + /** + * Called when a device is successfully initialized. + * Use attachOnInit(void (*funcOnInit)(void)) to call your own function. + * This is useful for instance if you want to set the LEDs in a specific way. + */ + virtual uint8_t OnInitSuccessful() { + PS4Parser::Reset(); + if (HIDUniversal::VID == PS4_VID && HIDUniversal::PID == PS4_PID && pFuncOnInit) + pFuncOnInit(); // Call the user function + return 0; + }; + /**@}*/ + + /** + * Used to check if a PS4 controller is connected. + * @return Returns true if it is connected. + */ + bool connected() { + return HIDUniversal::isReady() && HIDUniversal::VID == PS4_VID && HIDUniversal::PID == PS4_PID; + }; + + /** + * Used to call your own function when the device is successfully initialized. + * @param funcOnInit Function to call. + */ + void attachOnInit(void (*funcOnInit)(void)) { + pFuncOnInit = funcOnInit; + }; + +private: + void (*pFuncOnInit)(void); // Pointer to function called in onInit() +}; +#endif \ No newline at end of file diff --git a/README.md b/README.md index 157e84f4..ab7e2b2a 100644 --- a/README.md +++ b/README.md @@ -116,15 +116,17 @@ It enables me to see the Bluetooth communication between my Mac and any device. ### PS4 Library -This is the [PS4BT](PS4BT.cpp) library. It works with the official Sony PS4 controller via Bluetooth. +The PS4BT library is split up into the [PS4BT](PS4BT.h) and the [PS4USB](PS4USB.h) library. These allow you to use the Sony PS4 controller via Bluetooth and USB. -The [PS4BT.ino](examples/Bluetooth/PS4BT/PS4BT.ino) example shows how to easily read the buttons and joysticks on the controller. +The [PS4BT.ino](examples/Bluetooth/PS4BT/PS4BT.ino) and [PS4USB.ino](examples/PS4USB/PS4USB.ino) examples shows how to easily read the buttons and joysticks on the controller via Bluetooth and USB respectively. -I still have not figured out how to read the touchpad, turn rumble on and off and set the color of the light, but hopefully I will figure that out soon. +I still have not figured out how to turn rumble on and off and set the color of the light, but hopefully I will figure that out soon. -Before you can use the PS4 controller you will need to pair with it. +Also the gyro, accelerometer and touchpad values are still only available via USB at the moment. -Simply create the BTHID instance like so: ```BTHID bthid(&Btd, PAIR);``` and then hold down the PS and Share button at the same time, the PS4 controller will then start to blink rapidly indicating that it is in paring mode. +Before you can use the PS4 controller via Bluetooth you will need to pair with it. + +Simply create the PS4BT instance like so: ```PS4BT PS4(&Btd, PAIR);``` and then hold down the PS and Share button at the same time, the PS4 controller will then start to blink rapidly indicating that it is in paring mode. It should then automatically pair the dongle with your controller. This only have to be done once. diff --git a/controllerEnums.h b/controllerEnums.h index 2cc0b789..155588f2 100644 --- a/controllerEnums.h +++ b/controllerEnums.h @@ -124,4 +124,10 @@ enum AnalogHatEnum { RightHatY = 3, }; +/** Used to get the angle calculated using the PS3 controller and PS4 controller. */ +enum AngleEnum { + Pitch = 0x01, + Roll = 0x02, +}; + #endif diff --git a/examples/Bluetooth/PS4BT/PS4BT.ino b/examples/Bluetooth/PS4BT/PS4BT.ino index bf068876..924cdc1d 100644 --- a/examples/Bluetooth/PS4BT/PS4BT.ino +++ b/examples/Bluetooth/PS4BT/PS4BT.ino @@ -16,15 +16,13 @@ USB Usb; //USBHub Hub1(&Usb); // Some dongles have a hub inside BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so -/* You can create the instance of the BTHID class in two ways */ +/* You can create the instance of the PS4BT class in two ways */ // This will start an inquiry and then pair with the PS4 controller - you only have to do this once // You will need to hold down the PS and Share button at the same time, the PS4 controller will then start to blink rapidly indicating that it is in paring mode -BTHID bthid(&Btd, PAIR); +PS4BT PS4(&Btd, PAIR); // After that you can simply create the instance like so and then press the PS button on the device -//BTHID bthid(&Btd); - -PS4BT PS4(&bthid); // You should not modify this instance +//PS4BT PS4(&Btd); void setup() { Serial.begin(115200); diff --git a/examples/PS4USB/PS4USB.ino b/examples/PS4USB/PS4USB.ino new file mode 100644 index 00000000..95a0e586 --- /dev/null +++ b/examples/PS4USB/PS4USB.ino @@ -0,0 +1,107 @@ +/* + Example sketch for the PS4 USB library - developed by Kristian Lauszus + For more information visit my blog: http://blog.tkjelectronics.dk/ or + send me an e-mail: kristianl@tkjelectronics.com + */ + +#include + +USB Usb; +PS4USB PS4(&Usb); + +boolean printAngle, printTouch; + +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\nPS4 USB Library Started")); +} + +void loop() { + Usb.Task(); + + if (PS4.connected()) { + if (PS4.getAnalogHat(LeftHatX) > 137 || PS4.getAnalogHat(LeftHatX) < 117 || PS4.getAnalogHat(LeftHatY) > 137 || PS4.getAnalogHat(LeftHatY) < 117 || PS4.getAnalogHat(RightHatX) > 137 || PS4.getAnalogHat(RightHatX) < 117 || PS4.getAnalogHat(RightHatY) > 137 || PS4.getAnalogHat(RightHatY) < 117) { + Serial.print(F("\r\nLeftHatX: ")); + Serial.print(PS4.getAnalogHat(LeftHatX)); + Serial.print(F("\tLeftHatY: ")); + Serial.print(PS4.getAnalogHat(LeftHatY)); + Serial.print(F("\tRightHatX: ")); + Serial.print(PS4.getAnalogHat(RightHatX)); + Serial.print(F("\tRightHatY: ")); + Serial.print(PS4.getAnalogHat(RightHatY)); + } + + if (PS4.getAnalogButton(L2) || PS4.getAnalogButton(R2)) { // These are the only analog buttons on the PS4 controller + Serial.print(F("\r\nL2: ")); + Serial.print(PS4.getAnalogButton(L2)); + Serial.print(F("\tR2: ")); + Serial.print(PS4.getAnalogButton(R2)); + } + + if (PS4.getButtonClick(PS)) + Serial.print(F("\r\nPS")); + if (PS4.getButtonClick(TRIANGLE)) + Serial.print(F("\r\nTraingle")); + if (PS4.getButtonClick(CIRCLE)) + Serial.print(F("\r\nCircle")); + if (PS4.getButtonClick(CROSS)) + Serial.print(F("\r\nCross")); + if (PS4.getButtonClick(SQUARE)) + Serial.print(F("\r\nSquare")); + + if (PS4.getButtonClick(UP)) + Serial.print(F("\r\nUp")); + if (PS4.getButtonClick(RIGHT)) + Serial.print(F("\r\nRight")); + if (PS4.getButtonClick(DOWN)) + Serial.print(F("\r\nDown")); + if (PS4.getButtonClick(LEFT)) + Serial.print(F("\r\nLeft")); + + if (PS4.getButtonClick(L1)) + Serial.print(F("\r\nL1")); + if (PS4.getButtonClick(L3)) + Serial.print(F("\r\nL3")); + if (PS4.getButtonClick(R1)) + Serial.print(F("\r\nR1")); + if (PS4.getButtonClick(R3)) + Serial.print(F("\r\nR3")); + + if (PS4.getButtonClick(SHARE)) + Serial.print(F("\r\nShare")); + if (PS4.getButtonClick(OPTIONS)) { + Serial.print(F("\r\nOptions")); + printAngle = !printAngle; + } + if (PS4.getButtonClick(TOUCHPAD)) { + Serial.print(F("\r\nTouchpad")); + printTouch = !printTouch; + } + + if (printAngle) { // Print angle calculated using the accelerometer only + Serial.print(F("\r\nPitch: ")); + Serial.print(PS4.getAngle(Pitch)); + Serial.print(F("\tRoll: ")); + Serial.print(PS4.getAngle(Roll)); + } + + if (printTouch) { // Print the x, y coordinates of the touchpad + if (PS4.isTouching(0) || PS4.isTouching(1)) // Print newline and carriage return if any of the fingers are touching the touchpad + Serial.print(F("\r\n")); + for (uint8_t i = 0; i < 2; i++) { // The touchpad track two fingers + if (PS4.isTouching(i)) { // Print the position of the finger if it is touching the touchpad + Serial.print(F("X")); Serial.print(i + 1); Serial.print(F(": ")); + Serial.print(PS4.getX(i)); + Serial.print(F("\tY")); Serial.print(i + 1); Serial.print(F(": ")); + Serial.print(PS4.getY(i)); + Serial.print(F("\t")); + } + } + } + } +} diff --git a/hiduniversal.cpp b/hiduniversal.cpp index fb19683f..4e866cb2 100644 --- a/hiduniversal.cpp +++ b/hiduniversal.cpp @@ -3,6 +3,7 @@ HIDUniversal::HIDUniversal(USB *p) : HID(p), qNextPollTime(0), +pollInterval(0), bPollEnable(false), bHasReportId(false) { Initialize(); @@ -47,6 +48,7 @@ void HIDUniversal::Initialize() { bNumEP = 1; bNumIface = 0; bConfNum = 0; + pollInterval = 0; ZeroMemory(constBuffLen, prevBuf); } @@ -167,6 +169,9 @@ uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) { if(rcode) goto FailGetDevDescr; + VID = udd->idVendor; // Can be used by classes that inherits this class to check the VID and PID of the connected device + PID = udd->idProduct; + num_of_conf = udd->bNumConfigurations; // Assign epInfo to epinfo pointer @@ -198,7 +203,7 @@ uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) { // Assign epInfo to epinfo pointer rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); - USBTRACE2("\r\nCnf:", bConfNum); + USBTRACE2("Cnf:", bConfNum); // Set Configuration Value rcode = pUsb->setConf(bAddress, 0, bConfNum); @@ -307,6 +312,9 @@ void HIDUniversal::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint // Fill in the endpoint index list piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F); + if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints + pollInterval = pep->bInterval; + bNumEP++; } //PrintEndpointDescriptor(pep); @@ -346,7 +354,7 @@ uint8_t HIDUniversal::Poll() { return 0; if(qNextPollTime <= millis()) { - qNextPollTime = millis() + 50; + qNextPollTime = millis() + pollInterval; uint8_t buf[constBuffLen]; @@ -381,6 +389,8 @@ uint8_t HIDUniversal::Poll() { Notify(PSTR("\r\n"), 0x80); + ParseHIDData(this, bHasReportId, (uint8_t)read, buf); + HIDReportParser *prs = GetReportParser(((bHasReportId) ? *buf : 0)); if(prs) diff --git a/hiduniversal.h b/hiduniversal.h index 0f6729e7..bfd1173b 100644 --- a/hiduniversal.h +++ b/hiduniversal.h @@ -35,6 +35,7 @@ class HIDUniversal : public HID { uint8_t bNumIface; // number of interfaces in the configuration uint8_t bNumEP; // total number of EP in the configuration uint32_t qNextPollTime; // next poll time + uint8_t pollInterval; bool bPollEnable; // poll enable flag static const uint16_t constBuffLen = 64; // event buffer length @@ -50,6 +51,8 @@ class HIDUniversal : public HID { protected: bool bHasReportId; + uint16_t PID, VID; // PID and VID of connected device + // HID implementation virtual HIDReportParser* GetReportParser(uint8_t id); @@ -57,6 +60,10 @@ protected: return 0; }; + virtual void ParseHIDData(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) { + return; + }; + public: HIDUniversal(USB *p); @@ -72,6 +79,10 @@ public: return bAddress; }; + virtual bool isReady() { + return bPollEnable; + }; + // UsbConfigXtracter implementation virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); }; diff --git a/keywords.txt b/keywords.txt index a60fe5d8..786d4fa2 100644 --- a/keywords.txt +++ b/keywords.txt @@ -32,9 +32,10 @@ Task KEYWORD2 # Datatypes (KEYWORD1) #################################################### -PS4BT KEYWORD1 PS3BT KEYWORD1 PS3USB KEYWORD1 +PS4BT KEYWORD1 +PS4USB KEYWORD1 #################################################### # Methods and Functions (KEYWORD2) @@ -75,6 +76,11 @@ PS3NavigationConnected KEYWORD2 isReady KEYWORD2 watingForConnection KEYWORD2 +isTouching KEYWORD2 +getX KEYWORD2 +getY KEYWORD2 +getTouchCounter KEYWORD2 + #################################################### # Constants and enums (LITERAL1) #################################################### @@ -131,6 +137,8 @@ RightHatY LITERAL1 aX LITERAL1 aY LITERAL1 aZ LITERAL1 +gX LITERAL1 +gY LITERAL1 gZ LITERAL1 aXmove LITERAL1 aYmove LITERAL1 From 681c6684483738f1e40074e143a282418a298eaa Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sat, 18 Jan 2014 22:50:05 +0100 Subject: [PATCH 13/42] Fixed conflict between PS3 and PS4 libraries --- PS3Enums.h | 46 ++-------------------------------------------- PS4Parser.h | 9 ++------- controllerEnums.h | 42 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 43 insertions(+), 54 deletions(-) diff --git a/PS3Enums.h b/PS3Enums.h index dca5bebe..7ee84293 100644 --- a/PS3Enums.h +++ b/PS3Enums.h @@ -56,8 +56,7 @@ const uint8_t PS3_LEDS[] PROGMEM = { }; /** - * Buttons on the controllers - * + * Buttons on the controllers. * Note: that the location is shifted 9 when it's connected via USB. */ const uint32_t PS3_BUTTONS[] PROGMEM = { @@ -87,8 +86,7 @@ const uint32_t PS3_BUTTONS[] PROGMEM = { }; /** - * Analog buttons on the controllers - * + * Analog buttons on the controllers. * Note: that the location is shifted 9 when it's connected via USB. */ const uint8_t PS3_ANALOG_BUTTONS[] PROGMEM = { @@ -134,46 +132,6 @@ enum ColorsEnum { Off = 0x00, }; -/** - * Sensors inside the Sixaxis Dualshock 3 and Move controller. - * - * Note: that the location is shifted 9 when it's connected via USB. - */ -enum SensorEnum { - /** Accelerometer x-axis */ - aX = 50, - /** Accelerometer y-axis */ - aY = 52, - /** Accelerometer z-axis */ - aZ = 54, - /** Gyro z-axis */ - gZ = 56, - - /** Accelerometer x-axis */ - aXmove = 28, - /** Accelerometer z-axis */ - aZmove = 30, - /** Accelerometer y-axis */ - aYmove = 32, - - /** Gyro x-axis */ - gXmove = 40, - /** Gyro z-axis */ - gZmove = 42, - /** Gyro y-axis */ - gYmove = 44, - - /** Temperature sensor */ - tempMove = 46, - - /** Magnetometer x-axis */ - mXmove = 47, - /** Magnetometer z-axis */ - mZmove = 49, - /** Magnetometer y-axis */ - mYmove = 50, -}; - enum StatusEnum { // Note that the location is shifted 9 when it's connected via USB // Byte location | bit location diff --git a/PS4Parser.h b/PS4Parser.h index 738cf89b..d3e28f88 100644 --- a/PS4Parser.h +++ b/PS4Parser.h @@ -121,11 +121,6 @@ enum DPADEnum { DPAD_OFF = 0x8, }; -enum PS4SensorEnum { - gX, gY, gZ, /** Gyro values */ - aX, aY, aZ, /** Accelerometer values */ -}; - /** This class parses all the data sent by the PS4 controller */ class PS4Parser { public: @@ -191,8 +186,8 @@ public: return (atan2(ps4Data.accX, ps4Data.accZ) + PI) * RAD_TO_DEG; }; - int16_t getSensor(PS4SensorEnum a) { - switch(a) { + int16_t getSensor(SensorEnum s) { + switch(s) { case gX: return ps4Data.gyroX; case gY: diff --git a/controllerEnums.h b/controllerEnums.h index 155588f2..0eae781d 100644 --- a/controllerEnums.h +++ b/controllerEnums.h @@ -18,9 +18,9 @@ #ifndef _controllerenums_h #define _controllerenums_h -/* - This header file is used to store different enums for the controllers, - This is necessary so all the different libraries can be used at once +/** + * This header file is used to store different enums for the controllers, + * This is necessary so all the different libraries can be used at once. */ /** Enum used to turn on the LEDs on the different controllers. */ @@ -124,6 +124,42 @@ enum AnalogHatEnum { RightHatY = 3, }; +/** + * Sensors inside the Sixaxis Dualshock 3, Move controller and PS4 controller. + * Note: that the location is shifted 9 when it's connected via USB on the PS3 controller. + */ +enum SensorEnum { + /** Accelerometer values */ + aX = 50, aY = 52, aZ = 54, + /** Gyro z-axis */ + gZ = 56, + gX, gY, // These are not available on the PS3 controller + + /** Accelerometer x-axis */ + aXmove = 28, + /** Accelerometer z-axis */ + aZmove = 30, + /** Accelerometer y-axis */ + aYmove = 32, + + /** Gyro x-axis */ + gXmove = 40, + /** Gyro z-axis */ + gZmove = 42, + /** Gyro y-axis */ + gYmove = 44, + + /** Temperature sensor */ + tempMove = 46, + + /** Magnetometer x-axis */ + mXmove = 47, + /** Magnetometer z-axis */ + mZmove = 49, + /** Magnetometer y-axis */ + mYmove = 50, +}; + /** Used to get the angle calculated using the PS3 controller and PS4 controller. */ enum AngleEnum { Pitch = 0x01, From ad7078d6adacb8d0edf2f521ed53d152d21d5c57 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sat, 18 Jan 2014 23:51:20 +0100 Subject: [PATCH 14/42] Forgot return in connected() --- PS4BT.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PS4BT.h b/PS4BT.h index a723cec8..842adbac 100644 --- a/PS4BT.h +++ b/PS4BT.h @@ -65,7 +65,7 @@ public: /** True if a device is connected */ bool connected() { - BTHID::connected; + return BTHID::connected; }; /** From 06b859bb7fb7890bc96654fd7cc476d440df37d1 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 19 Jan 2014 00:11:48 +0100 Subject: [PATCH 15/42] Added links to blog posts --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index ab7e2b2a..4bda8002 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,8 @@ It uses the standard Boot protocol by default, but it is also able to use the Re The [PS4 library](#ps4-library) also uses this class to handle all Bluetooth communication. +For information see the following blog post: . + ### [SPP library](SPP.cpp) SPP stands for "Serial Port Profile" and is a Bluetooth protocol that implements a virtual comport which allows you to send data back and forth from your computer/phone to your Arduino via Bluetooth. @@ -130,6 +132,8 @@ Simply create the PS4BT instance like so: ```PS4BT PS4(&Btd, PAIR);``` and then It should then automatically pair the dongle with your controller. This only have to be done once. +For information see the following blog post: . + ### PS3 Library These libraries consist of the [PS3BT](PS3BT.cpp) and [PS3USB](PS3USB.cpp). These libraries allows you to use a Dualshock 3, Navigation or a Motion controller with the USB Host Shield both via Bluetooth and USB. From e781d6c554341fa0860dc9dfedc408ff7539c912 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 19 Jan 2014 16:58:29 +0100 Subject: [PATCH 16/42] Updated some comments and some other minor things --- BTHID.h | 2 +- PS4BT.h | 32 +++++++++++++----------- PS4Parser.cpp | 27 +++++++++++++-------- PS4Parser.h | 67 +++++++++++++++++++++++++++++++++++++++++++-------- PS4USB.h | 35 ++++++++++++++------------- 5 files changed, 111 insertions(+), 52 deletions(-) diff --git a/BTHID.h b/BTHID.h index 0dcd6a1e..07fd400d 100644 --- a/BTHID.h +++ b/BTHID.h @@ -25,7 +25,7 @@ #define MOUSE_PARSER_ID 1 #define NUM_PARSERS 2 -/** This BluetoothService class implements support for the HID keyboard and mice. */ +/** This BluetoothService class implements support for Bluetooth HID devices. */ class BTHID : public BluetoothService { public: /** diff --git a/PS4BT.h b/PS4BT.h index 842adbac..4183d2c0 100644 --- a/PS4BT.h +++ b/PS4BT.h @@ -29,13 +29,30 @@ class PS4BT : public BTHID, public PS4Parser { public: /** * Constructor for the PS4BT class. - * @param p Pointer to the BTHID class instance. + * @param p Pointer to the BTD class instance. */ PS4BT(BTD *p, bool pair = false, const char *pin = "0000") : BTHID(p, pair, pin) { PS4Parser::Reset(); }; + /** + * Used to check if a PS4 controller is connected. + * @return Returns true if it is connected. + */ + bool connected() { + return BTHID::connected; + }; + + /** + * Used to call your own function when the device is successfully initialized. + * @param funcOnInit Function to call. + */ + void attachOnInit(void (*funcOnInit)(void)) { + pFuncOnInit = funcOnInit; + }; + +protected: /** @name BTHID implementation */ /** * Used to parse Bluetooth HID data. @@ -63,19 +80,6 @@ public: }; /**@}*/ - /** True if a device is connected */ - bool connected() { - return BTHID::connected; - }; - - /** - * Used to call your own function when the device is successfully initialized. - * @param funcOnInit Function to call. - */ - void attachOnInit(void (*funcOnInit)(void)) { - pFuncOnInit = funcOnInit; - }; - private: void (*pFuncOnInit)(void); // Pointer to function called in onInit() }; diff --git a/PS4Parser.cpp b/PS4Parser.cpp index 16c1ee3d..01624581 100644 --- a/PS4Parser.cpp +++ b/PS4Parser.cpp @@ -61,10 +61,10 @@ bool PS4Parser::getButtonClick(ButtonEnum b) { return click; } -uint8_t PS4Parser::getAnalogButton(ButtonEnum a) { - if (a == L2) // These are the only analog buttons on the controller +uint8_t PS4Parser::getAnalogButton(ButtonEnum b) { + if (b == L2) // These are the only analog buttons on the controller return ps4Data.trigger[0]; - else if (a == R2) + else if (b == R2) return ps4Data.trigger[1]; return 0; } @@ -75,7 +75,21 @@ uint8_t PS4Parser::getAnalogHat(AnalogHatEnum a) { void PS4Parser::Parse(uint8_t len, uint8_t *buf) { if (len > 0 && buf) { +#ifdef PRINTREPORT + for (uint8_t i = 0; i < len; i++) { + D_PrintHex (buf[i], 0x80); + Notify(PSTR(" "), 0x80); + } + Notify(PSTR("\r\n"), 0x80); +#endif + memcpy(&ps4Data, buf, min(len, sizeof(ps4Data))); + if (ps4Data.reportId != 0x01) { +#ifdef DEBUG_USB_HOST + Notify(PSTR("\r\nUnknown report id"), 0x80); +#endif + return; + } for (uint8_t i = 0; i < sizeof(ps4Data.btn); i++) { if (ps4Data.btn.val[i] != oldButtonState.val[i]) { // Check if anything has changed @@ -98,12 +112,5 @@ void PS4Parser::Parse(uint8_t len, uint8_t *buf) { } } } -#ifdef PRINTREPORT - for (uint8_t i = 0; i < len; i++) { - D_PrintHex (buf[i], 0x80); - Notify(PSTR(" "), 0x80); - } - Notify(PSTR("\r\n"), 0x80); -#endif } } \ No newline at end of file diff --git a/PS4Parser.h b/PS4Parser.h index d3e28f88..26f83576 100644 --- a/PS4Parser.h +++ b/PS4Parser.h @@ -18,7 +18,7 @@ #ifndef _ps4parser_h_ #define _ps4parser_h_ -#include "hid.h" +#include "Usb.h" #include "controllerEnums.h" /** Buttons on the controller */ @@ -87,7 +87,7 @@ struct touchpadXY { struct PS4Data { /* Button and joystick values */ - uint8_t report_id; // Always 0x01 + uint8_t reportId; // Always 0x01 uint8_t hatValue[4]; PS4Buttons btn; uint8_t trigger[2]; @@ -95,12 +95,12 @@ struct PS4Data { // I still need to figure out how to make the PS4 controller send out the rest of the data via Bluetooth /* Gyro and accelerometer values */ - uint8_t dummy[3]; // First two looks random, while the third one might be some kind of status + uint8_t dummy[3]; // First two looks random, while the third one might be some kind of status - it increments once in a while int16_t gyroY, gyroZ, gyroX; int16_t accX, accZ, accY; /* The rest is data for the touchpad */ - uint8_t dummy2[9]; // Byte 5 looks like some kind of status (maybe battery status), bit 1 of byte 9 is set every time a finger is moving around the touchpad + uint8_t dummy2[9]; // Byte 5 looks like some kind of status (maybe battery status), bit 1 of byte 8 is set every time a finger is moving around the touchpad touchpadXY xy[3]; // It looks like it sends out three coordinates each time, this is possible because the microcontroller inside the PS4 controller is much faster than the Bluetooth connection. // The last data is read from the last position in the array while the oldest measurement is from the first position. // The first position will also keep it's value after the finger is released, while the other two will set them to zero. @@ -152,7 +152,7 @@ public: * ::TRIANGLE, ::CIRCLE, ::CROSS, ::SQUARE, and ::T. * @return Analog value in the range of 0-255. */ - uint8_t getAnalogButton(ButtonEnum a); + uint8_t getAnalogButton(ButtonEnum b); /** * Used to read the analog joystick. @@ -163,22 +163,59 @@ public: /**@}*/ /** @name Only available via USB at the moment */ + /** + * Get the x-coordinate of the touchpad. Position 0 is in the top left. + * @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used. + * @param xyId The controller sends out three packets with the same structure. + * The third one will contain the last measure, but if you read from the controller then there is only be data in the first one. + * For that reason it will be set to 0 if the argument is omitted. + * @return Returns the x-coordinate of the finger. + */ uint16_t getX(uint8_t finger = 0, uint8_t xyId = 0) { return ps4Data.xy[xyId].finger[finger].x; }; + /** + * Get the y-coordinate of the touchpad. Position 0 is in the top left. + * @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used. + * @param xyId The controller sends out three packets with the same structure. + * The third one will contain the last measure, but if you read from the controller then there is only be data in the first one. + * For that reason it will be set to 0 if the argument is omitted. + * @return Returns the y-coordinate of the finger. + */ uint16_t getY(uint8_t finger = 0, uint8_t xyId = 0) { return ps4Data.xy[xyId].finger[finger].y; }; - uint8_t isTouching(uint8_t finger = 0, uint8_t xyId = 0) { - return !(ps4Data.xy[xyId].finger[finger].touching); // The bit is cleared every time when a finger is touching the touchpad + /** + * Returns whenever the user is toucing the touchpad. + * @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used. + * @param xyId The controller sends out three packets with the same structure. + * The third one will contain the last measure, but if you read from the controller then there is only be data in the first one. + * For that reason it will be set to 0 if the argument is omitted. + * @return Returns true if the specific finger is touching the touchpad. + */ + bool isTouching(uint8_t finger = 0, uint8_t xyId = 0) { + return !(ps4Data.xy[xyId].finger[finger].touching); // The bit is cleared when a finger is touching the touchpad }; + /** + * This counter increments every time a finger touches the touchpad. + * @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used. + * @param xyId The controller sends out three packets with the same structure. + * The third one will contain the last measure, but if you read from the controller then there is only be data in the first one. + * For that reason it will be set to 0 if the argument is omitted. + * @return Return the value of the counter, note that it is only a 7-bit value. + */ uint8_t getTouchCounter(uint8_t finger = 0, uint8_t xyId = 0) { return ps4Data.xy[xyId].finger[finger].counter; }; + /** + * Get the angle of the controller calculated using the accelerometer. + * @param a Either ::Pitch or ::Roll. + * @return Return the angle in the range of 0-360. + */ double getAngle(AngleEnum a) { if(a == Pitch) return (atan2(ps4Data.accY, ps4Data.accZ) + PI) * RAD_TO_DEG; @@ -186,6 +223,11 @@ public: return (atan2(ps4Data.accX, ps4Data.accZ) + PI) * RAD_TO_DEG; }; + /** + * Used to get the raw values from the 3-axis gyroscope and 3-axis accelerometer inside the PS4 controller. + * @param s The sensor to read. + * @return Returns the raw sensor reading. + */ int16_t getSensor(SensorEnum s) { switch(s) { case gX: @@ -206,6 +248,14 @@ public: }; /**@}*/ +protected: + /** + * Used to parse data sent from the PS4 controller. + * @param len Length of the data. + * @param buf Pointer to the data buffer. + */ + void Parse(uint8_t len, uint8_t *buf); + /** Used to reset the different buffers to their default values */ void Reset() { uint8_t i; @@ -228,9 +278,6 @@ public: oldDpad = 0; }; -protected: - void Parse(uint8_t len, uint8_t *buf); - private: bool checkDpad(ButtonEnum b); // Used to check PS4 DPAD buttons diff --git a/PS4USB.h b/PS4USB.h index a009071c..1ea2a421 100644 --- a/PS4USB.h +++ b/PS4USB.h @@ -32,13 +32,30 @@ class PS4USB : public HIDUniversal, public PS4Parser { public: /** * Constructor for the PS4USB class. - * @param p Pointer to the HIDUniversal class instance. + * @param p Pointer to the USB class instance. */ PS4USB(USB *p) : HIDUniversal(p) { PS4Parser::Reset(); }; + /** + * Used to check if a PS4 controller is connected. + * @return Returns true if it is connected. + */ + bool connected() { + return HIDUniversal::isReady() && HIDUniversal::VID == PS4_VID && HIDUniversal::PID == PS4_PID; + }; + + /** + * Used to call your own function when the device is successfully initialized. + * @param funcOnInit Function to call. + */ + void attachOnInit(void (*funcOnInit)(void)) { + pFuncOnInit = funcOnInit; + }; + +protected: /** @name HIDUniversal implementation */ /** * Used to parse USB HID data. @@ -65,22 +82,6 @@ public: }; /**@}*/ - /** - * Used to check if a PS4 controller is connected. - * @return Returns true if it is connected. - */ - bool connected() { - return HIDUniversal::isReady() && HIDUniversal::VID == PS4_VID && HIDUniversal::PID == PS4_PID; - }; - - /** - * Used to call your own function when the device is successfully initialized. - * @param funcOnInit Function to call. - */ - void attachOnInit(void (*funcOnInit)(void)) { - pFuncOnInit = funcOnInit; - }; - private: void (*pFuncOnInit)(void); // Pointer to function called in onInit() }; From e2bf041286184b6ae2955a87674055a7ca238d95 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 19 Jan 2014 17:14:09 +0100 Subject: [PATCH 17/42] Updated some more comments --- PS4BT.h | 4 +++- PS4Parser.h | 2 +- Wii.h | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/PS4BT.h b/PS4BT.h index 4183d2c0..86b0ac47 100644 --- a/PS4BT.h +++ b/PS4BT.h @@ -29,7 +29,9 @@ class PS4BT : public BTHID, public PS4Parser { public: /** * Constructor for the PS4BT class. - * @param p Pointer to the BTD class instance. + * @param p Pointer to the BTD class instance. + * @param pair Set this to true in order to pair with the device. If the argument is omitted then it will not pair with it. One can use ::PAIR to set it to true. + * @param pin Write the pin to BTD#btdPin. If argument is omitted, then "0000" will be used. */ PS4BT(BTD *p, bool pair = false, const char *pin = "0000") : BTHID(p, pair, pin) { diff --git a/PS4Parser.h b/PS4Parser.h index 26f83576..ddd23161 100644 --- a/PS4Parser.h +++ b/PS4Parser.h @@ -146,7 +146,7 @@ public: /** @name PS4 Controller functions */ /** * Used to get the analog value from button presses. - * @param a The ::ButtonEnum to read. + * @param b The ::ButtonEnum to read. * The supported buttons are: * ::UP, ::RIGHT, ::DOWN, ::LEFT, ::L1, ::L2, ::R1, ::R2, * ::TRIANGLE, ::CIRCLE, ::CROSS, ::SQUARE, and ::T. diff --git a/Wii.h b/Wii.h index 294cd7a2..848dec93 100755 --- a/Wii.h +++ b/Wii.h @@ -280,7 +280,7 @@ public: #ifdef WIICAMERA /** @name Wiimote IR camera functions - * You will have to set ENABLE_WII_IR_CAMERA in settings.h to 1 in order use the IR camera. + * You will have to set ::ENABLE_WII_IR_CAMERA in settings.h to 1 in order use the IR camera. */ /** Initialises the camera as per the steps from: http://wiibrew.org/wiki/Wiimote#IR_Camera */ void IRinitialize(); From 2a1db31cf13551528390e02640b38f101ba576ce Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Wed, 22 Jan 2014 05:13:49 +0100 Subject: [PATCH 18/42] Can now read the IMU and touchpad values of the PS4 controller via Bluetooth as well Thanks to Frank Zhao - see: http://eleccelerator.com/wiki/index.php?title=DualShock_4#0x11 --- BTHID.cpp | 2 +- BTHID.h | 28 ++++++++++++++++----------- PS4BT.h | 13 +++++++++++++ PS4Parser.cpp | 13 +++++++++---- PS4Parser.h | 1 - README.md | 4 ++-- examples/Bluetooth/PS4BT/PS4BT.ino | 31 ++++++++++++++++++++++++++++-- 7 files changed, 71 insertions(+), 21 deletions(-) diff --git a/BTHID.cpp b/BTHID.cpp index 64d3a812..37da8f04 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -202,7 +202,7 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { if(pRptParser[MOUSE_PARSER_ID]) pRptParser[MOUSE_PARSER_ID]->Parse(reinterpret_cast(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance break; -#ifdef DEBUG_USB_HOST +#ifdef EXTRADEBUG default: Notify(PSTR("\r\nUnknown Report type: "), 0x80); D_PrintHex (l2capinbuf[9], 0x80); diff --git a/BTHID.h b/BTHID.h index 07fd400d..58b907a4 100644 --- a/BTHID.h +++ b/BTHID.h @@ -126,8 +126,20 @@ protected: } /**@}*/ + /** Pointer to BTD instance */ + BTD *pBtd; + + /** HCI Handle for connection */ + uint16_t hci_handle; + + /** L2CAP source CID for HID_Control */ + + uint8_t control_scid[2]; + + /** L2CAP source CID for HID_Interrupt */ + uint8_t interrupt_scid[2]; + private: - BTD *pBtd; // Pointer to BTD instance HIDReportParser *pRptParser[NUM_PARSERS]; // Pointer to HIDReportParsers. /** Set report protocol. */ @@ -148,19 +160,13 @@ private: void L2CAP_task(); // L2CAP state machine - /* Variables filled from HCI event management */ - uint16_t hci_handle; bool activeConnection; // Used to indicate if it already has established a connection - /* Variables used by high level L2CAP task */ + /* Variables used for L2CAP communication */ + uint8_t control_dcid[2]; // L2CAP device CID for HID_Control - Always 0x0070 + uint8_t interrupt_dcid[2]; // L2CAP device CID for HID_Interrupt - Always 0x0071 + uint8_t identifier; // Identifier for connection uint8_t l2cap_state; uint32_t l2cap_event_flag; // l2cap flags of received Bluetooth events - - /* L2CAP Channels */ - uint8_t control_scid[2]; // L2CAP source CID for HID_Control - uint8_t control_dcid[2]; // 0x0070 - uint8_t interrupt_scid[2]; // L2CAP source CID for HID_Interrupt - uint8_t interrupt_dcid[2]; // 0x0071 - uint8_t identifier; // Identifier for connection }; #endif diff --git a/PS4BT.h b/PS4BT.h index 86b0ac47..02399fcf 100644 --- a/PS4BT.h +++ b/PS4BT.h @@ -72,6 +72,7 @@ protected: * This is useful for instance if you want to set the LEDs in a specific way. */ virtual void OnInitBTHID() { + enable_sixaxis(); // Make the controller to send out the entire output report if (pFuncOnInit) pFuncOnInit(); // Call the user function }; @@ -84,5 +85,17 @@ protected: private: void (*pFuncOnInit)(void); // Pointer to function called in onInit() + + void HID_Command(uint8_t *data, uint8_t nbytes) { + pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]); + }; + + void enable_sixaxis() { // Command used to make the PS4 controller send out the entire output report + uint8_t buf[2]; + buf[0] = 0x43; // HID BT Get_report (0x40) | Report Type (Feature 0x03) + buf[1] = 0x02; // Report ID + + HID_Command(buf, 2); + }; }; #endif \ No newline at end of file diff --git a/PS4Parser.cpp b/PS4Parser.cpp index 01624581..f22784cd 100644 --- a/PS4Parser.cpp +++ b/PS4Parser.cpp @@ -76,17 +76,22 @@ uint8_t PS4Parser::getAnalogHat(AnalogHatEnum a) { void PS4Parser::Parse(uint8_t len, uint8_t *buf) { if (len > 0 && buf) { #ifdef PRINTREPORT + Notify(PSTR("\r\n"), 0x80); for (uint8_t i = 0; i < len; i++) { D_PrintHex (buf[i], 0x80); Notify(PSTR(" "), 0x80); } - Notify(PSTR("\r\n"), 0x80); #endif - memcpy(&ps4Data, buf, min(len, sizeof(ps4Data))); - if (ps4Data.reportId != 0x01) { + + if (buf[0] == 0x01) // Check report ID + memcpy(&ps4Data, buf + 1, min(len - 1, sizeof(ps4Data))); + else if (buf[0] == 0x11) // This report is send via Bluetooth, it has an offset of 2 compared to the USB data + memcpy(&ps4Data, buf + 3, min(len - 3, sizeof(ps4Data))); + else { #ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nUnknown report id"), 0x80); + Notify(PSTR("\r\nUnknown report id: "), 0x80); + D_PrintHex (buf[0], 0x80); #endif return; } diff --git a/PS4Parser.h b/PS4Parser.h index ddd23161..f5bc65e9 100644 --- a/PS4Parser.h +++ b/PS4Parser.h @@ -87,7 +87,6 @@ struct touchpadXY { struct PS4Data { /* Button and joystick values */ - uint8_t reportId; // Always 0x01 uint8_t hatValue[4]; PS4Buttons btn; uint8_t trigger[2]; diff --git a/README.md b/README.md index 4bda8002..b2a7dcc4 100644 --- a/README.md +++ b/README.md @@ -124,8 +124,6 @@ The [PS4BT.ino](examples/Bluetooth/PS4BT/PS4BT.ino) and [PS4USB.ino](examples/PS I still have not figured out how to turn rumble on and off and set the color of the light, but hopefully I will figure that out soon. -Also the gyro, accelerometer and touchpad values are still only available via USB at the moment. - Before you can use the PS4 controller via Bluetooth you will need to pair with it. Simply create the PS4BT instance like so: ```PS4BT PS4(&Btd, PAIR);``` and then hold down the PS and Share button at the same time, the PS4 controller will then start to blink rapidly indicating that it is in paring mode. @@ -134,6 +132,8 @@ It should then automatically pair the dongle with your controller. This only hav For information see the following blog post: . +Also check out this excellent Wiki by Frank Zhao about the PS4 controller: . + ### PS3 Library These libraries consist of the [PS3BT](PS3BT.cpp) and [PS3USB](PS3USB.cpp). These libraries allows you to use a Dualshock 3, Navigation or a Motion controller with the USB Host Shield both via Bluetooth and USB. diff --git a/examples/Bluetooth/PS4BT/PS4BT.ino b/examples/Bluetooth/PS4BT/PS4BT.ino index 924cdc1d..0b850737 100644 --- a/examples/Bluetooth/PS4BT/PS4BT.ino +++ b/examples/Bluetooth/PS4BT/PS4BT.ino @@ -24,6 +24,8 @@ PS4BT PS4(&Btd, PAIR); // After that you can simply create the instance like so and then press the PS button on the device //PS4BT PS4(&Btd); +boolean printAngle, printTouch; + 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 @@ -88,10 +90,35 @@ void loop() { if (PS4.getButtonClick(SHARE)) Serial.print(F("\r\nShare")); - if (PS4.getButtonClick(OPTIONS)) + if (PS4.getButtonClick(OPTIONS)) { Serial.print(F("\r\nOptions")); - if (PS4.getButtonClick(TOUCHPAD)) + printAngle = !printAngle; + } + if (PS4.getButtonClick(TOUCHPAD)) { Serial.print(F("\r\nTouchpad")); + printTouch = !printTouch; + } + + if (printAngle) { // Print angle calculated using the accelerometer only + Serial.print(F("\r\nPitch: ")); + Serial.print(PS4.getAngle(Pitch)); + Serial.print(F("\tRoll: ")); + Serial.print(PS4.getAngle(Roll)); + } + + if (printTouch) { // Print the x, y coordinates of the touchpad + if (PS4.isTouching(0) || PS4.isTouching(1)) // Print newline and carriage return if any of the fingers are touching the touchpad + Serial.print(F("\r\n")); + for (uint8_t i = 0; i < 2; i++) { // The touchpad track two fingers + if (PS4.isTouching(i)) { // Print the position of the finger if it is touching the touchpad + Serial.print(F("X")); Serial.print(i + 1); Serial.print(F(": ")); + Serial.print(PS4.getX(i)); + Serial.print(F("\tY")); Serial.print(i + 1); Serial.print(F(": ")); + Serial.print(PS4.getY(i)); + Serial.print(F("\t")); + } + } + } } } } From 876962afcef92327dbdd8d65570e216a30a742df Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Wed, 22 Jan 2014 06:31:27 +0100 Subject: [PATCH 19/42] Update comments --- PS4BT.h | 2 +- PS4Parser.h | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/PS4BT.h b/PS4BT.h index 02399fcf..33bb58ec 100644 --- a/PS4BT.h +++ b/PS4BT.h @@ -72,7 +72,7 @@ protected: * This is useful for instance if you want to set the LEDs in a specific way. */ virtual void OnInitBTHID() { - enable_sixaxis(); // Make the controller to send out the entire output report + enable_sixaxis(); // Make the controller send out the entire output report if (pFuncOnInit) pFuncOnInit(); // Call the user function }; diff --git a/PS4Parser.h b/PS4Parser.h index f5bc65e9..4c1d9d4b 100644 --- a/PS4Parser.h +++ b/PS4Parser.h @@ -66,7 +66,7 @@ union PS4Buttons { uint8_t ps : 1; uint8_t touchpad : 1; - uint8_t timestamp : 6; // Only available via USB + uint8_t reportCounter : 6; }; uint8_t val[3]; }; @@ -91,8 +91,6 @@ struct PS4Data { PS4Buttons btn; uint8_t trigger[2]; - // I still need to figure out how to make the PS4 controller send out the rest of the data via Bluetooth - /* Gyro and accelerometer values */ uint8_t dummy[3]; // First two looks random, while the third one might be some kind of status - it increments once in a while int16_t gyroY, gyroZ, gyroX; @@ -100,7 +98,7 @@ struct PS4Data { /* The rest is data for the touchpad */ uint8_t dummy2[9]; // Byte 5 looks like some kind of status (maybe battery status), bit 1 of byte 8 is set every time a finger is moving around the touchpad - touchpadXY xy[3]; // It looks like it sends out three coordinates each time, this is possible because the microcontroller inside the PS4 controller is much faster than the Bluetooth connection. + touchpadXY xy[3]; // It looks like it sends out three coordinates each time, this might be because the microcontroller inside the PS4 controller is much faster than the Bluetooth connection. // The last data is read from the last position in the array while the oldest measurement is from the first position. // The first position will also keep it's value after the finger is released, while the other two will set them to zero. // Note that if you read fast enough from the device, then only the first one will contain any data. @@ -159,9 +157,7 @@ public: * @return Return the analog value in the range of 0-255. */ uint8_t getAnalogHat(AnalogHatEnum a); - /**@}*/ - /** @name Only available via USB at the moment */ /** * Get the x-coordinate of the touchpad. Position 0 is in the top left. * @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used. From 08abfd4268e7e927f9605019075f972d39e5b788 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Thu, 23 Jan 2014 10:38:00 +0100 Subject: [PATCH 20/42] Fixes #72 --- avrpins.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avrpins.h b/avrpins.h index ca83a8a9..bdc99ba6 100644 --- a/avrpins.h +++ b/avrpins.h @@ -457,7 +457,7 @@ public: #define P2 Pe4 #define P3 Pe5 #define P4 Pg5 -#define P5 Pe5 +#define P5 Pe3 #define P6 Ph3 #define P7 Ph4 From 78062121325f99e1a068eed8f0fe7c76017b9c6a Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 3 Feb 2014 23:06:27 +0100 Subject: [PATCH 21/42] Removed some unnecessary functions and some other cleanup --- BTHID.cpp | 2 +- BTHID.h | 3 +-- PS4BT.h | 14 +------------- PS4Parser.h | 12 ++++-------- PS4USB.h | 4 ++-- 5 files changed, 9 insertions(+), 26 deletions(-) diff --git a/BTHID.cpp b/BTHID.cpp index 37da8f04..01f190a7 100644 --- a/BTHID.cpp +++ b/BTHID.cpp @@ -190,7 +190,7 @@ void BTHID::ACLData(uint8_t* l2capinbuf) { #endif if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); - ParseBTHID(this, (uint8_t)(length - 1), &l2capinbuf[9]); + ParseBTHIDData((uint8_t)(length - 1), &l2capinbuf[9]); switch(l2capinbuf[9]) { case 0x01: // Keyboard or Joystick events diff --git a/BTHID.h b/BTHID.h index 58b907a4..2419e58b 100644 --- a/BTHID.h +++ b/BTHID.h @@ -109,11 +109,10 @@ protected: /** @name Overridable functions */ /** * Used to parse Bluetooth HID data to any class that inherits this class. - * @param bthid Pointer to this class. * @param len The length of the incoming data. * @param buf Pointer to the data buffer. */ - virtual void ParseBTHID(BTHID *bthid, uint8_t len, uint8_t *buf) { + virtual void ParseBTHIDData(uint8_t len, uint8_t *buf) { return; }; /** Called when a device is connected */ diff --git a/PS4BT.h b/PS4BT.h index 33bb58ec..bd42786a 100644 --- a/PS4BT.h +++ b/PS4BT.h @@ -46,14 +46,6 @@ public: return BTHID::connected; }; - /** - * Used to call your own function when the device is successfully initialized. - * @param funcOnInit Function to call. - */ - void attachOnInit(void (*funcOnInit)(void)) { - pFuncOnInit = funcOnInit; - }; - protected: /** @name BTHID implementation */ /** @@ -62,7 +54,7 @@ protected: * @param len The length of the incoming data. * @param buf Pointer to the data buffer. */ - virtual void ParseBTHID(BTHID *bthid, uint8_t len, uint8_t *buf) { + virtual void ParseBTHIDData(uint8_t len, uint8_t *buf) { PS4Parser::Parse(len, buf); }; @@ -73,8 +65,6 @@ protected: */ virtual void OnInitBTHID() { enable_sixaxis(); // Make the controller send out the entire output report - if (pFuncOnInit) - pFuncOnInit(); // Call the user function }; /** Used to reset the different buffers to there default values */ @@ -84,8 +74,6 @@ protected: /**@}*/ private: - void (*pFuncOnInit)(void); // Pointer to function called in onInit() - void HID_Command(uint8_t *data, uint8_t nbytes) { pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]); }; diff --git a/PS4Parser.h b/PS4Parser.h index 4c1d9d4b..cedbc0b4 100644 --- a/PS4Parser.h +++ b/PS4Parser.h @@ -74,14 +74,10 @@ union PS4Buttons { struct touchpadXY { uint8_t dummy; // I can not figure out what this data is for, it seems to change randomly, maybe a timestamp? struct { - struct { - uint8_t counter : 7; // Increments every time a finger is touching the touchpad - uint8_t touching : 1; // The top bit is cleared if the finger is touching the touchpad - }; - struct { - uint16_t x : 12; - uint16_t y : 12; - }; + uint8_t counter : 7; // Increments every time a finger is touching the touchpad + uint8_t touching : 1; // The top bit is cleared if the finger is touching the touchpad + uint16_t x : 12; + uint16_t y : 12; } finger[2]; // 0 = first finger, 1 = second finger }; diff --git a/PS4USB.h b/PS4USB.h index 1ea2a421..fcb514c3 100644 --- a/PS4USB.h +++ b/PS4USB.h @@ -21,8 +21,8 @@ #include "hiduniversal.h" #include "PS4Parser.h" -#define PS4_VID 0x054C // Sony Corporation -#define PS4_PID 0x05C4 // PS4 Controller +#define PS4_VID 0x054C // Sony Corporation +#define PS4_PID 0x05C4 // PS4 Controller /** * This class implements support for the PS4 controller via USB. From b25c7d2f3c674a430e5aa25e74b229475521ef88 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 3 Feb 2014 23:11:44 +0100 Subject: [PATCH 22/42] Made it easy to disable printing incoming data in hiduniversal --- hiduniversal.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hiduniversal.cpp b/hiduniversal.cpp index 4e866cb2..a2b4dc2e 100644 --- a/hiduniversal.cpp +++ b/hiduniversal.cpp @@ -381,14 +381,14 @@ uint8_t HIDUniversal::Poll() { if(identical) return 0; - +#if 1 Notify(PSTR("\r\nBuf: "), 0x80); for(uint8_t i = 0; i < read; i++) D_PrintHex (buf[i], 0x80); Notify(PSTR("\r\n"), 0x80); - +#endif ParseHIDData(this, bHasReportId, (uint8_t)read, buf); HIDReportParser *prs = GetReportParser(((bHasReportId) ? *buf : 0)); From 9b44357d044f13f29bd2e21a02cb74d21a3a40e0 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 16 Feb 2014 01:24:38 +0100 Subject: [PATCH 23/42] Added packed attribute to all structs in PS4Parser.h. This was needed for Teensy 3.x It was actually only necessary for finger in touchpadXY, but I added to all structs to prevent similar compile errors for future architectures --- PS4Parser.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PS4Parser.h b/PS4Parser.h index cedbc0b4..1fe8ab2a 100644 --- a/PS4Parser.h +++ b/PS4Parser.h @@ -67,7 +67,7 @@ union PS4Buttons { uint8_t ps : 1; uint8_t touchpad : 1; uint8_t reportCounter : 6; - }; + } __attribute__((packed)); uint8_t val[3]; }; @@ -78,8 +78,8 @@ struct touchpadXY { uint8_t touching : 1; // The top bit is cleared if the finger is touching the touchpad uint16_t x : 12; uint16_t y : 12; - } finger[2]; // 0 = first finger, 1 = second finger -}; + } __attribute__((packed)) finger[2]; // 0 = first finger, 1 = second finger +} __attribute__((packed)); struct PS4Data { /* Button and joystick values */ @@ -100,7 +100,7 @@ struct PS4Data { // Note that if you read fast enough from the device, then only the first one will contain any data. // The last three bytes are always: 0x00, 0x80, 0x00 -}; +} __attribute__((packed)); enum DPADEnum { DPAD_UP = 0x0, From ac5d134f73a0296d26d23b86b4cde4b9cb2bcc59 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 16 Feb 2014 18:13:19 +0100 Subject: [PATCH 24/42] Added support for Afterglow wired Xbox controller --- XBOXUSB.cpp | 2 +- XBOXUSB.h | 23 ++++++++++++----------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/XBOXUSB.cpp b/XBOXUSB.cpp index 8ee06d4f..4128d231 100644 --- a/XBOXUSB.cpp +++ b/XBOXUSB.cpp @@ -105,7 +105,7 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) { Notify(PSTR("\r\nThis library only supports Xbox 360 controllers via USB"), 0x80); #endif goto FailUnknownDevice; - } else if(PID != XBOX_WIRED_PID && PID != MADCATZ_WIRED_PID && PID != GAMESTOP_WIRED_PID) // Check PID + } else if(PID != XBOX_WIRED_PID && PID != MADCATZ_WIRED_PID && PID != GAMESTOP_WIRED_PID && PID != AFTERGLOW_WIRED_PID) // Check PID goto FailUnknownDevice; // Allocate new address according to device class diff --git a/XBOXUSB.h b/XBOXUSB.h index c18ea248..aed330a2 100644 --- a/XBOXUSB.h +++ b/XBOXUSB.h @@ -33,17 +33,18 @@ #define XBOX_OUTPUT_PIPE 2 // PID and VID of the different devices -#define XBOX_VID 0x045E // Microsoft Corporation -#define MADCATZ_VID 0x1BAD // For unofficial Mad Catz controllers -#define JOYTECH_VID 0x162E // For unofficial Joytech controllers -#define GAMESTOP_VID 0x0E6F // Gamestop controller +#define XBOX_VID 0x045E // Microsoft Corporation +#define MADCATZ_VID 0x1BAD // For unofficial Mad Catz controllers +#define JOYTECH_VID 0x162E // For unofficial Joytech controllers +#define GAMESTOP_VID 0x0E6F // Gamestop controller -#define XBOX_WIRED_PID 0x028E // Microsoft 360 Wired controller -#define XBOX_WIRELESS_PID 0x028F // Wireless controller only support charging -#define XBOX_WIRELESS_RECEIVER_PID 0x0719 // Microsoft Wireless Gaming Receiver -#define XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID 0x0291 // Third party Wireless Gaming Receiver -#define MADCATZ_WIRED_PID 0xF016 // Mad Catz wired controller -#define GAMESTOP_WIRED_PID 0x0401 // Gamestop wired controller +#define XBOX_WIRED_PID 0x028E // Microsoft 360 Wired controller +#define XBOX_WIRELESS_PID 0x028F // Wireless controller only support charging +#define XBOX_WIRELESS_RECEIVER_PID 0x0719 // Microsoft Wireless Gaming Receiver +#define XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID 0x0291 // Third party Wireless Gaming Receiver +#define MADCATZ_WIRED_PID 0xF016 // Mad Catz wired controller +#define GAMESTOP_WIRED_PID 0x0401 // Gamestop wired controller +#define AFTERGLOW_WIRED_PID 0x0213 // Afterglow wired controller - it uses the same VID as a Gamestop controller #define XBOX_REPORT_BUFFER_SIZE 14 // Size of the input report buffer @@ -105,7 +106,7 @@ public: * @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 || vid == MADCATZ_VID || vid == JOYTECH_VID || vid == GAMESTOP_VID) && (pid == XBOX_WIRED_PID || pid == MADCATZ_WIRED_PID || pid == GAMESTOP_WIRED_PID)); + return ((vid == XBOX_VID || vid == MADCATZ_VID || vid == JOYTECH_VID || vid == GAMESTOP_VID) && (pid == XBOX_WIRED_PID || pid == MADCATZ_WIRED_PID || pid == GAMESTOP_WIRED_PID || pid == AFTERGLOW_WIRED_PID)); }; /**@}*/ From 6373ebe6ce1010b5242197149d33a9e1be2bc34d Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 17 Feb 2014 00:21:21 +0100 Subject: [PATCH 25/42] Can now set the rumble and light on the PS4 controller Still need to test it via USB --- PS3Enums.h | 27 ------------- PS4BT.h | 43 ++++++++++++++++++++ PS4Parser.cpp | 3 ++ PS4Parser.h | 83 ++++++++++++++++++++++++++++++++++++++ PS4USB.h | 36 +++++++++++++++-- README.md | 6 +-- controllerEnums.h | 27 +++++++++++++ examples/PS4USB/PS4USB.ino | 5 +++ hiduniversal.h | 8 ++-- keywords.txt | 1 + 10 files changed, 200 insertions(+), 39 deletions(-) diff --git a/PS3Enums.h b/PS3Enums.h index 7ee84293..77801945 100644 --- a/PS3Enums.h +++ b/PS3Enums.h @@ -110,28 +110,6 @@ const uint8_t PS3_ANALOG_BUTTONS[] PROGMEM = { 15, // T_ANALOG - Both at byte 14 (last reading) and byte 15 (current reading) }; -/** Used to set the colors of the move controller. */ -enum ColorsEnum { - /** r = 255, g = 0, b = 0 */ - Red = 0xFF0000, - /** r = 0, g = 255, b = 0 */ - Green = 0xFF00, - /** r = 0, g = 0, b = 255 */ - Blue = 0xFF, - - /** r = 255, g = 235, b = 4 */ - Yellow = 0xFFEB04, - /** r = 0, g = 255, b = 255 */ - Lightblue = 0xFFFF, - /** r = 255, g = 0, b = 255 */ - Purble = 0xFF00FF, - - /** r = 255, g = 255, b = 255 */ - White = 0xFFFFFF, - /** r = 0, g = 0, b = 0 */ - Off = 0x00, -}; - enum StatusEnum { // Note that the location is shifted 9 when it's connected via USB // Byte location | bit location @@ -160,9 +138,4 @@ enum StatusEnum { Bluetooth = (40 << 8) | 0x16, // Operating by Bluetooth and rumble is turned off }; -enum RumbleEnum { - RumbleHigh = 0x10, - RumbleLow = 0x20, -}; - #endif diff --git a/PS4BT.h b/PS4BT.h index bd42786a..129df6b1 100644 --- a/PS4BT.h +++ b/PS4BT.h @@ -46,6 +46,14 @@ public: return BTHID::connected; }; + /** + * Used to call your own function when the device is successfully initialized. + * @param funcOnInit Function to call. + */ + void attachOnInit(void (*funcOnInit)(void)) { + pFuncOnInit = funcOnInit; + }; + protected: /** @name BTHID implementation */ /** @@ -64,7 +72,12 @@ protected: * This is useful for instance if you want to set the LEDs in a specific way. */ virtual void OnInitBTHID() { + PS4Parser::Reset(); enable_sixaxis(); // Make the controller send out the entire output report + if (pFuncOnInit) + pFuncOnInit(); // Call the user function + else + setLed(Blue); }; /** Used to reset the different buffers to there default values */ @@ -74,6 +87,34 @@ protected: /**@}*/ private: + /** @name PS4Parser implementation */ + virtual void sendOutputReport(PS4Output *output) { // Source: https://github.com/chrippa/ds4drv + uint8_t buf[79]; + memset(buf, 0, sizeof(buf)); + + buf[0] = 0x52; // HID BT Set_report (0x50) | Report Type (Output 0x02) + buf[1] = 0x11; // Report ID + buf[2] = 0x80; + buf[4]= 0xFF; + + buf[7] = output->bigRumble; // Big Rumble + buf[8] = output->smallRumble; // Small rumble + + buf[9] = output->r; // Red + buf[10] = output->g; // Green + buf[11] = output->b; // Blue + + buf[12] = output->flashOn; // Time to flash bright (255 = 2.5 seconds) + buf[13] = output->flashOff; // Time to flash dark (255 = 2.5 seconds) + + output->reportChanged = false; + + // The PS4 console actually set the four last bytes to a CRC32 checksum, but it seems like it is actually not needed + + HID_Command(buf, sizeof(buf)); + }; + /**@}*/ + void HID_Command(uint8_t *data, uint8_t nbytes) { pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]); }; @@ -85,5 +126,7 @@ private: HID_Command(buf, 2); }; + + void (*pFuncOnInit)(void); // Pointer to function called in onInit() }; #endif \ No newline at end of file diff --git a/PS4Parser.cpp b/PS4Parser.cpp index f22784cd..1a449adb 100644 --- a/PS4Parser.cpp +++ b/PS4Parser.cpp @@ -118,4 +118,7 @@ void PS4Parser::Parse(uint8_t len, uint8_t *buf) { } } } + + if (ps4Output.reportChanged) + sendOutputReport(&ps4Output); // Send output report } \ No newline at end of file diff --git a/PS4Parser.h b/PS4Parser.h index 1fe8ab2a..680edc83 100644 --- a/PS4Parser.h +++ b/PS4Parser.h @@ -102,6 +102,13 @@ struct PS4Data { // The last three bytes are always: 0x00, 0x80, 0x00 } __attribute__((packed)); +struct PS4Output { + uint8_t bigRumble, smallRumble; // Rumble + uint8_t r, g, b; // RGB + uint8_t flashOn, flashOff; // Time to flash bright/dark (255 = 2.5 seconds) + bool reportChanged; // The data is send when data is received from the controller +} __attribute__((packed)); + enum DPADEnum { DPAD_UP = 0x0, DPAD_UP_RIGHT = 0x1, @@ -237,6 +244,74 @@ public: return 0; } }; + + /** Turn both rumble and the LEDs off. */ + void setAllOff() { + setRumbleOff(); + setLedOff(); + }; + + /** Set rumble off. */ + void setRumbleOff() { + setRumbleOn(0, 0); + }; + + /** + * Turn on rumble. + * @param mode Either ::RumbleHigh or ::RumbleLow. + */ + void setRumbleOn(RumbleEnum mode) { + if (mode == RumbleLow) + setRumbleOn(0xFF, 0x00); + else + setRumbleOn(0x00, 0xFF); + }; + + /** + * Turn on rumble. + * @param bigRumble Value for big motor. + * @param smallRumble Value for small motor. + */ + void setRumbleOn(uint8_t bigRumble, uint8_t smallRumble) { + ps4Output.bigRumble = bigRumble; + ps4Output.smallRumble = smallRumble; + ps4Output.reportChanged = true; + }; + + /** Turn all LEDs off. */ + void setLedOff() { + setLed(0, 0, 0); + }; + + /** + * Use this to set the color using RGB values. + * @param r,g,b RGB value. + */ + void setLed(uint8_t r, uint8_t g, uint8_t b) { + ps4Output.r = r; + ps4Output.g = g; + ps4Output.b = b; + ps4Output.reportChanged = true; + }; + + /** + * Use this to set the color using the predefined colors in ::ColorsEnum. + * @param color The desired color. + */ + void setLed(ColorsEnum color) { + setLed((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color)); + }; + + /** + * Set the LEDs flash time. + * @param flashOn Time to flash bright (255 = 2.5 seconds). + * @param flashOff Time to flash dark (255 = 2.5 seconds). + */ + void setLedFlash(uint8_t flashOn, uint8_t flashOff) { + ps4Output.flashOn = flashOn; + ps4Output.flashOff = flashOff; + ps4Output.reportChanged = true; + }; /**@}*/ protected: @@ -267,13 +342,21 @@ protected: oldButtonState.dpad = DPAD_OFF; buttonClickState.dpad = 0; oldDpad = 0; + + ps4Output.bigRumble = ps4Output.smallRumble = 0; + ps4Output.r = ps4Output.g = ps4Output.b = 0; + ps4Output.flashOn = ps4Output.flashOff = 0; + ps4Output.reportChanged = false; }; + virtual void sendOutputReport(PS4Output *output) = 0; // This is overridden in PS4BT and PS4USB + private: bool checkDpad(ButtonEnum b); // Used to check PS4 DPAD buttons PS4Data ps4Data; PS4Buttons oldButtonState, buttonClickState; + PS4Output ps4Output; uint8_t oldDpad; }; #endif \ No newline at end of file diff --git a/PS4USB.h b/PS4USB.h index fcb514c3..d377b60d 100644 --- a/PS4USB.h +++ b/PS4USB.h @@ -75,14 +75,44 @@ protected: * This is useful for instance if you want to set the LEDs in a specific way. */ virtual uint8_t OnInitSuccessful() { - PS4Parser::Reset(); - if (HIDUniversal::VID == PS4_VID && HIDUniversal::PID == PS4_PID && pFuncOnInit) - pFuncOnInit(); // Call the user function + if (HIDUniversal::VID == PS4_VID && HIDUniversal::PID == PS4_PID) { + PS4Parser::Reset(); + if (pFuncOnInit) + pFuncOnInit(); // Call the user function + else + setLed(Blue); + }; return 0; }; /**@}*/ private: + /** @name PS4Parser implementation */ + virtual void sendOutputReport(PS4Output *output) { // Source: https://github.com/chrippa/ds4drv + uint8_t buf[32]; + memset(buf, 0, sizeof(buf)); + + buf[0] = 0x05; // Report ID + buf[1]= 0xFF; + + buf[4] = output->bigRumble; // Big Rumble + buf[5] = output->smallRumble; // Small rumble + + buf[6] = output->r; // Red + buf[7] = output->g; // Green + buf[8] = output->b; // Blue + + buf[9] = output->flashOn; // Time to flash bright (255 = 2.5 seconds) + buf[10] = output->flashOff; // Time to flash dark (255 = 2.5 seconds) + + output->reportChanged = false; + + // The PS4 console actually set the four last bytes to a CRC32 checksum, but it seems like it is actually not needed + + pUsb->outTransfer(bAddress, epInfo[ hidInterfaces[0].epIndex[epInterruptOutIndex] ].epAddr, sizeof(buf), buf); + }; + /**@}*/ + void (*pFuncOnInit)(void); // Pointer to function called in onInit() }; #endif \ No newline at end of file diff --git a/README.md b/README.md index b2a7dcc4..56152496 100644 --- a/README.md +++ b/README.md @@ -120,9 +120,7 @@ It enables me to see the Bluetooth communication between my Mac and any device. The PS4BT library is split up into the [PS4BT](PS4BT.h) and the [PS4USB](PS4USB.h) library. These allow you to use the Sony PS4 controller via Bluetooth and USB. -The [PS4BT.ino](examples/Bluetooth/PS4BT/PS4BT.ino) and [PS4USB.ino](examples/PS4USB/PS4USB.ino) examples shows how to easily read the buttons and joysticks on the controller via Bluetooth and USB respectively. - -I still have not figured out how to turn rumble on and off and set the color of the light, but hopefully I will figure that out soon. +The [PS4BT.ino](examples/Bluetooth/PS4BT/PS4BT.ino) and [PS4USB.ino](examples/PS4USB/PS4USB.ino) examples shows how to easily read the buttons, joysticks, touchpad and IMU on the controller via Bluetooth and USB respectively. It is also possible to control the rumble and light on the controller. Before you can use the PS4 controller via Bluetooth you will need to pair with it. @@ -132,7 +130,7 @@ It should then automatically pair the dongle with your controller. This only hav For information see the following blog post: . -Also check out this excellent Wiki by Frank Zhao about the PS4 controller: . +Also check out this excellent Wiki by Frank Zhao about the PS4 controller: and this Linux driver: . ### PS3 Library diff --git a/controllerEnums.h b/controllerEnums.h index 0eae781d..295b6ae4 100644 --- a/controllerEnums.h +++ b/controllerEnums.h @@ -41,6 +41,33 @@ enum LEDEnum { ALL = 5, }; +/** Used to set the colors of the Move and PS4 controller. */ +enum ColorsEnum { + /** r = 255, g = 0, b = 0 */ + Red = 0xFF0000, + /** r = 0, g = 255, b = 0 */ + Green = 0xFF00, + /** r = 0, g = 0, b = 255 */ + Blue = 0xFF, + + /** r = 255, g = 235, b = 4 */ + Yellow = 0xFFEB04, + /** r = 0, g = 255, b = 255 */ + Lightblue = 0xFFFF, + /** r = 255, g = 0, b = 255 */ + Purble = 0xFF00FF, + + /** r = 255, g = 255, b = 255 */ + White = 0xFFFFFF, + /** r = 0, g = 0, b = 0 */ + Off = 0x00, +}; + +enum RumbleEnum { + RumbleHigh = 0x10, + RumbleLow = 0x20, +}; + /** This enum is used to read all the different buttons on the different controllers */ enum ButtonEnum { /**@{*/ diff --git a/examples/PS4USB/PS4USB.ino b/examples/PS4USB/PS4USB.ino index 95a0e586..c8dc5069 100644 --- a/examples/PS4USB/PS4USB.ino +++ b/examples/PS4USB/PS4USB.ino @@ -6,6 +6,11 @@ #include +// Satisfy IDE, which only needs to see the include statment in the ino. +#ifdef dobogusinclude +#include +#endif + USB Usb; PS4USB PS4(&Usb); diff --git a/hiduniversal.h b/hiduniversal.h index bfd1173b..d97f4b8c 100644 --- a/hiduniversal.h +++ b/hiduniversal.h @@ -17,10 +17,7 @@ class HIDUniversal : public HID { // Returns HID class specific descriptor length by its type and order number uint16_t GetHidClassDescrLen(uint8_t type, uint8_t num); - EpInfo epInfo[totalEndpoints]; - struct HIDInterface { - struct { uint8_t bmInterface : 3; uint8_t bmAltSet : 3; @@ -29,8 +26,6 @@ class HIDUniversal : public HID { uint8_t epIndex[maxEpPerInterface]; }; - HIDInterface hidInterfaces[maxHidInterfaces]; - uint8_t bConfNum; // configuration number uint8_t bNumIface; // number of interfaces in the configuration uint8_t bNumEP; // total number of EP in the configuration @@ -49,6 +44,9 @@ class HIDUniversal : public HID { void SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest); protected: + EpInfo epInfo[totalEndpoints]; + HIDInterface hidInterfaces[maxHidInterfaces]; + bool bHasReportId; uint16_t PID, VID; // PID and VID of connected device diff --git a/keywords.txt b/keywords.txt index 786d4fa2..a13ff34d 100644 --- a/keywords.txt +++ b/keywords.txt @@ -64,6 +64,7 @@ setRumbleOn KEYWORD2 setLedOff KEYWORD2 setLedOn KEYWORD2 setLedToggle KEYWORD2 +setLedFlash KEYWORD2 moveSetBulb KEYWORD2 moveSetRumble KEYWORD2 From 2b69cfe15e18482a810f91a87726a48349e977c4 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 17 Feb 2014 00:27:46 +0100 Subject: [PATCH 26/42] Fixed indentation in PS4Parser.cpp --- PS4Parser.cpp | 128 +++++++++++++++++++++++++------------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/PS4Parser.cpp b/PS4Parser.cpp index 1a449adb..d8157f43 100644 --- a/PS4Parser.cpp +++ b/PS4Parser.cpp @@ -36,89 +36,89 @@ bool PS4Parser::checkDpad(ButtonEnum b) { } bool PS4Parser::getButtonPress(ButtonEnum b) { - if (b <= LEFT) // Dpad - return checkDpad(b); - else { - uint8_t button = pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]); - uint8_t index = button < 8 ? 0 : button < 16 ? 1 : 2; - uint8_t mask = 1 << (button - 8 * index); - return ps4Data.btn.val[index] & mask; - } + if (b <= LEFT) // Dpad + return checkDpad(b); + else { + uint8_t button = pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]); + uint8_t index = button < 8 ? 0 : button < 16 ? 1 : 2; + uint8_t mask = 1 << (button - 8 * index); + return ps4Data.btn.val[index] & mask; + } } bool PS4Parser::getButtonClick(ButtonEnum b) { - uint8_t mask, index = 0; - if (b <= LEFT) // Dpad - mask = 1 << b; - else { - uint8_t button = pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]); - index = button < 8 ? 0 : button < 16 ? 1 : 2; - mask = 1 << (button - 8 * index); - } + uint8_t mask, index = 0; + if (b <= LEFT) // Dpad + mask = 1 << b; + else { + uint8_t button = pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]); + index = button < 8 ? 0 : button < 16 ? 1 : 2; + mask = 1 << (button - 8 * index); + } - bool click = buttonClickState.val[index] & mask; - buttonClickState.val[index] &= ~mask; // Clear "click" event - return click; + bool click = buttonClickState.val[index] & mask; + buttonClickState.val[index] &= ~mask; // Clear "click" event + return click; } uint8_t PS4Parser::getAnalogButton(ButtonEnum b) { - if (b == L2) // These are the only analog buttons on the controller - return ps4Data.trigger[0]; - else if (b == R2) - return ps4Data.trigger[1]; - return 0; + if (b == L2) // These are the only analog buttons on the controller + return ps4Data.trigger[0]; + else if (b == R2) + return ps4Data.trigger[1]; + return 0; } uint8_t PS4Parser::getAnalogHat(AnalogHatEnum a) { - return ps4Data.hatValue[(uint8_t)a]; + return ps4Data.hatValue[(uint8_t)a]; } void PS4Parser::Parse(uint8_t len, uint8_t *buf) { - if (len > 0 && buf) { + if (len > 0 && buf) { #ifdef PRINTREPORT - Notify(PSTR("\r\n"), 0x80); - for (uint8_t i = 0; i < len; i++) { - D_PrintHex (buf[i], 0x80); - Notify(PSTR(" "), 0x80); - } + Notify(PSTR("\r\n"), 0x80); + for (uint8_t i = 0; i < len; i++) { + D_PrintHex (buf[i], 0x80); + Notify(PSTR(" "), 0x80); + } #endif - if (buf[0] == 0x01) // Check report ID - memcpy(&ps4Data, buf + 1, min(len - 1, sizeof(ps4Data))); - else if (buf[0] == 0x11) // This report is send via Bluetooth, it has an offset of 2 compared to the USB data - memcpy(&ps4Data, buf + 3, min(len - 3, sizeof(ps4Data))); - else { + if (buf[0] == 0x01) // Check report ID + memcpy(&ps4Data, buf + 1, min(len - 1, sizeof(ps4Data))); + else if (buf[0] == 0x11) // This report is send via Bluetooth, it has an offset of 2 compared to the USB data + memcpy(&ps4Data, buf + 3, min(len - 3, sizeof(ps4Data))); + else { #ifdef DEBUG_USB_HOST - Notify(PSTR("\r\nUnknown report id: "), 0x80); - D_PrintHex (buf[0], 0x80); + Notify(PSTR("\r\nUnknown report id: "), 0x80); + D_PrintHex (buf[0], 0x80); #endif - return; - } + return; + } - for (uint8_t i = 0; i < sizeof(ps4Data.btn); i++) { - if (ps4Data.btn.val[i] != oldButtonState.val[i]) { // Check if anything has changed - buttonClickState.val[i] = ps4Data.btn.val[i] & ~oldButtonState.val[i]; // Update click state variable - oldButtonState.val[i] = ps4Data.btn.val[i]; - if (i == 0) { // The DPAD buttons does not set the different bits, but set a value corresponding to the buttons pressed, we will simply set the bits ourself - uint8_t newDpad = 0; - if (checkDpad(UP)) - newDpad |= 1 << UP; - if (checkDpad(RIGHT)) - newDpad |= 1 << RIGHT; - if (checkDpad(DOWN)) - newDpad |= 1 << DOWN; - if (checkDpad(LEFT)) - newDpad |= 1 << LEFT; - if (newDpad != oldDpad) { - buttonClickState.dpad = newDpad & ~oldDpad; // Override values - oldDpad = newDpad; - } - } - } - } - } + for (uint8_t i = 0; i < sizeof(ps4Data.btn); i++) { + if (ps4Data.btn.val[i] != oldButtonState.val[i]) { // Check if anything has changed + buttonClickState.val[i] = ps4Data.btn.val[i] & ~oldButtonState.val[i]; // Update click state variable + oldButtonState.val[i] = ps4Data.btn.val[i]; + if (i == 0) { // The DPAD buttons does not set the different bits, but set a value corresponding to the buttons pressed, we will simply set the bits ourself + uint8_t newDpad = 0; + if (checkDpad(UP)) + newDpad |= 1 << UP; + if (checkDpad(RIGHT)) + newDpad |= 1 << RIGHT; + if (checkDpad(DOWN)) + newDpad |= 1 << DOWN; + if (checkDpad(LEFT)) + newDpad |= 1 << LEFT; + if (newDpad != oldDpad) { + buttonClickState.dpad = newDpad & ~oldDpad; // Override values + oldDpad = newDpad; + } + } + } + } + } - if (ps4Output.reportChanged) - sendOutputReport(&ps4Output); // Send output report + if (ps4Output.reportChanged) + sendOutputReport(&ps4Output); // Send output report } \ No newline at end of file From a21d1e7258b9a095f96ae87f53a16a0fa7e30287 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 17 Feb 2014 00:50:02 +0100 Subject: [PATCH 27/42] Cleanup No new code --- PS4BT.h | 10 +++++----- PS4Parser.h | 8 ++++++-- PS4USB.h | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/PS4BT.h b/PS4BT.h index 129df6b1..85d70f48 100644 --- a/PS4BT.h +++ b/PS4BT.h @@ -86,7 +86,6 @@ protected: }; /**@}*/ -private: /** @name PS4Parser implementation */ virtual void sendOutputReport(PS4Output *output) { // Source: https://github.com/chrippa/ds4drv uint8_t buf[79]; @@ -115,10 +114,7 @@ private: }; /**@}*/ - void HID_Command(uint8_t *data, uint8_t nbytes) { - pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]); - }; - +private: void enable_sixaxis() { // Command used to make the PS4 controller send out the entire output report uint8_t buf[2]; buf[0] = 0x43; // HID BT Get_report (0x40) | Report Type (Feature 0x03) @@ -127,6 +123,10 @@ private: HID_Command(buf, 2); }; + void HID_Command(uint8_t *data, uint8_t nbytes) { + pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]); + }; + void (*pFuncOnInit)(void); // Pointer to function called in onInit() }; #endif \ No newline at end of file diff --git a/PS4Parser.h b/PS4Parser.h index 680edc83..acde9a65 100644 --- a/PS4Parser.h +++ b/PS4Parser.h @@ -215,7 +215,7 @@ public: * @return Return the angle in the range of 0-360. */ double getAngle(AngleEnum a) { - if(a == Pitch) + if (a == Pitch) return (atan2(ps4Data.accY, ps4Data.accZ) + PI) * RAD_TO_DEG; else return (atan2(ps4Data.accX, ps4Data.accZ) + PI) * RAD_TO_DEG; @@ -349,7 +349,11 @@ protected: ps4Output.reportChanged = false; }; - virtual void sendOutputReport(PS4Output *output) = 0; // This is overridden in PS4BT and PS4USB + /** + * Send the output to the PS4 controller. This is implemented in PS4BT.h and PS4USB.h. + * @param output Pointer to PS4Output buffer; + */ + virtual void sendOutputReport(PS4Output *output) = 0; private: bool checkDpad(ButtonEnum b); // Used to check PS4 DPAD buttons diff --git a/PS4USB.h b/PS4USB.h index d377b60d..019ea930 100644 --- a/PS4USB.h +++ b/PS4USB.h @@ -86,7 +86,6 @@ protected: }; /**@}*/ -private: /** @name PS4Parser implementation */ virtual void sendOutputReport(PS4Output *output) { // Source: https://github.com/chrippa/ds4drv uint8_t buf[32]; @@ -113,6 +112,7 @@ private: }; /**@}*/ +private: void (*pFuncOnInit)(void); // Pointer to function called in onInit() }; #endif \ No newline at end of file From fcd6eb508475a9a614aa5c445bb0e35fd6fc3e71 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 17 Feb 2014 01:25:29 +0100 Subject: [PATCH 28/42] Improved the way PS4 buttons are read --- PS4Parser.cpp | 59 +++++++++++++++++++-------------------------------- PS4Parser.h | 12 +++++------ 2 files changed, 27 insertions(+), 44 deletions(-) diff --git a/PS4Parser.cpp b/PS4Parser.cpp index d8157f43..ca992866 100644 --- a/PS4Parser.cpp +++ b/PS4Parser.cpp @@ -38,26 +38,14 @@ bool PS4Parser::checkDpad(ButtonEnum b) { bool PS4Parser::getButtonPress(ButtonEnum b) { if (b <= LEFT) // Dpad return checkDpad(b); - else { - uint8_t button = pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]); - uint8_t index = button < 8 ? 0 : button < 16 ? 1 : 2; - uint8_t mask = 1 << (button - 8 * index); - return ps4Data.btn.val[index] & mask; - } + else + return ps4Data.btn.val & (1UL << pgm_read_byte(&PS4_BUTTONS[(uint8_t)b])); } bool PS4Parser::getButtonClick(ButtonEnum b) { - uint8_t mask, index = 0; - if (b <= LEFT) // Dpad - mask = 1 << b; - else { - uint8_t button = pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]); - index = button < 8 ? 0 : button < 16 ? 1 : 2; - mask = 1 << (button - 8 * index); - } - - bool click = buttonClickState.val[index] & mask; - buttonClickState.val[index] &= ~mask; // Clear "click" event + uint32_t mask = 1UL << pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]); + bool click = buttonClickState.val & mask; + buttonClickState.val &= ~mask; // Clear "click" event return click; } @@ -83,7 +71,6 @@ void PS4Parser::Parse(uint8_t len, uint8_t *buf) { } #endif - if (buf[0] == 0x01) // Check report ID memcpy(&ps4Data, buf + 1, min(len - 1, sizeof(ps4Data))); else if (buf[0] == 0x11) // This report is send via Bluetooth, it has an offset of 2 compared to the USB data @@ -96,25 +83,23 @@ void PS4Parser::Parse(uint8_t len, uint8_t *buf) { return; } - for (uint8_t i = 0; i < sizeof(ps4Data.btn); i++) { - if (ps4Data.btn.val[i] != oldButtonState.val[i]) { // Check if anything has changed - buttonClickState.val[i] = ps4Data.btn.val[i] & ~oldButtonState.val[i]; // Update click state variable - oldButtonState.val[i] = ps4Data.btn.val[i]; - if (i == 0) { // The DPAD buttons does not set the different bits, but set a value corresponding to the buttons pressed, we will simply set the bits ourself - uint8_t newDpad = 0; - if (checkDpad(UP)) - newDpad |= 1 << UP; - if (checkDpad(RIGHT)) - newDpad |= 1 << RIGHT; - if (checkDpad(DOWN)) - newDpad |= 1 << DOWN; - if (checkDpad(LEFT)) - newDpad |= 1 << LEFT; - if (newDpad != oldDpad) { - buttonClickState.dpad = newDpad & ~oldDpad; // Override values - oldDpad = newDpad; - } - } + if (ps4Data.btn.val != oldButtonState.val) { // Check if anything has changed + buttonClickState.val = ps4Data.btn.val & ~oldButtonState.val; // Update click state variable + oldButtonState.val = ps4Data.btn.val; + + // The DPAD buttons does not set the different bits, but set a value corresponding to the buttons pressed, we will simply set the bits ourself + uint8_t newDpad = 0; + if (checkDpad(UP)) + newDpad |= 1 << UP; + if (checkDpad(RIGHT)) + newDpad |= 1 << RIGHT; + if (checkDpad(DOWN)) + newDpad |= 1 << DOWN; + if (checkDpad(LEFT)) + newDpad |= 1 << LEFT; + if (newDpad != oldDpad) { + buttonClickState.dpad = newDpad & ~oldDpad; // Override values + oldDpad = newDpad; } } } diff --git a/PS4Parser.h b/PS4Parser.h index acde9a65..2d8541be 100644 --- a/PS4Parser.h +++ b/PS4Parser.h @@ -68,8 +68,8 @@ union PS4Buttons { uint8_t touchpad : 1; uint8_t reportCounter : 6; } __attribute__((packed)); - uint8_t val[3]; -}; + uint32_t val : 24; +} __attribute__((packed)); struct touchpadXY { uint8_t dummy; // I can not figure out what this data is for, it seems to change randomly, maybe a timestamp? @@ -326,11 +326,9 @@ protected: void Reset() { uint8_t i; for (i = 0; i < sizeof(ps4Data.hatValue); i++) - ps4Data.hatValue[i] = 127; - for (i = 0; i < sizeof(PS4Buttons); i++) { - ps4Data.btn.val[i] = 0; - oldButtonState.val[i] = 0; - } + ps4Data.hatValue[i] = 127; // Center value + ps4Data.btn.val = 0; + oldButtonState.val = 0; for (i = 0; i < sizeof(ps4Data.trigger); i++) ps4Data.trigger[i] = 0; for (i = 0; i < sizeof(ps4Data.xy)/sizeof(ps4Data.xy[0]); i++) { From 37d59a63b252ccf370397d5d59a8f5746ef8b5e3 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 17 Feb 2014 17:39:15 +0100 Subject: [PATCH 29/42] bigRumble and smallRumble values were swapped --- PS4BT.h | 4 ++-- PS4Parser.h | 4 ++-- PS4USB.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/PS4BT.h b/PS4BT.h index 85d70f48..3c0aae12 100644 --- a/PS4BT.h +++ b/PS4BT.h @@ -96,8 +96,8 @@ protected: buf[2] = 0x80; buf[4]= 0xFF; - buf[7] = output->bigRumble; // Big Rumble - buf[8] = output->smallRumble; // Small rumble + buf[7] = output->smallRumble; // Small Rumble + buf[8] = output->bigRumble; // Big rumble buf[9] = output->r; // Red buf[10] = output->g; // Green diff --git a/PS4Parser.h b/PS4Parser.h index 2d8541be..093701e9 100644 --- a/PS4Parser.h +++ b/PS4Parser.h @@ -262,9 +262,9 @@ public: */ void setRumbleOn(RumbleEnum mode) { if (mode == RumbleLow) - setRumbleOn(0xFF, 0x00); - else setRumbleOn(0x00, 0xFF); + else + setRumbleOn(0xFF, 0x00); }; /** diff --git a/PS4USB.h b/PS4USB.h index 019ea930..ea38455a 100644 --- a/PS4USB.h +++ b/PS4USB.h @@ -94,8 +94,8 @@ protected: buf[0] = 0x05; // Report ID buf[1]= 0xFF; - buf[4] = output->bigRumble; // Big Rumble - buf[5] = output->smallRumble; // Small rumble + buf[4] = output->smallRumble; // Small Rumble + buf[5] = output->bigRumble; // Big rumble buf[6] = output->r; // Red buf[7] = output->g; // Green From 39b6c3b124f95edbd173d0cb7ef7462aa9be5dbc Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Tue, 25 Feb 2014 11:47:59 +0100 Subject: [PATCH 30/42] Added support for the Arduino Due Untested --- UsbCore.h | 2 +- avrpins.h | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++- settings.h | 9 ++++++--- usbhost.h | 36 +++++++++++++++++++++++++++++------ 4 files changed, 91 insertions(+), 11 deletions(-) diff --git a/UsbCore.h b/UsbCore.h index 9a09d804..444700a6 100644 --- a/UsbCore.h +++ b/UsbCore.h @@ -24,7 +24,7 @@ typedef MAX3421e MAX3421E; // Arduino Mega ADK #elif defined(ARDUINO_AVR_BALANDUINO) typedef MAX3421e MAX3421E; // Balanduino #else -typedef MAX3421e MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo etc.) or Teensy 2.0 and 3.0 +typedef MAX3421e MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo, Due etc.) or Teensy 2.0 and 3.0 #endif /* Common setup data constant combinations */ diff --git a/avrpins.h b/avrpins.h index bdc99ba6..2bfcdc10 100644 --- a/avrpins.h +++ b/avrpins.h @@ -749,11 +749,13 @@ public: #endif // __AVR__ -#if defined(__arm__) && defined(CORE_TEENSY) +#if defined(__arm__) // pointers are 32 bits on ARM #define pgm_read_pointer(p) pgm_read_dword(p) +#if defined(CORE_TEENSY) && (defined(__MK20DX128__) || defined(__MK20DX256__)) + #include "core_pins.h" #include "avr_emulation.h" @@ -819,6 +821,57 @@ MAKE_PIN(P33, CORE_PIN33_PORTREG, CORE_PIN33_BIT, CORE_PIN33_CONFIG); #undef MAKE_PIN +#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__) + +// Disable interrupts +// Enable the pull up resistor +// Set to INPUT +// Enable PIO + +// Disable interrupts +// Disable the pull up resistor +// Set to OUTPUT +// Enable PIO + +#define MAKE_PIN(className, baseReg, pinMask) \ +class className { \ +public: \ + static void Set() { \ + baseReg->PIO_SODR = pinMask; \ + } \ + static void Clear() { \ + baseReg->PIO_CODR = pinMask; \ + } \ + static void SetDirRead() { \ + baseReg->PIO_IDR = pinMask ; \ + baseReg->PIO_PUER = pinMask; \ + baseReg->PIO_ODR = pinMask; \ + baseReg->PIO_PER = pinMask; \ + } \ + static void SetDirWrite() { \ + baseReg->PIO_IDR = pinMask ; \ + baseReg->PIO_PUDR = pinMask; \ + baseReg->PIO_OER = pinMask; \ + baseReg->PIO_PER = pinMask; \ + } \ + static uint8_t IsSet() { \ + return baseReg->PIO_PDSR & pinMask; \ + } \ +}; + +MAKE_PIN(P9, PIOC, PIO_PC21); // INT +MAKE_PIN(P10, PIOC, PIO_PC29); // SS +MAKE_PIN(P74, PIOA, PIO_PA25); // MISO +MAKE_PIN(P75, PIOA, PIO_PA26); // MOSI +MAKE_PIN(P76, PIOA, PIO_PA27); // CLK + +#undef MAKE_PIN + +#else +#error "Please define board in avrpins.h" + +#endif + #endif // __arm__ #endif //_avrpins_h_ diff --git a/settings.h b/settings.h index 424a5bcf..c6d78ad4 100644 --- a/settings.h +++ b/settings.h @@ -68,7 +68,6 @@ // No user serviceable parts below this line. // DO NOT change anything below here unless you are a developer! -// When will we drop support for the older bug-ridden stuff? #if defined(ARDUINO) && ARDUINO >=100 #include #else @@ -79,7 +78,7 @@ #define F(str) (str) #endif -#ifdef __GNUC__ +#if defined(__GNUC__) && defined(__AVR__) #ifndef GCC_VERSION #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #endif @@ -110,10 +109,14 @@ #define XMEM_RELEASE_SPI() (void(0)) #endif -#if defined(__MK20DX128__) || defined(__MK20DX256__) +#if defined(CORE_TEENSY) && (defined(__MK20DX128__) || defined(__MK20DX256__)) #define USING_SPI4TEENSY3 USE_SPI4TEENSY3 #else #define USING_SPI4TEENSY3 0 #endif +#if defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__) +#include // Use the Arduino SPI library for the Arduino Due +#endif + #endif /* SETTINGS_H */ diff --git a/usbhost.h b/usbhost.h index adfff592..e5cd4188 100644 --- a/usbhost.h +++ b/usbhost.h @@ -29,9 +29,8 @@ e-mail : support@circuitsathome.com /* SPI initialization */ template< typename SPI_CLK, typename SPI_MOSI, typename SPI_MISO, typename SPI_SS > class SPi { -#if USING_SPI4TEENSY3 public: - +#if USING_SPI4TEENSY3 static void init() { // spi4teensy3 inits everything for us, except /SS // CLK, MOSI and MISO are hard coded for now. @@ -40,10 +39,13 @@ public: SPI_SS::SetDirWrite(); SPI_SS::Set(); } - +#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__) + static void init() { + SPI_SS::SetDirWrite(); + SPI_SS::Set(); + SPI.begin(); + } #else -public: - static void init() { //uint8_t tmp; SPI_CLK::SetDirWrite(); @@ -67,8 +69,10 @@ typedef SPi< Pb1, Pb2, Pb3, Pb0 > spi; typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi; #elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) typedef SPi< Pb7, Pb5, Pb6, Pb4 > spi; -#elif defined(__MK20DX128__) || defined(__MK20DX256__) +#elif defined(CORE_TEENSY) && (defined(__MK20DX128__) || defined(__MK20DX256__)) typedef SPi< P13, P11, P12, P10 > spi; +#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__) +typedef SPi< P76, P75, P74, P10 > spi; #else #error "No SPI entry in usbhost.h" #endif @@ -130,6 +134,9 @@ void MAX3421e< SPI_SS, INTR >::regWr(uint8_t reg, uint8_t data) { c[0] = reg | 0x02; c[1] = data; spi4teensy3::send(c, 2); +#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__) + SPI.transfer(reg | 0x02); + SPI.transfer(data); #else SPDR = (reg | 0x02); while(!(SPSR & (1 << SPIF))); @@ -151,6 +158,13 @@ uint8_t* MAX3421e< SPI_SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* spi4teensy3::send(reg | 0x02); spi4teensy3::send(data_p, nbytes); data_p += nbytes; +#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__) + SPI.transfer(reg | 0x02); + while(nbytes) { + SPI.transfer(*data_p); + nbytes--; + data_p++; // advance data pointer + } #else SPDR = (reg | 0x02); //set WR bit and send register number while(nbytes) { @@ -186,6 +200,10 @@ uint8_t MAX3421e< SPI_SS, INTR >::regRd(uint8_t reg) { spi4teensy3::send(reg); uint8_t rv = spi4teensy3::receive(); SPI_SS::Set(); +#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__) + SPI.transfer(reg); + uint8_t rv = SPI.transfer(0); + SPI_SS::Set(); #else SPDR = reg; while(!(SPSR & (1 << SPIF))); @@ -208,6 +226,12 @@ uint8_t* MAX3421e< SPI_SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* spi4teensy3::send(reg); spi4teensy3::receive(data_p, nbytes); data_p += nbytes; +#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__) + SPI.transfer(reg); + while(nbytes) { + *data_p++ = SPI.transfer(0); + nbytes--; + } #else SPDR = reg; while(!(SPSR & (1 << SPIF))); //wait From a24ecb57977e8aad850b7aed635c65b8e9397fc1 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Tue, 25 Feb 2014 19:32:49 +0100 Subject: [PATCH 31/42] Updated readme and some comments --- README.md | 5 +++-- avrpins.h | 18 ++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 56152496..80715680 100644 --- a/README.md +++ b/README.md @@ -66,8 +66,9 @@ By default serial debugging is disabled. To turn it on simply change ```ENABLE_U Currently the following boards are supported by the library: * All official Arduino AVR boards (Uno, Duemilanove, Mega, Mega 2560, Mega ADK, Leonardo etc.) -* Teensy (Teensy++ 1.0, Teensy 2.0, Teensy++ 2.0, and Teensy 3.0) - * Note if you are using the Teensy 3.0 you should download this SPI library as well: . You should then add ```#include ``` to your .ino file. +* Arduino Due +* Teensy (Teensy++ 1.0, Teensy 2.0, Teensy++ 2.0, and Teensy 3.x) + * Note if you are using the Teensy 3.x you should download this SPI library as well: . You should then add ```#include ``` to your .ino file. * Balanduino * Sanguino * Black Widdow diff --git a/avrpins.h b/avrpins.h index 2bfcdc10..e75042b2 100644 --- a/avrpins.h +++ b/avrpins.h @@ -823,15 +823,17 @@ MAKE_PIN(P33, CORE_PIN33_PORTREG, CORE_PIN33_BIT, CORE_PIN33_CONFIG); #elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__) -// Disable interrupts -// Enable the pull up resistor -// Set to INPUT -// Enable PIO +// SetDirRead: +// Disable interrupts +// Enable the pull up resistor +// Set to INPUT +// Enable PIO -// Disable interrupts -// Disable the pull up resistor -// Set to OUTPUT -// Enable PIO +// SetDirWrite: +// Disable interrupts +// Disable the pull up resistor +// Set to OUTPUT +// Enable PIO #define MAKE_PIN(className, baseReg, pinMask) \ class className { \ From 983a7d664fc5b89732e2dcfe75680684d1706270 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Tue, 25 Feb 2014 19:37:57 +0100 Subject: [PATCH 32/42] Added getLastMessageTime() - this is useful if you want to detect if the connection is lost with the PS3 controller Credit: Thomas Frederick --- PS3BT.cpp | 2 ++ PS3BT.h | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/PS3BT.cpp b/PS3BT.cpp index ba531c26..80b6dc3f 100644 --- a/PS3BT.cpp +++ b/PS3BT.cpp @@ -343,6 +343,8 @@ void PS3BT::ACLData(uint8_t* ACLData) { if(PS3Connected || PS3MoveConnected || PS3NavigationConnected) { /* Read Report */ if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT + lastMessageTime = millis(); // Store the last message time + if(PS3Connected || PS3NavigationConnected) ButtonState = (uint32_t)(l2capinbuf[11] | ((uint16_t)l2capinbuf[12] << 8) | ((uint32_t)l2capinbuf[13] << 16)); else if(PS3MoveConnected) diff --git a/PS3BT.h b/PS3BT.h index 7291c092..d07a4577 100644 --- a/PS3BT.h +++ b/PS3BT.h @@ -179,6 +179,11 @@ public: */ void moveSetRumble(uint8_t rumble); + /** Used to get the millis() of the last message */ + uint32_t getLastMessageTime() { + return lastMessageTime; + }; + /** * Used to call your own function when the controller is successfully initialized. * @param funcOnInit Function to call. @@ -214,10 +219,12 @@ private: uint8_t remote_name[30]; // First 30 chars of remote name bool activeConnection; // Used to indicate if it's already has established a connection - /* variables used by high level L2CAP task */ + /* Variables used by high level L2CAP task */ uint8_t l2cap_state; uint32_t l2cap_event_flag; // L2CAP flags of received Bluetooth events + uint32_t lastMessageTime; // Variable used to store the millis value of the last message. + unsigned long timer; uint32_t ButtonState; From ce81146f2b58fded9e08371fc2b3cbbcd8c57c5f Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Wed, 26 Feb 2014 23:43:40 +0100 Subject: [PATCH 33/42] Disable pull up resistor when using input on the Due --- avrpins.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/avrpins.h b/avrpins.h index e75042b2..d013851a 100644 --- a/avrpins.h +++ b/avrpins.h @@ -825,7 +825,7 @@ MAKE_PIN(P33, CORE_PIN33_PORTREG, CORE_PIN33_BIT, CORE_PIN33_CONFIG); // SetDirRead: // Disable interrupts -// Enable the pull up resistor +// Disable the pull up resistor // Set to INPUT // Enable PIO @@ -846,7 +846,7 @@ public: \ } \ static void SetDirRead() { \ baseReg->PIO_IDR = pinMask ; \ - baseReg->PIO_PUER = pinMask; \ + baseReg->PIO_PUDR = pinMask; \ baseReg->PIO_ODR = pinMask; \ baseReg->PIO_PER = pinMask; \ } \ From f8379baffea82490374c44cea7c8363704f28a5b Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Wed, 26 Feb 2014 23:46:21 +0100 Subject: [PATCH 34/42] Changed variable name from baseReg to pio --- avrpins.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/avrpins.h b/avrpins.h index d013851a..6e074b65 100644 --- a/avrpins.h +++ b/avrpins.h @@ -835,29 +835,29 @@ MAKE_PIN(P33, CORE_PIN33_PORTREG, CORE_PIN33_BIT, CORE_PIN33_CONFIG); // Set to OUTPUT // Enable PIO -#define MAKE_PIN(className, baseReg, pinMask) \ +#define MAKE_PIN(className, pio, pinMask) \ class className { \ public: \ static void Set() { \ - baseReg->PIO_SODR = pinMask; \ + pio->PIO_SODR = pinMask; \ } \ static void Clear() { \ - baseReg->PIO_CODR = pinMask; \ + pio->PIO_CODR = pinMask; \ } \ static void SetDirRead() { \ - baseReg->PIO_IDR = pinMask ; \ - baseReg->PIO_PUDR = pinMask; \ - baseReg->PIO_ODR = pinMask; \ - baseReg->PIO_PER = pinMask; \ + pio->PIO_IDR = pinMask ; \ + pio->PIO_PUDR = pinMask; \ + pio->PIO_ODR = pinMask; \ + pio->PIO_PER = pinMask; \ } \ static void SetDirWrite() { \ - baseReg->PIO_IDR = pinMask ; \ - baseReg->PIO_PUDR = pinMask; \ - baseReg->PIO_OER = pinMask; \ - baseReg->PIO_PER = pinMask; \ + pio->PIO_IDR = pinMask ; \ + pio->PIO_PUDR = pinMask; \ + pio->PIO_OER = pinMask; \ + pio->PIO_PER = pinMask; \ } \ static uint8_t IsSet() { \ - return baseReg->PIO_PDSR & pinMask; \ + return pio->PIO_PDSR & pinMask; \ } \ }; From d8cadc5744e4483ce2161f8fd0c163483e12a997 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Sun, 2 Mar 2014 16:35:16 +0100 Subject: [PATCH 35/42] Increase SPI speed on the Due to 21MHz --- usbhost.h | 1 + 1 file changed, 1 insertion(+) diff --git a/usbhost.h b/usbhost.h index e5cd4188..172742e5 100644 --- a/usbhost.h +++ b/usbhost.h @@ -44,6 +44,7 @@ public: SPI_SS::SetDirWrite(); SPI_SS::Set(); SPI.begin(); + SPI.setClockDivider(BOARD_SPI_DEFAULT_SS, 4); // Set speed to 84MHz/4=21MHz - the MAX3421E can handle up to 26MHz } #else static void init() { From 76b1c3fb323c5ccbf00199fa8e71aa84e3a6da15 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Mon, 3 Mar 2014 02:59:09 +0100 Subject: [PATCH 36/42] Added some syntax highlighting in the readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 80715680..b964c548 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Documentation for the library can be found at the following link: Date: Thu, 6 Mar 2014 19:25:35 +0100 Subject: [PATCH 37/42] Added information about the need to include the Arduino SPI library when using the Due --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b964c548..85ef87c7 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ By default serial debugging is disabled. To turn it on simply change ```ENABLE_U Currently the following boards are supported by the library: * All official Arduino AVR boards (Uno, Duemilanove, Mega, Mega 2560, Mega ADK, Leonardo etc.) + * If you are using the Arduino Due, then you must include the Arduino SPI library as well like so: ```#include ``` to your .ino file. * Arduino Due * Teensy (Teensy++ 1.0, Teensy 2.0, Teensy++ 2.0, and Teensy 3.x) * Note if you are using the Teensy 3.x you should download this SPI library as well: . You should then add ```#include ``` to your .ino file. From a0661ef244d5d5fae8946236ba806de370a7aeb1 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Thu, 6 Mar 2014 19:32:17 +0100 Subject: [PATCH 38/42] Typo correction --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 85ef87c7..647a69a9 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ By default serial debugging is disabled. To turn it on simply change ```ENABLE_U Currently the following boards are supported by the library: * All official Arduino AVR boards (Uno, Duemilanove, Mega, Mega 2560, Mega ADK, Leonardo etc.) - * If you are using the Arduino Due, then you must include the Arduino SPI library as well like so: ```#include ``` to your .ino file. + * If you are using the Arduino Due, then you must include the Arduino SPI library like so: ```#include ``` in your .ino file. * Arduino Due * Teensy (Teensy++ 1.0, Teensy 2.0, Teensy++ 2.0, and Teensy 3.x) * Note if you are using the Teensy 3.x you should download this SPI library as well: . You should then add ```#include ``` to your .ino file. From bb9fef05dbebc6200243ee471ca1c1f2e124d7c1 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Thu, 6 Mar 2014 21:48:48 +0100 Subject: [PATCH 39/42] Typo once again --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 647a69a9..883c661e 100644 --- a/README.md +++ b/README.md @@ -66,8 +66,8 @@ By default serial debugging is disabled. To turn it on simply change ```ENABLE_U Currently the following boards are supported by the library: * All official Arduino AVR boards (Uno, Duemilanove, Mega, Mega 2560, Mega ADK, Leonardo etc.) - * If you are using the Arduino Due, then you must include the Arduino SPI library like so: ```#include ``` in your .ino file. * Arduino Due + * If you are using the Arduino Due, then you must include the Arduino SPI library like so: ```#include ``` in your .ino file. * Teensy (Teensy++ 1.0, Teensy 2.0, Teensy++ 2.0, and Teensy 3.x) * Note if you are using the Teensy 3.x you should download this SPI library as well: . You should then add ```#include ``` to your .ino file. * Balanduino From a042e5a8497f1457b39e38113b8b6a84aa643bb0 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Fri, 7 Mar 2014 02:12:39 +0100 Subject: [PATCH 40/42] Simplify how PS3 printStatusString prints the string --- PS3BT.cpp | 2 +- PS3USB.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PS3BT.cpp b/PS3BT.cpp index 80b6dc3f..38d6c3dc 100644 --- a/PS3BT.cpp +++ b/PS3BT.cpp @@ -201,7 +201,7 @@ void PS3BT::printStatusString() { } else strcpy_P(statusOutput, PSTR("Error")); - USB_HOST_SERIAL.write((uint8_t*)statusOutput, strlen(statusOutput)); + USB_HOST_SERIAL.write(statusOutput); } void PS3BT::Reset() { diff --git a/PS3USB.cpp b/PS3USB.cpp index fa865495..7e6285a2 100644 --- a/PS3USB.cpp +++ b/PS3USB.cpp @@ -392,7 +392,7 @@ void PS3USB::printStatusString() { } else strcpy_P(statusOutput, PSTR("Error")); - USB_HOST_SERIAL.write((uint8_t*)statusOutput, strlen(statusOutput)); + USB_HOST_SERIAL.write(statusOutput); } /* Playstation Sixaxis Dualshock and Navigation Controller commands */ From 1ebce9b87752331a61971602b08048e569cdaa41 Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Fri, 7 Mar 2014 02:17:47 +0100 Subject: [PATCH 41/42] Some files were missing copyright section --- UsbCore.h | 20 +++++++++++++++----- hid.cpp | 17 +++++++++++++++++ hidescriptorparser.cpp | 17 +++++++++++++++++ hiduniversal.cpp | 17 +++++++++++++++++ hiduniversal.h | 17 +++++++++++++++++ macros.h | 20 +++++++++++++++----- masstorage.cpp | 17 +++++++++++++++++ masstorage.h | 17 +++++++++++++++++ 8 files changed, 132 insertions(+), 10 deletions(-) diff --git a/UsbCore.h b/UsbCore.h index 6e6822d3..76d9d5ee 100644 --- a/UsbCore.h +++ b/UsbCore.h @@ -1,8 +1,18 @@ -/* - * File: UsbCore.h - * Author: xxxajk - * - * Created on September 29, 2013, 9:25 PM +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com */ #if !defined(_usb_h_) || defined(USBCORE_H) diff --git a/hid.cpp b/hid.cpp index c86f6b91..c3c425b8 100644 --- a/hid.cpp +++ b/hid.cpp @@ -1,3 +1,20 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + #include "hid.h" //get HID report descriptor diff --git a/hidescriptorparser.cpp b/hidescriptorparser.cpp index fd9d2d2d..f3040ce8 100644 --- a/hidescriptorparser.cpp +++ b/hidescriptorparser.cpp @@ -1,3 +1,20 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + #include "hidescriptorparser.h" const char * const ReportDescParserBase::usagePageTitles0[] PROGMEM = { diff --git a/hiduniversal.cpp b/hiduniversal.cpp index a2b4dc2e..c2f33533 100644 --- a/hiduniversal.cpp +++ b/hiduniversal.cpp @@ -1,3 +1,20 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + #include "hiduniversal.h" HIDUniversal::HIDUniversal(USB *p) : diff --git a/hiduniversal.h b/hiduniversal.h index d97f4b8c..3e090aa7 100644 --- a/hiduniversal.h +++ b/hiduniversal.h @@ -1,3 +1,20 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + #if !defined(__HIDUNIVERSAL_H__) #define __HIDUNIVERSAL_H__ diff --git a/macros.h b/macros.h index 1f56814a..51476830 100644 --- a/macros.h +++ b/macros.h @@ -1,8 +1,18 @@ -/* - * File: macros.h - * Author: AJK - * - * Created on September 23, 2013, 12:31 AM +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com */ #if !defined(_usb_h_) || defined(MACROS_H) diff --git a/masstorage.cpp b/masstorage.cpp index 19da7b19..41ee4258 100644 --- a/masstorage.cpp +++ b/masstorage.cpp @@ -1,3 +1,20 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + #include "masstorage.h" const uint8_t BulkOnly::epDataInIndex = 1; diff --git a/masstorage.h b/masstorage.h index eb042eac..176752fc 100644 --- a/masstorage.h +++ b/masstorage.h @@ -1,3 +1,20 @@ +/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. + +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 +------------------- + +Circuits At Home, LTD +Web : http://www.circuitsathome.com +e-mail : support@circuitsathome.com + */ + #if !defined(__MASSTORAGE_H__) #define __MASSTORAGE_H__ From 62f8cbbc2506d30110d9b9afabe993c45421bbfa Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Fri, 7 Mar 2014 02:19:34 +0100 Subject: [PATCH 42/42] Do not set SS pin for the Due Let the Arduino SPI library take care of that --- usbhost.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usbhost.h b/usbhost.h index 172742e5..cf26c1f0 100644 --- a/usbhost.h +++ b/usbhost.h @@ -44,7 +44,7 @@ public: SPI_SS::SetDirWrite(); SPI_SS::Set(); SPI.begin(); - SPI.setClockDivider(BOARD_SPI_DEFAULT_SS, 4); // Set speed to 84MHz/4=21MHz - the MAX3421E can handle up to 26MHz + SPI.setClockDivider(4); // Set speed to 84MHz/4=21MHz - the MAX3421E can handle up to 26MHz } #else static void init() {