From 2a1db31cf13551528390e02640b38f101ba576ce Mon Sep 17 00:00:00 2001 From: Kristian Lauszus Date: Wed, 22 Jan 2014 05:13:49 +0100 Subject: [PATCH] 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")); + } + } + } } } }