Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
USB_Host/PS3BT.cpp@0:b1ce54272580, 2020-01-18 (annotated)
- Committer:
- kotakku
- Date:
- Sat Jan 18 15:06:35 2020 +0000
- Revision:
- 0:b1ce54272580
1.0.0 first commit
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| kotakku | 0:b1ce54272580 | 1 | /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved. |
| kotakku | 0:b1ce54272580 | 2 | |
| kotakku | 0:b1ce54272580 | 3 | This software may be distributed and modified under the terms of the GNU |
| kotakku | 0:b1ce54272580 | 4 | General Public License version 2 (GPL2) as published by the Free Software |
| kotakku | 0:b1ce54272580 | 5 | Foundation and appearing in the file GPL2.TXT included in the packaging of |
| kotakku | 0:b1ce54272580 | 6 | this file. Please note that GPL2 Section 2[b] requires that all works based |
| kotakku | 0:b1ce54272580 | 7 | on this software must also be made publicly available under the terms of |
| kotakku | 0:b1ce54272580 | 8 | the GPL2 ("Copyleft"). |
| kotakku | 0:b1ce54272580 | 9 | |
| kotakku | 0:b1ce54272580 | 10 | Contact information |
| kotakku | 0:b1ce54272580 | 11 | ------------------- |
| kotakku | 0:b1ce54272580 | 12 | |
| kotakku | 0:b1ce54272580 | 13 | Kristian Lauszus, TKJ Electronics |
| kotakku | 0:b1ce54272580 | 14 | Web : http://www.tkjelectronics.com |
| kotakku | 0:b1ce54272580 | 15 | e-mail : kristianl@tkjelectronics.com |
| kotakku | 0:b1ce54272580 | 16 | */ |
| kotakku | 0:b1ce54272580 | 17 | |
| kotakku | 0:b1ce54272580 | 18 | #include "PS3BT.h" |
| kotakku | 0:b1ce54272580 | 19 | // To enable serial debugging see "settings.h" |
| kotakku | 0:b1ce54272580 | 20 | //#define EXTRADEBUG // Uncomment to get even more debugging data |
| kotakku | 0:b1ce54272580 | 21 | //#define PRINTREPORT // Uncomment to print the report send by the PS3 Controllers |
| kotakku | 0:b1ce54272580 | 22 | |
| kotakku | 0:b1ce54272580 | 23 | PS3BT::PS3BT(BTD *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0) : |
| kotakku | 0:b1ce54272580 | 24 | BluetoothService(p) // Pointer to USB class instance - mandatory |
| kotakku | 0:b1ce54272580 | 25 | { |
| kotakku | 0:b1ce54272580 | 26 | pBtd->my_bdaddr[5] = btadr5; // Change to your dongle's Bluetooth address instead |
| kotakku | 0:b1ce54272580 | 27 | pBtd->my_bdaddr[4] = btadr4; |
| kotakku | 0:b1ce54272580 | 28 | pBtd->my_bdaddr[3] = btadr3; |
| kotakku | 0:b1ce54272580 | 29 | pBtd->my_bdaddr[2] = btadr2; |
| kotakku | 0:b1ce54272580 | 30 | pBtd->my_bdaddr[1] = btadr1; |
| kotakku | 0:b1ce54272580 | 31 | pBtd->my_bdaddr[0] = btadr0; |
| kotakku | 0:b1ce54272580 | 32 | |
| kotakku | 0:b1ce54272580 | 33 | HIDBuffer[0] = 0x52; // HID BT Set_report (0x50) | Report Type (Output 0x02) |
| kotakku | 0:b1ce54272580 | 34 | HIDBuffer[1] = 0x01; // Report ID |
| kotakku | 0:b1ce54272580 | 35 | |
| kotakku | 0:b1ce54272580 | 36 | // Needed for PS3 Move Controller commands to work via bluetooth |
| kotakku | 0:b1ce54272580 | 37 | HIDMoveBuffer[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02) |
| kotakku | 0:b1ce54272580 | 38 | HIDMoveBuffer[1] = 0x02; // Report ID |
| kotakku | 0:b1ce54272580 | 39 | |
| kotakku | 0:b1ce54272580 | 40 | /* Set device cid for the control and intterrupt channelse - LSB */ |
| kotakku | 0:b1ce54272580 | 41 | control_dcid[0] = 0x40; // 0x0040 |
| kotakku | 0:b1ce54272580 | 42 | control_dcid[1] = 0x00; |
| kotakku | 0:b1ce54272580 | 43 | interrupt_dcid[0] = 0x41; // 0x0041 |
| kotakku | 0:b1ce54272580 | 44 | interrupt_dcid[1] = 0x00; |
| kotakku | 0:b1ce54272580 | 45 | |
| kotakku | 0:b1ce54272580 | 46 | Reset(); |
| kotakku | 0:b1ce54272580 | 47 | } |
| kotakku | 0:b1ce54272580 | 48 | |
| kotakku | 0:b1ce54272580 | 49 | bool PS3BT::getButtonPress(ButtonEnum b) { |
| kotakku | 0:b1ce54272580 | 50 | return (ButtonState & pgm_read_dword(&PS3_BUTTONS[(uint8_t)b])); |
| kotakku | 0:b1ce54272580 | 51 | } |
| kotakku | 0:b1ce54272580 | 52 | |
| kotakku | 0:b1ce54272580 | 53 | bool PS3BT::getButtonClick(ButtonEnum b) { |
| kotakku | 0:b1ce54272580 | 54 | uint32_t button = pgm_read_dword(&PS3_BUTTONS[(uint8_t)b]); |
| kotakku | 0:b1ce54272580 | 55 | bool click = (ButtonClickState & button); |
| kotakku | 0:b1ce54272580 | 56 | ButtonClickState &= ~button; // Clear "click" event |
| kotakku | 0:b1ce54272580 | 57 | return click; |
| kotakku | 0:b1ce54272580 | 58 | } |
| kotakku | 0:b1ce54272580 | 59 | |
| kotakku | 0:b1ce54272580 | 60 | uint8_t PS3BT::getAnalogButton(ButtonEnum a) { |
| kotakku | 0:b1ce54272580 | 61 | return (uint8_t)(l2capinbuf[pgm_read_byte(&PS3_ANALOG_BUTTONS[(uint8_t)a])]); |
| kotakku | 0:b1ce54272580 | 62 | } |
| kotakku | 0:b1ce54272580 | 63 | |
| kotakku | 0:b1ce54272580 | 64 | uint8_t PS3BT::getAnalogHat(AnalogHatEnum a) { |
| kotakku | 0:b1ce54272580 | 65 | return (uint8_t)(l2capinbuf[(uint8_t)a + 15]); |
| kotakku | 0:b1ce54272580 | 66 | } |
| kotakku | 0:b1ce54272580 | 67 | |
| kotakku | 0:b1ce54272580 | 68 | int16_t PS3BT::getSensor(SensorEnum a) { |
| kotakku | 0:b1ce54272580 | 69 | if(PS3Connected) { |
| kotakku | 0:b1ce54272580 | 70 | if(a == aX || a == aY || a == aZ || a == gZ) |
| kotakku | 0:b1ce54272580 | 71 | return ((l2capinbuf[(uint16_t)a] << 8) | l2capinbuf[(uint16_t)a + 1]); |
| kotakku | 0:b1ce54272580 | 72 | else |
| kotakku | 0:b1ce54272580 | 73 | return 0; |
| kotakku | 0:b1ce54272580 | 74 | } else if(PS3MoveConnected) { |
| kotakku | 0:b1ce54272580 | 75 | if(a == mXmove || a == mYmove) // These are all 12-bits long |
| kotakku | 0:b1ce54272580 | 76 | return (((l2capinbuf[(uint16_t)a] & 0x0F) << 8) | (l2capinbuf[(uint16_t)a + 1])); |
| kotakku | 0:b1ce54272580 | 77 | else if(a == mZmove || a == tempMove) // The tempearature is also 12 bits long |
| kotakku | 0:b1ce54272580 | 78 | return ((l2capinbuf[(uint16_t)a] << 4) | ((l2capinbuf[(uint16_t)a + 1] & 0xF0) >> 4)); |
| kotakku | 0:b1ce54272580 | 79 | else // aXmove, aYmove, aZmove, gXmove, gYmove and gZmove |
| kotakku | 0:b1ce54272580 | 80 | return (l2capinbuf[(uint16_t)a] | (l2capinbuf[(uint16_t)a + 1] << 8)); |
| kotakku | 0:b1ce54272580 | 81 | } else |
| kotakku | 0:b1ce54272580 | 82 | return 0; |
| kotakku | 0:b1ce54272580 | 83 | } |
| kotakku | 0:b1ce54272580 | 84 | |
| kotakku | 0:b1ce54272580 | 85 | float PS3BT::getAngle(AngleEnum a) { |
| kotakku | 0:b1ce54272580 | 86 | float accXval, accYval, accZval; |
| kotakku | 0:b1ce54272580 | 87 | |
| kotakku | 0:b1ce54272580 | 88 | if(PS3Connected) { |
| kotakku | 0:b1ce54272580 | 89 | // Data for the Kionix KXPC4 used in the DualShock 3 |
| kotakku | 0:b1ce54272580 | 90 | const float zeroG = 511.5f; // 1.65/3.3*1023 (1.65V) |
| kotakku | 0:b1ce54272580 | 91 | accXval = -((float)getSensor(aX) - zeroG); |
| kotakku | 0:b1ce54272580 | 92 | accYval = -((float)getSensor(aY) - zeroG); |
| kotakku | 0:b1ce54272580 | 93 | accZval = -((float)getSensor(aZ) - zeroG); |
| kotakku | 0:b1ce54272580 | 94 | } else if(PS3MoveConnected) { |
| kotakku | 0:b1ce54272580 | 95 | // It's a Kionix KXSC4 inside the Motion controller |
| kotakku | 0:b1ce54272580 | 96 | const uint16_t zeroG = 0x8000; |
| kotakku | 0:b1ce54272580 | 97 | accXval = -(int16_t)(getSensor(aXmove) - zeroG); |
| kotakku | 0:b1ce54272580 | 98 | accYval = (int16_t)(getSensor(aYmove) - zeroG); |
| kotakku | 0:b1ce54272580 | 99 | accZval = (int16_t)(getSensor(aZmove) - zeroG); |
| kotakku | 0:b1ce54272580 | 100 | } else |
| kotakku | 0:b1ce54272580 | 101 | return 0; |
| kotakku | 0:b1ce54272580 | 102 | |
| kotakku | 0:b1ce54272580 | 103 | // Convert to 360 degrees resolution |
| kotakku | 0:b1ce54272580 | 104 | // atan2 outputs the value of -π to π (radians) |
| kotakku | 0:b1ce54272580 | 105 | // We are then converting it to 0 to 2π and then to degrees |
| kotakku | 0:b1ce54272580 | 106 | if(a == Pitch) |
| kotakku | 0:b1ce54272580 | 107 | return (atan2f(accYval, accZval) + PI) * RAD_TO_DEG; |
| kotakku | 0:b1ce54272580 | 108 | else |
| kotakku | 0:b1ce54272580 | 109 | return (atan2f(accXval, accZval) + PI) * RAD_TO_DEG; |
| kotakku | 0:b1ce54272580 | 110 | } |
| kotakku | 0:b1ce54272580 | 111 | |
| kotakku | 0:b1ce54272580 | 112 | float PS3BT::get9DOFValues(SensorEnum a) { // Thanks to Manfred Piendl |
| kotakku | 0:b1ce54272580 | 113 | if(!PS3MoveConnected) |
| kotakku | 0:b1ce54272580 | 114 | return 0; |
| kotakku | 0:b1ce54272580 | 115 | int16_t value = getSensor(a); |
| kotakku | 0:b1ce54272580 | 116 | if(a == mXmove || a == mYmove || a == mZmove) { |
| kotakku | 0:b1ce54272580 | 117 | if(value > 2047) |
| kotakku | 0:b1ce54272580 | 118 | value -= 0x1000; |
| kotakku | 0:b1ce54272580 | 119 | return (float)value / 3.2f; // unit: muT = 10^(-6) Tesla |
| kotakku | 0:b1ce54272580 | 120 | } else if(a == aXmove || a == aYmove || a == aZmove) { |
| kotakku | 0:b1ce54272580 | 121 | if(value < 0) |
| kotakku | 0:b1ce54272580 | 122 | value += 0x8000; |
| kotakku | 0:b1ce54272580 | 123 | else |
| kotakku | 0:b1ce54272580 | 124 | value -= 0x8000; |
| kotakku | 0:b1ce54272580 | 125 | return (float)value / 442.0f; // unit: m/(s^2) |
| kotakku | 0:b1ce54272580 | 126 | } else if(a == gXmove || a == gYmove || a == gZmove) { |
| kotakku | 0:b1ce54272580 | 127 | if(value < 0) |
| kotakku | 0:b1ce54272580 | 128 | value += 0x8000; |
| kotakku | 0:b1ce54272580 | 129 | else |
| kotakku | 0:b1ce54272580 | 130 | value -= 0x8000; |
| kotakku | 0:b1ce54272580 | 131 | if(a == gXmove) |
| kotakku | 0:b1ce54272580 | 132 | return (float)value / 11.6f; // unit: deg/s |
| kotakku | 0:b1ce54272580 | 133 | else if(a == gYmove) |
| kotakku | 0:b1ce54272580 | 134 | return (float)value / 11.2f; // unit: deg/s |
| kotakku | 0:b1ce54272580 | 135 | else // gZmove |
| kotakku | 0:b1ce54272580 | 136 | return (float)value / 9.6f; // unit: deg/s |
| kotakku | 0:b1ce54272580 | 137 | } else |
| kotakku | 0:b1ce54272580 | 138 | return 0; |
| kotakku | 0:b1ce54272580 | 139 | } |
| kotakku | 0:b1ce54272580 | 140 | |
| kotakku | 0:b1ce54272580 | 141 | String PS3BT::getTemperature() { |
| kotakku | 0:b1ce54272580 | 142 | if(PS3MoveConnected) { |
| kotakku | 0:b1ce54272580 | 143 | int16_t input = getSensor(tempMove); |
| kotakku | 0:b1ce54272580 | 144 | |
| kotakku | 0:b1ce54272580 | 145 | String output = String(input / 100); |
| kotakku | 0:b1ce54272580 | 146 | output += "."; |
| kotakku | 0:b1ce54272580 | 147 | if(input % 100 < 10) |
| kotakku | 0:b1ce54272580 | 148 | output += "0"; |
| kotakku | 0:b1ce54272580 | 149 | output += String(input % 100); |
| kotakku | 0:b1ce54272580 | 150 | |
| kotakku | 0:b1ce54272580 | 151 | return output; |
| kotakku | 0:b1ce54272580 | 152 | } else |
| kotakku | 0:b1ce54272580 | 153 | return "Error"; |
| kotakku | 0:b1ce54272580 | 154 | } |
| kotakku | 0:b1ce54272580 | 155 | |
| kotakku | 0:b1ce54272580 | 156 | bool PS3BT::getStatus(StatusEnum c) { |
| kotakku | 0:b1ce54272580 | 157 | return (l2capinbuf[(uint16_t)c >> 8] == ((uint8_t)c & 0xff)); |
| kotakku | 0:b1ce54272580 | 158 | } |
| kotakku | 0:b1ce54272580 | 159 | |
| kotakku | 0:b1ce54272580 | 160 | void PS3BT::printStatusString() { |
| kotakku | 0:b1ce54272580 | 161 | char statusOutput[102]; // Max string length plus null character |
| kotakku | 0:b1ce54272580 | 162 | if(PS3Connected || PS3NavigationConnected) { |
| kotakku | 0:b1ce54272580 | 163 | strcpy_P(statusOutput, PSTR("\r\nConnectionStatus: ")); |
| kotakku | 0:b1ce54272580 | 164 | |
| kotakku | 0:b1ce54272580 | 165 | if(getStatus(Plugged)) strcat_P(statusOutput, PSTR("Plugged")); |
| kotakku | 0:b1ce54272580 | 166 | else if(getStatus(Unplugged)) strcat_P(statusOutput, PSTR("Unplugged")); |
| kotakku | 0:b1ce54272580 | 167 | else strcat_P(statusOutput, PSTR("Error")); |
| kotakku | 0:b1ce54272580 | 168 | |
| kotakku | 0:b1ce54272580 | 169 | strcat_P(statusOutput, PSTR(" - PowerRating: ")); |
| kotakku | 0:b1ce54272580 | 170 | |
| kotakku | 0:b1ce54272580 | 171 | if(getStatus(Charging)) strcat_P(statusOutput, PSTR("Charging")); |
| kotakku | 0:b1ce54272580 | 172 | else if(getStatus(NotCharging)) strcat_P(statusOutput, PSTR("Not Charging")); |
| kotakku | 0:b1ce54272580 | 173 | else if(getStatus(Shutdown)) strcat_P(statusOutput, PSTR("Shutdown")); |
| kotakku | 0:b1ce54272580 | 174 | else if(getStatus(Dying)) strcat_P(statusOutput, PSTR("Dying")); |
| kotakku | 0:b1ce54272580 | 175 | else if(getStatus(Low)) strcat_P(statusOutput, PSTR("Low")); |
| kotakku | 0:b1ce54272580 | 176 | else if(getStatus(High)) strcat_P(statusOutput, PSTR("High")); |
| kotakku | 0:b1ce54272580 | 177 | else if(getStatus(Full)) strcat_P(statusOutput, PSTR("Full")); |
| kotakku | 0:b1ce54272580 | 178 | else strcat_P(statusOutput, PSTR("Error")); |
| kotakku | 0:b1ce54272580 | 179 | |
| kotakku | 0:b1ce54272580 | 180 | strcat_P(statusOutput, PSTR(" - WirelessStatus: ")); |
| kotakku | 0:b1ce54272580 | 181 | |
| kotakku | 0:b1ce54272580 | 182 | if(getStatus(CableRumble)) strcat_P(statusOutput, PSTR("Cable - Rumble is on")); |
| kotakku | 0:b1ce54272580 | 183 | else if(getStatus(Cable)) strcat_P(statusOutput, PSTR("Cable - Rumble is off")); |
| kotakku | 0:b1ce54272580 | 184 | else if(getStatus(BluetoothRumble)) strcat_P(statusOutput, PSTR("Bluetooth - Rumble is on")); |
| kotakku | 0:b1ce54272580 | 185 | else if(getStatus(Bluetooth)) strcat_P(statusOutput, PSTR("Bluetooth - Rumble is off")); |
| kotakku | 0:b1ce54272580 | 186 | else strcat_P(statusOutput, PSTR("Error")); |
| kotakku | 0:b1ce54272580 | 187 | } else if(PS3MoveConnected) { |
| kotakku | 0:b1ce54272580 | 188 | strcpy_P(statusOutput, PSTR("\r\nPowerRating: ")); |
| kotakku | 0:b1ce54272580 | 189 | |
| kotakku | 0:b1ce54272580 | 190 | if(getStatus(MoveCharging)) strcat_P(statusOutput, PSTR("Charging")); |
| kotakku | 0:b1ce54272580 | 191 | else if(getStatus(MoveNotCharging)) strcat_P(statusOutput, PSTR("Not Charging")); |
| kotakku | 0:b1ce54272580 | 192 | else if(getStatus(MoveShutdown)) strcat_P(statusOutput, PSTR("Shutdown")); |
| kotakku | 0:b1ce54272580 | 193 | else if(getStatus(MoveDying)) strcat_P(statusOutput, PSTR("Dying")); |
| kotakku | 0:b1ce54272580 | 194 | else if(getStatus(MoveLow)) strcat_P(statusOutput, PSTR("Low")); |
| kotakku | 0:b1ce54272580 | 195 | else if(getStatus(MoveHigh)) strcat_P(statusOutput, PSTR("High")); |
| kotakku | 0:b1ce54272580 | 196 | else if(getStatus(MoveFull)) strcat_P(statusOutput, PSTR("Full")); |
| kotakku | 0:b1ce54272580 | 197 | else strcat_P(statusOutput, PSTR("Error")); |
| kotakku | 0:b1ce54272580 | 198 | } else |
| kotakku | 0:b1ce54272580 | 199 | strcpy_P(statusOutput, PSTR("\r\nError")); |
| kotakku | 0:b1ce54272580 | 200 | |
| kotakku | 0:b1ce54272580 | 201 | //USB_HOST_SERIAL.write(statusOutput); |
| kotakku | 0:b1ce54272580 | 202 | } |
| kotakku | 0:b1ce54272580 | 203 | |
| kotakku | 0:b1ce54272580 | 204 | void PS3BT::Reset() { |
| kotakku | 0:b1ce54272580 | 205 | PS3Connected = false; |
| kotakku | 0:b1ce54272580 | 206 | PS3MoveConnected = false; |
| kotakku | 0:b1ce54272580 | 207 | PS3NavigationConnected = false; |
| kotakku | 0:b1ce54272580 | 208 | activeConnection = false; |
| kotakku | 0:b1ce54272580 | 209 | l2cap_event_flag = 0; // Reset flags |
| kotakku | 0:b1ce54272580 | 210 | l2cap_state = L2CAP_WAIT; |
| kotakku | 0:b1ce54272580 | 211 | |
| kotakku | 0:b1ce54272580 | 212 | // Needed for PS3 Dualshock Controller commands to work via Bluetooth |
| kotakku | 0:b1ce54272580 | 213 | for(uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++) |
| kotakku | 0:b1ce54272580 | 214 | HIDBuffer[i + 2] = pgm_read_byte(&PS3_REPORT_BUFFER[i]); // First two bytes reserved for report type and ID |
| kotakku | 0:b1ce54272580 | 215 | } |
| kotakku | 0:b1ce54272580 | 216 | |
| kotakku | 0:b1ce54272580 | 217 | void PS3BT::disconnect() { // Use this void to disconnect any of the controllers |
| kotakku | 0:b1ce54272580 | 218 | // First the HID interrupt channel has to be disconnected, then the HID control channel and finally the HCI connection |
| kotakku | 0:b1ce54272580 | 219 | pBtd->l2cap_disconnection_request(hci_handle, ++identifier, interrupt_scid, interrupt_dcid); |
| kotakku | 0:b1ce54272580 | 220 | Reset(); |
| kotakku | 0:b1ce54272580 | 221 | l2cap_state = L2CAP_INTERRUPT_DISCONNECT; |
| kotakku | 0:b1ce54272580 | 222 | } |
| kotakku | 0:b1ce54272580 | 223 | |
| kotakku | 0:b1ce54272580 | 224 | void PS3BT::ACLData(uint8_t* ACLData) { |
| kotakku | 0:b1ce54272580 | 225 | if(!pBtd->l2capConnectionClaimed && !PS3Connected && !PS3MoveConnected && !PS3NavigationConnected && !activeConnection && !pBtd->connectToWii && !pBtd->incomingWii && !pBtd->pairWithWii) { |
| kotakku | 0:b1ce54272580 | 226 | if(ACLData[8] == L2CAP_CMD_CONNECTION_REQUEST) { |
| kotakku | 0:b1ce54272580 | 227 | if((ACLData[12] | (ACLData[13] << 8)) == HID_CTRL_PSM) { |
| kotakku | 0:b1ce54272580 | 228 | pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service |
| kotakku | 0:b1ce54272580 | 229 | activeConnection = true; |
| kotakku | 0:b1ce54272580 | 230 | hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection |
| kotakku | 0:b1ce54272580 | 231 | l2cap_state = L2CAP_WAIT; |
| kotakku | 0:b1ce54272580 | 232 | remote_name_first = pBtd->remote_name[0]; // Store the first letter in remote name for the connection |
| kotakku | 0:b1ce54272580 | 233 | #ifdef DEBUG_USB_HOST |
| kotakku | 0:b1ce54272580 | 234 | if(pBtd->hci_version < 3) { // Check the HCI Version of the Bluetooth dongle |
| kotakku | 0:b1ce54272580 | 235 | Notify(PSTR("\r\nYour dongle may not support reading the analog buttons, sensors and status\r\nYour HCI Version is: "), 0x80); |
| kotakku | 0:b1ce54272580 | 236 | Notify(pBtd->hci_version, 0x80); |
| kotakku | 0:b1ce54272580 | 237 | Notify(PSTR("\r\nBut should be at least 3\r\nThis means that it doesn't support Bluetooth Version 2.0+EDR"), 0x80); |
| kotakku | 0:b1ce54272580 | 238 | } |
| kotakku | 0:b1ce54272580 | 239 | #endif |
| kotakku | 0:b1ce54272580 | 240 | } |
| kotakku | 0:b1ce54272580 | 241 | } |
| kotakku | 0:b1ce54272580 | 242 | } |
| kotakku | 0:b1ce54272580 | 243 | |
| kotakku | 0:b1ce54272580 | 244 | if(checkHciHandle(ACLData, hci_handle)) { // acl_handle_ok |
| kotakku | 0:b1ce54272580 | 245 | memcpy(l2capinbuf, ACLData, BULK_MAXPKTSIZE); |
| kotakku | 0:b1ce54272580 | 246 | if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U |
| kotakku | 0:b1ce54272580 | 247 | if(l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) { |
| kotakku | 0:b1ce54272580 | 248 | #ifdef DEBUG_USB_HOST |
| kotakku | 0:b1ce54272580 | 249 | Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80); |
| kotakku | 0:b1ce54272580 | 250 | D_PrintHex<uint8_t > (l2capinbuf[13], 0x80); |
| kotakku | 0:b1ce54272580 | 251 | Notify(PSTR(" "), 0x80); |
| kotakku | 0:b1ce54272580 | 252 | D_PrintHex<uint8_t > (l2capinbuf[12], 0x80); |
| kotakku | 0:b1ce54272580 | 253 | Notify(PSTR(" Data: "), 0x80); |
| kotakku | 0:b1ce54272580 | 254 | D_PrintHex<uint8_t > (l2capinbuf[17], 0x80); |
| kotakku | 0:b1ce54272580 | 255 | Notify(PSTR(" "), 0x80); |
| kotakku | 0:b1ce54272580 | 256 | D_PrintHex<uint8_t > (l2capinbuf[16], 0x80); |
| kotakku | 0:b1ce54272580 | 257 | Notify(PSTR(" "), 0x80); |
| kotakku | 0:b1ce54272580 | 258 | D_PrintHex<uint8_t > (l2capinbuf[15], 0x80); |
| kotakku | 0:b1ce54272580 | 259 | Notify(PSTR(" "), 0x80); |
| kotakku | 0:b1ce54272580 | 260 | D_PrintHex<uint8_t > (l2capinbuf[14], 0x80); |
| kotakku | 0:b1ce54272580 | 261 | #endif |
| kotakku | 0:b1ce54272580 | 262 | } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { |
| kotakku | 0:b1ce54272580 | 263 | #ifdef EXTRADEBUG |
| kotakku | 0:b1ce54272580 | 264 | Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80); |
| kotakku | 0:b1ce54272580 | 265 | D_PrintHex<uint8_t > (l2capinbuf[13], 0x80); |
| kotakku | 0:b1ce54272580 | 266 | Notify(PSTR(" "), 0x80); |
| kotakku | 0:b1ce54272580 | 267 | D_PrintHex<uint8_t > (l2capinbuf[12], 0x80); |
| kotakku | 0:b1ce54272580 | 268 | Notify(PSTR(" SCID: "), 0x80); |
| kotakku | 0:b1ce54272580 | 269 | D_PrintHex<uint8_t > (l2capinbuf[15], 0x80); |
| kotakku | 0:b1ce54272580 | 270 | Notify(PSTR(" "), 0x80); |
| kotakku | 0:b1ce54272580 | 271 | D_PrintHex<uint8_t > (l2capinbuf[14], 0x80); |
| kotakku | 0:b1ce54272580 | 272 | Notify(PSTR(" Identifier: "), 0x80); |
| kotakku | 0:b1ce54272580 | 273 | D_PrintHex<uint8_t > (l2capinbuf[9], 0x80); |
| kotakku | 0:b1ce54272580 | 274 | #endif |
| kotakku | 0:b1ce54272580 | 275 | if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) { |
| kotakku | 0:b1ce54272580 | 276 | identifier = l2capinbuf[9]; |
| kotakku | 0:b1ce54272580 | 277 | control_scid[0] = l2capinbuf[14]; |
| kotakku | 0:b1ce54272580 | 278 | control_scid[1] = l2capinbuf[15]; |
| kotakku | 0:b1ce54272580 | 279 | l2cap_set_flag(L2CAP_FLAG_CONNECTION_CONTROL_REQUEST); |
| kotakku | 0:b1ce54272580 | 280 | } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM) { |
| kotakku | 0:b1ce54272580 | 281 | identifier = l2capinbuf[9]; |
| kotakku | 0:b1ce54272580 | 282 | interrupt_scid[0] = l2capinbuf[14]; |
| kotakku | 0:b1ce54272580 | 283 | interrupt_scid[1] = l2capinbuf[15]; |
| kotakku | 0:b1ce54272580 | 284 | l2cap_set_flag(L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST); |
| kotakku | 0:b1ce54272580 | 285 | } |
| kotakku | 0:b1ce54272580 | 286 | } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) { |
| kotakku | 0:b1ce54272580 | 287 | if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success |
| kotakku | 0:b1ce54272580 | 288 | if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { |
| kotakku | 0:b1ce54272580 | 289 | //Notify(PSTR("\r\nHID Control Configuration Complete"), 0x80); |
| kotakku | 0:b1ce54272580 | 290 | l2cap_set_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS); |
| kotakku | 0:b1ce54272580 | 291 | } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { |
| kotakku | 0:b1ce54272580 | 292 | //Notify(PSTR("\r\nHID Interrupt Configuration Complete"), 0x80); |
| kotakku | 0:b1ce54272580 | 293 | l2cap_set_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS); |
| kotakku | 0:b1ce54272580 | 294 | } |
| kotakku | 0:b1ce54272580 | 295 | } |
| kotakku | 0:b1ce54272580 | 296 | } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) { |
| kotakku | 0:b1ce54272580 | 297 | if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { |
| kotakku | 0:b1ce54272580 | 298 | //Notify(PSTR("\r\nHID Control Configuration Request"), 0x80); |
| kotakku | 0:b1ce54272580 | 299 | pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid); |
| kotakku | 0:b1ce54272580 | 300 | } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { |
| kotakku | 0:b1ce54272580 | 301 | //Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80); |
| kotakku | 0:b1ce54272580 | 302 | pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], interrupt_scid); |
| kotakku | 0:b1ce54272580 | 303 | } |
| kotakku | 0:b1ce54272580 | 304 | } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) { |
| kotakku | 0:b1ce54272580 | 305 | if(l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) { |
| kotakku | 0:b1ce54272580 | 306 | #ifdef DEBUG_USB_HOST |
| kotakku | 0:b1ce54272580 | 307 | Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80); |
| kotakku | 0:b1ce54272580 | 308 | #endif |
| kotakku | 0:b1ce54272580 | 309 | identifier = l2capinbuf[9]; |
| kotakku | 0:b1ce54272580 | 310 | pBtd->l2cap_disconnection_response(hci_handle, identifier, control_dcid, control_scid); |
| kotakku | 0:b1ce54272580 | 311 | Reset(); |
| kotakku | 0:b1ce54272580 | 312 | } else if(l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) { |
| kotakku | 0:b1ce54272580 | 313 | #ifdef DEBUG_USB_HOST |
| kotakku | 0:b1ce54272580 | 314 | Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80); |
| kotakku | 0:b1ce54272580 | 315 | #endif |
| kotakku | 0:b1ce54272580 | 316 | identifier = l2capinbuf[9]; |
| kotakku | 0:b1ce54272580 | 317 | pBtd->l2cap_disconnection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid); |
| kotakku | 0:b1ce54272580 | 318 | Reset(); |
| kotakku | 0:b1ce54272580 | 319 | } |
| kotakku | 0:b1ce54272580 | 320 | } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) { |
| kotakku | 0:b1ce54272580 | 321 | if(l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) { |
| kotakku | 0:b1ce54272580 | 322 | //Notify(PSTR("\r\nDisconnect Response: Control Channel"), 0x80); |
| kotakku | 0:b1ce54272580 | 323 | identifier = l2capinbuf[9]; |
| kotakku | 0:b1ce54272580 | 324 | l2cap_set_flag(L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE); |
| kotakku | 0:b1ce54272580 | 325 | } else if(l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) { |
| kotakku | 0:b1ce54272580 | 326 | //Notify(PSTR("\r\nDisconnect Response: Interrupt Channel"), 0x80); |
| kotakku | 0:b1ce54272580 | 327 | identifier = l2capinbuf[9]; |
| kotakku | 0:b1ce54272580 | 328 | l2cap_set_flag(L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE); |
| kotakku | 0:b1ce54272580 | 329 | } |
| kotakku | 0:b1ce54272580 | 330 | } |
| kotakku | 0:b1ce54272580 | 331 | #ifdef EXTRADEBUG |
| kotakku | 0:b1ce54272580 | 332 | else { |
| kotakku | 0:b1ce54272580 | 333 | Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80); |
| kotakku | 0:b1ce54272580 | 334 | D_PrintHex<uint8_t > (l2capinbuf[8], 0x80); |
| kotakku | 0:b1ce54272580 | 335 | } |
| kotakku | 0:b1ce54272580 | 336 | #endif |
| kotakku | 0:b1ce54272580 | 337 | } else if(l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt |
| kotakku | 0:b1ce54272580 | 338 | //Notify(PSTR("\r\nL2CAP Interrupt"), 0x80); |
| kotakku | 0:b1ce54272580 | 339 | if(PS3Connected || PS3MoveConnected || PS3NavigationConnected) { |
| kotakku | 0:b1ce54272580 | 340 | /* Read Report */ |
| kotakku | 0:b1ce54272580 | 341 | if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT |
| kotakku | 0:b1ce54272580 | 342 | lastMessageTime = (uint32_t)millis(); // Store the last message time |
| kotakku | 0:b1ce54272580 | 343 | |
| kotakku | 0:b1ce54272580 | 344 | if(PS3Connected || PS3NavigationConnected) |
| kotakku | 0:b1ce54272580 | 345 | ButtonState = (uint32_t)(l2capinbuf[11] | ((uint16_t)l2capinbuf[12] << 8) | ((uint32_t)l2capinbuf[13] << 16)); |
| kotakku | 0:b1ce54272580 | 346 | else if(PS3MoveConnected) |
| kotakku | 0:b1ce54272580 | 347 | ButtonState = (uint32_t)(l2capinbuf[10] | ((uint16_t)l2capinbuf[11] << 8) | ((uint32_t)l2capinbuf[12] << 16)); |
| kotakku | 0:b1ce54272580 | 348 | |
| kotakku | 0:b1ce54272580 | 349 | //Notify(PSTR("\r\nButtonState", 0x80); |
| kotakku | 0:b1ce54272580 | 350 | //PrintHex<uint32_t>(ButtonState, 0x80); |
| kotakku | 0:b1ce54272580 | 351 | |
| kotakku | 0:b1ce54272580 | 352 | if(ButtonState != OldButtonState) { |
| kotakku | 0:b1ce54272580 | 353 | ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable |
| kotakku | 0:b1ce54272580 | 354 | OldButtonState = ButtonState; |
| kotakku | 0:b1ce54272580 | 355 | } |
| kotakku | 0:b1ce54272580 | 356 | |
| kotakku | 0:b1ce54272580 | 357 | #ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers |
| kotakku | 0:b1ce54272580 | 358 | for(uint8_t i = 10; i < 58; i++) { |
| kotakku | 0:b1ce54272580 | 359 | D_PrintHex<uint8_t > (l2capinbuf[i], 0x80); |
| kotakku | 0:b1ce54272580 | 360 | Notify(PSTR(" "), 0x80); |
| kotakku | 0:b1ce54272580 | 361 | } |
| kotakku | 0:b1ce54272580 | 362 | Notify(PSTR("\r\n"), 0x80); |
| kotakku | 0:b1ce54272580 | 363 | #endif |
| kotakku | 0:b1ce54272580 | 364 | } |
| kotakku | 0:b1ce54272580 | 365 | } |
| kotakku | 0:b1ce54272580 | 366 | } |
| kotakku | 0:b1ce54272580 | 367 | L2CAP_task(); |
| kotakku | 0:b1ce54272580 | 368 | } |
| kotakku | 0:b1ce54272580 | 369 | } |
| kotakku | 0:b1ce54272580 | 370 | |
| kotakku | 0:b1ce54272580 | 371 | void PS3BT::L2CAP_task() { |
| kotakku | 0:b1ce54272580 | 372 | switch(l2cap_state) { |
| kotakku | 0:b1ce54272580 | 373 | case L2CAP_WAIT: |
| kotakku | 0:b1ce54272580 | 374 | if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_CONTROL_REQUEST)) { |
| kotakku | 0:b1ce54272580 | 375 | #ifdef DEBUG_USB_HOST |
| kotakku | 0:b1ce54272580 | 376 | Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80); |
| kotakku | 0:b1ce54272580 | 377 | #endif |
| kotakku | 0:b1ce54272580 | 378 | pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, PENDING); |
| kotakku | 0:b1ce54272580 | 379 | delay(1); |
| kotakku | 0:b1ce54272580 | 380 | pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, SUCCESSFUL); |
| kotakku | 0:b1ce54272580 | 381 | identifier++; |
| kotakku | 0:b1ce54272580 | 382 | delay(1); |
| kotakku | 0:b1ce54272580 | 383 | pBtd->l2cap_config_request(hci_handle, identifier, control_scid); |
| kotakku | 0:b1ce54272580 | 384 | l2cap_state = L2CAP_CONTROL_SUCCESS; |
| kotakku | 0:b1ce54272580 | 385 | } |
| kotakku | 0:b1ce54272580 | 386 | break; |
| kotakku | 0:b1ce54272580 | 387 | |
| kotakku | 0:b1ce54272580 | 388 | case L2CAP_CONTROL_SUCCESS: |
| kotakku | 0:b1ce54272580 | 389 | if(l2cap_check_flag(L2CAP_FLAG_CONFIG_CONTROL_SUCCESS)) { |
| kotakku | 0:b1ce54272580 | 390 | #ifdef DEBUG_USB_HOST |
| kotakku | 0:b1ce54272580 | 391 | Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80); |
| kotakku | 0:b1ce54272580 | 392 | #endif |
| kotakku | 0:b1ce54272580 | 393 | l2cap_state = L2CAP_INTERRUPT_SETUP; |
| kotakku | 0:b1ce54272580 | 394 | } |
| kotakku | 0:b1ce54272580 | 395 | break; |
| kotakku | 0:b1ce54272580 | 396 | |
| kotakku | 0:b1ce54272580 | 397 | case L2CAP_INTERRUPT_SETUP: |
| kotakku | 0:b1ce54272580 | 398 | if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST)) { |
| kotakku | 0:b1ce54272580 | 399 | #ifdef DEBUG_USB_HOST |
| kotakku | 0:b1ce54272580 | 400 | Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80); |
| kotakku | 0:b1ce54272580 | 401 | #endif |
| kotakku | 0:b1ce54272580 | 402 | pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, PENDING); |
| kotakku | 0:b1ce54272580 | 403 | delay(1); |
| kotakku | 0:b1ce54272580 | 404 | pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL); |
| kotakku | 0:b1ce54272580 | 405 | identifier++; |
| kotakku | 0:b1ce54272580 | 406 | delay(1); |
| kotakku | 0:b1ce54272580 | 407 | pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid); |
| kotakku | 0:b1ce54272580 | 408 | |
| kotakku | 0:b1ce54272580 | 409 | l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST; |
| kotakku | 0:b1ce54272580 | 410 | } |
| kotakku | 0:b1ce54272580 | 411 | break; |
| kotakku | 0:b1ce54272580 | 412 | |
| kotakku | 0:b1ce54272580 | 413 | case L2CAP_INTERRUPT_CONFIG_REQUEST: |
| kotakku | 0:b1ce54272580 | 414 | if(l2cap_check_flag(L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS)) { // Now the HID channels is established |
| kotakku | 0:b1ce54272580 | 415 | #ifdef DEBUG_USB_HOST |
| kotakku | 0:b1ce54272580 | 416 | Notify(PSTR("\r\nHID Interrupt Successfully Configured"), 0x80); |
| kotakku | 0:b1ce54272580 | 417 | #endif |
| kotakku | 0:b1ce54272580 | 418 | if(remote_name_first == 'M') { // First letter in Motion Controller ('M') |
| kotakku | 0:b1ce54272580 | 419 | memset(l2capinbuf, 0, BULK_MAXPKTSIZE); // Reset l2cap in buffer as it sometimes read it as a button has been pressed |
| kotakku | 0:b1ce54272580 | 420 | l2cap_state = TURN_ON_LED; |
| kotakku | 0:b1ce54272580 | 421 | } else |
| kotakku | 0:b1ce54272580 | 422 | l2cap_state = PS3_ENABLE_SIXAXIS; |
| kotakku | 0:b1ce54272580 | 423 | timer = (uint32_t)millis(); |
| kotakku | 0:b1ce54272580 | 424 | } |
| kotakku | 0:b1ce54272580 | 425 | break; |
| kotakku | 0:b1ce54272580 | 426 | |
| kotakku | 0:b1ce54272580 | 427 | /* These states are handled in Run() */ |
| kotakku | 0:b1ce54272580 | 428 | |
| kotakku | 0:b1ce54272580 | 429 | case L2CAP_INTERRUPT_DISCONNECT: |
| kotakku | 0:b1ce54272580 | 430 | if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE)) { |
| kotakku | 0:b1ce54272580 | 431 | #ifdef DEBUG_USB_HOST |
| kotakku | 0:b1ce54272580 | 432 | Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80); |
| kotakku | 0:b1ce54272580 | 433 | #endif |
| kotakku | 0:b1ce54272580 | 434 | identifier++; |
| kotakku | 0:b1ce54272580 | 435 | pBtd->l2cap_disconnection_request(hci_handle, identifier, control_scid, control_dcid); |
| kotakku | 0:b1ce54272580 | 436 | l2cap_state = L2CAP_CONTROL_DISCONNECT; |
| kotakku | 0:b1ce54272580 | 437 | } |
| kotakku | 0:b1ce54272580 | 438 | break; |
| kotakku | 0:b1ce54272580 | 439 | |
| kotakku | 0:b1ce54272580 | 440 | case L2CAP_CONTROL_DISCONNECT: |
| kotakku | 0:b1ce54272580 | 441 | if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE)) { |
| kotakku | 0:b1ce54272580 | 442 | #ifdef DEBUG_USB_HOST |
| kotakku | 0:b1ce54272580 | 443 | Notify(PSTR("\r\nDisconnected Control Channel"), 0x80); |
| kotakku | 0:b1ce54272580 | 444 | #endif |
| kotakku | 0:b1ce54272580 | 445 | pBtd->hci_disconnect(hci_handle); |
| kotakku | 0:b1ce54272580 | 446 | hci_handle = -1; // Reset handle |
| kotakku | 0:b1ce54272580 | 447 | l2cap_event_flag = 0; // Reset flags |
| kotakku | 0:b1ce54272580 | 448 | l2cap_state = L2CAP_WAIT; |
| kotakku | 0:b1ce54272580 | 449 | } |
| kotakku | 0:b1ce54272580 | 450 | break; |
| kotakku | 0:b1ce54272580 | 451 | } |
| kotakku | 0:b1ce54272580 | 452 | } |
| kotakku | 0:b1ce54272580 | 453 | |
| kotakku | 0:b1ce54272580 | 454 | void PS3BT::Run() { |
| kotakku | 0:b1ce54272580 | 455 | switch(l2cap_state) { |
| kotakku | 0:b1ce54272580 | 456 | case PS3_ENABLE_SIXAXIS: |
| kotakku | 0:b1ce54272580 | 457 | if((int32_t)((uint32_t)millis() - timer) > 1000) { // loop 1 second before sending the command |
| kotakku | 0:b1ce54272580 | 458 | memset(l2capinbuf, 0, BULK_MAXPKTSIZE); // Reset l2cap in buffer as it sometimes read it as a button has been pressed |
| kotakku | 0:b1ce54272580 | 459 | for(uint8_t i = 15; i < 19; i++) |
| kotakku | 0:b1ce54272580 | 460 | l2capinbuf[i] = 0x7F; // Set the analog joystick values to center position |
| kotakku | 0:b1ce54272580 | 461 | enable_sixaxis(); |
| kotakku | 0:b1ce54272580 | 462 | l2cap_state = TURN_ON_LED; |
| kotakku | 0:b1ce54272580 | 463 | timer = (uint32_t)millis(); |
| kotakku | 0:b1ce54272580 | 464 | } |
| kotakku | 0:b1ce54272580 | 465 | break; |
| kotakku | 0:b1ce54272580 | 466 | |
| kotakku | 0:b1ce54272580 | 467 | case TURN_ON_LED: |
| kotakku | 0:b1ce54272580 | 468 | if((int32_t)((uint32_t)millis() - timer) > 1000) { // loop 1 second before sending the command |
| kotakku | 0:b1ce54272580 | 469 | if(remote_name_first == 'P') { // First letter in PLAYSTATION(R)3 Controller ('P') |
| kotakku | 0:b1ce54272580 | 470 | #ifdef DEBUG_USB_HOST |
| kotakku | 0:b1ce54272580 | 471 | Notify(PSTR("\r\nDualshock 3 Controller Enabled\r\n"), 0x80); |
| kotakku | 0:b1ce54272580 | 472 | #endif |
| kotakku | 0:b1ce54272580 | 473 | PS3Connected = true; |
| kotakku | 0:b1ce54272580 | 474 | } else if(remote_name_first == 'N') { // First letter in Navigation Controller ('N') |
| kotakku | 0:b1ce54272580 | 475 | #ifdef DEBUG_USB_HOST |
| kotakku | 0:b1ce54272580 | 476 | Notify(PSTR("\r\nNavigation Controller Enabled\r\n"), 0x80); |
| kotakku | 0:b1ce54272580 | 477 | #endif |
| kotakku | 0:b1ce54272580 | 478 | PS3NavigationConnected = true; |
| kotakku | 0:b1ce54272580 | 479 | } else if(remote_name_first == 'M') { // First letter in Motion Controller ('M') |
| kotakku | 0:b1ce54272580 | 480 | timer = (uint32_t)millis(); |
| kotakku | 0:b1ce54272580 | 481 | #ifdef DEBUG_USB_HOST |
| kotakku | 0:b1ce54272580 | 482 | Notify(PSTR("\r\nMotion Controller Enabled\r\n"), 0x80); |
| kotakku | 0:b1ce54272580 | 483 | #endif |
| kotakku | 0:b1ce54272580 | 484 | PS3MoveConnected = true; |
| kotakku | 0:b1ce54272580 | 485 | } |
| kotakku | 0:b1ce54272580 | 486 | ButtonState = 0; // Clear all values |
| kotakku | 0:b1ce54272580 | 487 | OldButtonState = 0; |
| kotakku | 0:b1ce54272580 | 488 | ButtonClickState = 0; |
| kotakku | 0:b1ce54272580 | 489 | |
| kotakku | 0:b1ce54272580 | 490 | onInit(); // Turn on the LED on the controller |
| kotakku | 0:b1ce54272580 | 491 | l2cap_state = L2CAP_DONE; |
| kotakku | 0:b1ce54272580 | 492 | } |
| kotakku | 0:b1ce54272580 | 493 | break; |
| kotakku | 0:b1ce54272580 | 494 | |
| kotakku | 0:b1ce54272580 | 495 | case L2CAP_DONE: |
| kotakku | 0:b1ce54272580 | 496 | if(PS3MoveConnected) { // The Bulb and rumble values, has to be send at approximately every 5th second for it to stay on |
| kotakku | 0:b1ce54272580 | 497 | if((int32_t)((uint32_t)millis() - timer) > 4000) { // Send at least every 4th second |
| kotakku | 0:b1ce54272580 | 498 | HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE); // The Bulb and rumble values, has to be written again and again, for it to stay turned on |
| kotakku | 0:b1ce54272580 | 499 | timer = (uint32_t)millis(); |
| kotakku | 0:b1ce54272580 | 500 | } |
| kotakku | 0:b1ce54272580 | 501 | } |
| kotakku | 0:b1ce54272580 | 502 | break; |
| kotakku | 0:b1ce54272580 | 503 | } |
| kotakku | 0:b1ce54272580 | 504 | } |
| kotakku | 0:b1ce54272580 | 505 | |
| kotakku | 0:b1ce54272580 | 506 | /************************************************************/ |
| kotakku | 0:b1ce54272580 | 507 | /* HID Commands */ |
| kotakku | 0:b1ce54272580 | 508 | /************************************************************/ |
| kotakku | 0:b1ce54272580 | 509 | |
| kotakku | 0:b1ce54272580 | 510 | // Playstation Sixaxis Dualshock and Navigation Controller commands |
| kotakku | 0:b1ce54272580 | 511 | |
| kotakku | 0:b1ce54272580 | 512 | void PS3BT::HID_Command(uint8_t* data, uint8_t nbytes) { |
| kotakku | 0:b1ce54272580 | 513 | if((int32_t)((uint32_t)millis() - timerHID) <= 150) // Check if is has been more than 150ms since last command |
| kotakku | 0:b1ce54272580 | 514 | delay((uint32_t)(150 - ((uint32_t)millis() - timerHID))); // There have to be a delay between commands |
| kotakku | 0:b1ce54272580 | 515 | pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]); // Both the Navigation and Dualshock controller sends data via the control channel |
| kotakku | 0:b1ce54272580 | 516 | timerHID = (uint32_t)millis(); |
| kotakku | 0:b1ce54272580 | 517 | } |
| kotakku | 0:b1ce54272580 | 518 | |
| kotakku | 0:b1ce54272580 | 519 | void PS3BT::setAllOff() { |
| kotakku | 0:b1ce54272580 | 520 | HIDBuffer[3] = 0x00; // Rumble bytes |
| kotakku | 0:b1ce54272580 | 521 | HIDBuffer[4] = 0x00; |
| kotakku | 0:b1ce54272580 | 522 | HIDBuffer[5] = 0x00; |
| kotakku | 0:b1ce54272580 | 523 | HIDBuffer[6] = 0x00; |
| kotakku | 0:b1ce54272580 | 524 | |
| kotakku | 0:b1ce54272580 | 525 | HIDBuffer[11] = 0x00; // LED byte |
| kotakku | 0:b1ce54272580 | 526 | |
| kotakku | 0:b1ce54272580 | 527 | HID_Command(HIDBuffer, HID_BUFFERSIZE); |
| kotakku | 0:b1ce54272580 | 528 | } |
| kotakku | 0:b1ce54272580 | 529 | |
| kotakku | 0:b1ce54272580 | 530 | void PS3BT::setRumbleOff() { |
| kotakku | 0:b1ce54272580 | 531 | uint8_t rumbleBuf[HID_BUFFERSIZE]; |
| kotakku | 0:b1ce54272580 | 532 | memcpy(rumbleBuf, HIDBuffer, HID_BUFFERSIZE); |
| kotakku | 0:b1ce54272580 | 533 | rumbleBuf[3] = 0x00; |
| kotakku | 0:b1ce54272580 | 534 | rumbleBuf[4] = 0x00; |
| kotakku | 0:b1ce54272580 | 535 | rumbleBuf[5] = 0x00; |
| kotakku | 0:b1ce54272580 | 536 | rumbleBuf[6] = 0x00; |
| kotakku | 0:b1ce54272580 | 537 | HID_Command(rumbleBuf, HID_BUFFERSIZE); |
| kotakku | 0:b1ce54272580 | 538 | } |
| kotakku | 0:b1ce54272580 | 539 | |
| kotakku | 0:b1ce54272580 | 540 | void PS3BT::setRumbleOn(RumbleEnum mode) { |
| kotakku | 0:b1ce54272580 | 541 | uint8_t power[2] = {0xff, 0x00}; // Defaults to RumbleLow |
| kotakku | 0:b1ce54272580 | 542 | if(mode == RumbleHigh) { |
| kotakku | 0:b1ce54272580 | 543 | power[0] = 0x00; |
| kotakku | 0:b1ce54272580 | 544 | power[1] = 0xff; |
| kotakku | 0:b1ce54272580 | 545 | } |
| kotakku | 0:b1ce54272580 | 546 | setRumbleOn(0xfe, power[0], 0xfe, power[1]); |
| kotakku | 0:b1ce54272580 | 547 | } |
| kotakku | 0:b1ce54272580 | 548 | |
| kotakku | 0:b1ce54272580 | 549 | void PS3BT::setRumbleOn(uint8_t rightDuration, uint8_t rightPower, uint8_t leftDuration, uint8_t leftPower) { |
| kotakku | 0:b1ce54272580 | 550 | uint8_t rumbleBuf[HID_BUFFERSIZE]; |
| kotakku | 0:b1ce54272580 | 551 | memcpy(rumbleBuf, HIDBuffer, HID_BUFFERSIZE); |
| kotakku | 0:b1ce54272580 | 552 | rumbleBuf[3] = rightDuration; |
| kotakku | 0:b1ce54272580 | 553 | rumbleBuf[4] = rightPower; |
| kotakku | 0:b1ce54272580 | 554 | rumbleBuf[5] = leftDuration; |
| kotakku | 0:b1ce54272580 | 555 | rumbleBuf[6] = leftPower; |
| kotakku | 0:b1ce54272580 | 556 | HID_Command(rumbleBuf, HID_BUFFERSIZE); |
| kotakku | 0:b1ce54272580 | 557 | } |
| kotakku | 0:b1ce54272580 | 558 | |
| kotakku | 0:b1ce54272580 | 559 | void PS3BT::setLedRaw(uint8_t value) { |
| kotakku | 0:b1ce54272580 | 560 | HIDBuffer[11] = value << 1; |
| kotakku | 0:b1ce54272580 | 561 | HID_Command(HIDBuffer, HID_BUFFERSIZE); |
| kotakku | 0:b1ce54272580 | 562 | } |
| kotakku | 0:b1ce54272580 | 563 | |
| kotakku | 0:b1ce54272580 | 564 | void PS3BT::setLedOff(LEDEnum a) { |
| kotakku | 0:b1ce54272580 | 565 | HIDBuffer[11] &= ~((uint8_t)((pgm_read_byte(&PS3_LEDS[(uint8_t)a]) & 0x0f) << 1)); |
| kotakku | 0:b1ce54272580 | 566 | HID_Command(HIDBuffer, HID_BUFFERSIZE); |
| kotakku | 0:b1ce54272580 | 567 | } |
| kotakku | 0:b1ce54272580 | 568 | |
| kotakku | 0:b1ce54272580 | 569 | void PS3BT::setLedOn(LEDEnum a) { |
| kotakku | 0:b1ce54272580 | 570 | if(a == OFF) |
| kotakku | 0:b1ce54272580 | 571 | setLedRaw(0); |
| kotakku | 0:b1ce54272580 | 572 | else { |
| kotakku | 0:b1ce54272580 | 573 | HIDBuffer[11] |= (uint8_t)((pgm_read_byte(&PS3_LEDS[(uint8_t)a]) & 0x0f) << 1); |
| kotakku | 0:b1ce54272580 | 574 | HID_Command(HIDBuffer, HID_BUFFERSIZE); |
| kotakku | 0:b1ce54272580 | 575 | } |
| kotakku | 0:b1ce54272580 | 576 | } |
| kotakku | 0:b1ce54272580 | 577 | |
| kotakku | 0:b1ce54272580 | 578 | void PS3BT::setLedToggle(LEDEnum a) { |
| kotakku | 0:b1ce54272580 | 579 | HIDBuffer[11] ^= (uint8_t)((pgm_read_byte(&PS3_LEDS[(uint8_t)a]) & 0x0f) << 1); |
| kotakku | 0:b1ce54272580 | 580 | HID_Command(HIDBuffer, HID_BUFFERSIZE); |
| kotakku | 0:b1ce54272580 | 581 | } |
| kotakku | 0:b1ce54272580 | 582 | |
| kotakku | 0:b1ce54272580 | 583 | void PS3BT::enable_sixaxis() { // Command used to enable the Dualshock 3 and Navigation controller to send data via Bluetooth |
| kotakku | 0:b1ce54272580 | 584 | uint8_t cmd_buf[6]; |
| kotakku | 0:b1ce54272580 | 585 | cmd_buf[0] = 0x53; // HID BT Set_report (0x50) | Report Type (Feature 0x03) |
| kotakku | 0:b1ce54272580 | 586 | cmd_buf[1] = 0xF4; // Report ID |
| kotakku | 0:b1ce54272580 | 587 | cmd_buf[2] = 0x42; // Special PS3 Controller enable commands |
| kotakku | 0:b1ce54272580 | 588 | cmd_buf[3] = 0x03; |
| kotakku | 0:b1ce54272580 | 589 | cmd_buf[4] = 0x00; |
| kotakku | 0:b1ce54272580 | 590 | cmd_buf[5] = 0x00; |
| kotakku | 0:b1ce54272580 | 591 | |
| kotakku | 0:b1ce54272580 | 592 | HID_Command(cmd_buf, 6); |
| kotakku | 0:b1ce54272580 | 593 | } |
| kotakku | 0:b1ce54272580 | 594 | |
| kotakku | 0:b1ce54272580 | 595 | // Playstation Move Controller commands |
| kotakku | 0:b1ce54272580 | 596 | |
| kotakku | 0:b1ce54272580 | 597 | void PS3BT::HIDMove_Command(uint8_t* data, uint8_t nbytes) { |
| kotakku | 0:b1ce54272580 | 598 | if((int32_t)((uint32_t)millis() - timerHID) <= 150)// Check if is has been less than 150ms since last command |
| kotakku | 0:b1ce54272580 | 599 | delay((uint32_t)(150 - ((uint32_t)millis() - timerHID))); // There have to be a delay between commands |
| kotakku | 0:b1ce54272580 | 600 | pBtd->L2CAP_Command(hci_handle, data, nbytes, interrupt_scid[0], interrupt_scid[1]); // The Move controller sends it's data via the intterrupt channel |
| kotakku | 0:b1ce54272580 | 601 | timerHID = (uint32_t)millis(); |
| kotakku | 0:b1ce54272580 | 602 | } |
| kotakku | 0:b1ce54272580 | 603 | |
| kotakku | 0:b1ce54272580 | 604 | void PS3BT::moveSetBulb(uint8_t r, uint8_t g, uint8_t b) { // Use this to set the Color using RGB values |
| kotakku | 0:b1ce54272580 | 605 | // Set the Bulb's values into the write buffer |
| kotakku | 0:b1ce54272580 | 606 | HIDMoveBuffer[3] = r; |
| kotakku | 0:b1ce54272580 | 607 | HIDMoveBuffer[4] = g; |
| kotakku | 0:b1ce54272580 | 608 | HIDMoveBuffer[5] = b; |
| kotakku | 0:b1ce54272580 | 609 | |
| kotakku | 0:b1ce54272580 | 610 | HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE); |
| kotakku | 0:b1ce54272580 | 611 | } |
| kotakku | 0:b1ce54272580 | 612 | |
| kotakku | 0:b1ce54272580 | 613 | void PS3BT::moveSetBulb(ColorsEnum color) { // Use this to set the Color using the predefined colors in enum |
| kotakku | 0:b1ce54272580 | 614 | moveSetBulb((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color)); |
| kotakku | 0:b1ce54272580 | 615 | } |
| kotakku | 0:b1ce54272580 | 616 | |
| kotakku | 0:b1ce54272580 | 617 | void PS3BT::moveSetRumble(uint8_t rumble) { |
| kotakku | 0:b1ce54272580 | 618 | #ifdef DEBUG_USB_HOST |
| kotakku | 0:b1ce54272580 | 619 | if(rumble < 64 && rumble != 0) // The rumble value has to at least 64, or approximately 25% (64/255*100) |
| kotakku | 0:b1ce54272580 | 620 | Notify(PSTR("\r\nThe rumble value has to at least 64, or approximately 25%"), 0x80); |
| kotakku | 0:b1ce54272580 | 621 | #endif |
| kotakku | 0:b1ce54272580 | 622 | // Set the rumble value into the write buffer |
| kotakku | 0:b1ce54272580 | 623 | HIDMoveBuffer[7] = rumble; |
| kotakku | 0:b1ce54272580 | 624 | |
| kotakku | 0:b1ce54272580 | 625 | HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE); |
| kotakku | 0:b1ce54272580 | 626 | } |
| kotakku | 0:b1ce54272580 | 627 | |
| kotakku | 0:b1ce54272580 | 628 | void PS3BT::onInit() { |
| kotakku | 0:b1ce54272580 | 629 | if(pFuncOnInit) |
| kotakku | 0:b1ce54272580 | 630 | pFuncOnInit(); // Call the user function |
| kotakku | 0:b1ce54272580 | 631 | else { |
| kotakku | 0:b1ce54272580 | 632 | if(PS3MoveConnected) |
| kotakku | 0:b1ce54272580 | 633 | moveSetBulb(Red); |
| kotakku | 0:b1ce54272580 | 634 | else // Dualshock 3 or Navigation controller |
| kotakku | 0:b1ce54272580 | 635 | setLedOn(static_cast<LEDEnum>(CONTROLLER_LED1)); |
| kotakku | 0:b1ce54272580 | 636 | } |
| kotakku | 0:b1ce54272580 | 637 | } |
| kotakku | 0:b1ce54272580 | 638 |