Zoltan Hudak / UsbHostMAX3421E

Dependents:   UsbHostMAX3421E_Hello

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PS4Parser.h Source File

PS4Parser.h

00001 /* Copyright (C) 2014 Kristian Lauszus, TKJ Electronics. All rights reserved.
00002 
00003  This software may be distributed and modified under the terms of the GNU
00004  General Public License version 2 (GPL2) as published by the Free Software
00005  Foundation and appearing in the file GPL2.TXT included in the packaging of
00006  this file. Please note that GPL2 Section 2[b] requires that all works based
00007  on this software must also be made publicly available under the terms of
00008  the GPL2 ("Copyleft").
00009 
00010  Contact information
00011  -------------------
00012 
00013  Kristian Lauszus, TKJ Electronics
00014  Web      :  http://www.tkjelectronics.com
00015  e-mail   :  kristianl@tkjelectronics.com
00016  */
00017 
00018 #ifndef _ps4parser_h_
00019 #define _ps4parser_h_
00020 
00021 #include "Usb.h"
00022 #include "controllerEnums.h"
00023 
00024 /** Buttons on the controller */
00025 const uint8_t PS4_BUTTONS[] PROGMEM = {
00026         UP, // UP
00027         RIGHT, // RIGHT
00028         DOWN, // DOWN
00029         LEFT, // LEFT
00030 
00031         0x0C, // SHARE
00032         0x0D, // OPTIONS
00033         0x0E, // L3
00034         0x0F, // R3
00035 
00036         0x0A, // L2
00037         0x0B, // R2
00038         0x08, // L1
00039         0x09, // R1
00040 
00041         0x07, // TRIANGLE
00042         0x06, // CIRCLE
00043         0x05, // CROSS
00044         0x04, // SQUARE
00045 
00046         0x10, // PS
00047         0x11, // TOUCHPAD
00048 };
00049 
00050 union PS4Buttons {
00051         struct {
00052                 uint8_t dpad : 4;
00053                 uint8_t square : 1;
00054                 uint8_t cross : 1;
00055                 uint8_t circle : 1;
00056                 uint8_t triangle : 1;
00057 
00058                 uint8_t l1 : 1;
00059                 uint8_t r1 : 1;
00060                 uint8_t l2 : 1;
00061                 uint8_t r2 : 1;
00062                 uint8_t share : 1;
00063                 uint8_t options : 1;
00064                 uint8_t l3 : 1;
00065                 uint8_t r3 : 1;
00066 
00067                 uint8_t ps : 1;
00068                 uint8_t touchpad : 1;
00069                 uint8_t reportCounter : 6;
00070         } __attribute__((packed));
00071         uint32_t val : 24;
00072 } __attribute__((packed));
00073 
00074 struct touchpadXY {
00075         uint8_t dummy; // I can not figure out what this data is for, it seems to change randomly, maybe a timestamp?
00076         struct {
00077                 uint8_t counter : 7; // Increments every time a finger is touching the touchpad
00078                 uint8_t touching : 1; // The top bit is cleared if the finger is touching the touchpad
00079                 uint16_t x : 12;
00080                 uint16_t y : 12;
00081         } __attribute__((packed)) finger[2]; // 0 = first finger, 1 = second finger
00082 } __attribute__((packed));
00083 
00084 struct PS4Status {
00085         uint8_t battery : 4;
00086         uint8_t usb : 1;
00087         uint8_t audio : 1;
00088         uint8_t mic : 1;
00089         uint8_t unknown : 1; // Extension port?
00090 } __attribute__((packed));
00091 
00092 struct PS4Data {
00093         /* Button and joystick values */
00094         uint8_t hatValue[4];
00095         PS4Buttons btn;
00096         uint8_t trigger[2];
00097 
00098         /* Gyro and accelerometer values */
00099         uint8_t dummy[3]; // First two looks random, while the third one might be some kind of status - it increments once in a while
00100         int16_t gyroY, gyroZ, gyroX;
00101         int16_t accX, accZ, accY;
00102 
00103         uint8_t dummy2[5];
00104         PS4Status status;
00105         uint8_t dummy3[3];
00106 
00107         /* The rest is data for the touchpad */
00108         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.
00109                           // The last data is read from the last position in the array while the oldest measurement is from the first position.
00110                           // The first position will also keep it's value after the finger is released, while the other two will set them to zero.
00111                           // Note that if you read fast enough from the device, then only the first one will contain any data.
00112 
00113         // The last three bytes are always: 0x00, 0x80, 0x00
00114 } __attribute__((packed));
00115 
00116 struct PS4Output {
00117         uint8_t bigRumble, smallRumble; // Rumble
00118         uint8_t r, g, b; // RGB
00119         uint8_t flashOn, flashOff; // Time to flash bright/dark (255 = 2.5 seconds)
00120         bool reportChanged; // The data is send when data is received from the controller
00121 } __attribute__((packed));
00122 
00123 /** This class parses all the data sent by the PS4 controller */
00124 class PS4Parser {
00125 public:
00126         /** Constructor for the PS4Parser class. */
00127         PS4Parser() {
00128                 Reset();
00129         };
00130 
00131         /** @name PS4 Controller functions */
00132         /**
00133          * getButtonPress(ButtonEnum b) will return true as long as the button is held down.
00134          *
00135          * While getButtonClick(ButtonEnum b) will only return it once.
00136          *
00137          * So you instance if you need to increase a variable once you would use getButtonClick(ButtonEnum b),
00138          * but if you need to drive a robot forward you would use getButtonPress(ButtonEnum b).
00139          * @param  b          ::ButtonEnum to read.
00140          * @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.
00141          */
00142         bool getButtonPress(ButtonEnum b);
00143         bool getButtonClick(ButtonEnum b);
00144         /**@}*/
00145         /** @name PS4 Controller functions */
00146         /**
00147          * Used to get the analog value from button presses.
00148          * @param  b The ::ButtonEnum to read.
00149          * The supported buttons are:
00150          * ::L2 and ::R2.
00151          * @return   Analog value in the range of 0-255.
00152          */
00153         uint8_t getAnalogButton(ButtonEnum b);
00154 
00155         /**
00156          * Used to read the analog joystick.
00157          * @param  a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY.
00158          * @return   Return the analog value in the range of 0-255.
00159          */
00160         uint8_t getAnalogHat(AnalogHatEnum a);
00161 
00162         /**
00163          * Get the x-coordinate of the touchpad. Position 0 is in the top left.
00164          * @param  finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used.
00165          * @param  xyId   The controller sends out three packets with the same structure.
00166          *                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.
00167          *                For that reason it will be set to 0 if the argument is omitted.
00168          * @return        Returns the x-coordinate of the finger.
00169          */
00170         uint16_t getX(uint8_t finger = 0, uint8_t xyId = 0) {
00171                 return ps4Data.xy[xyId].finger[finger].x;
00172         };
00173 
00174         /**
00175          * Get the y-coordinate of the touchpad. Position 0 is in the top left.
00176          * @param  finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used.
00177          * @param  xyId   The controller sends out three packets with the same structure.
00178          *                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.
00179          *                For that reason it will be set to 0 if the argument is omitted.
00180          * @return        Returns the y-coordinate of the finger.
00181          */
00182         uint16_t getY(uint8_t finger = 0, uint8_t xyId = 0) {
00183                 return ps4Data.xy[xyId].finger[finger].y;
00184         };
00185 
00186         /**
00187          * Returns whenever the user is toucing the touchpad.
00188          * @param  finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used.
00189          * @param  xyId   The controller sends out three packets with the same structure.
00190          *                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.
00191          *                For that reason it will be set to 0 if the argument is omitted.
00192          * @return        Returns true if the specific finger is touching the touchpad.
00193          */
00194         bool isTouching(uint8_t finger = 0, uint8_t xyId = 0) {
00195                 return !(ps4Data.xy[xyId].finger[finger].touching); // The bit is cleared when a finger is touching the touchpad
00196         };
00197 
00198         /**
00199          * This counter increments every time a finger touches the touchpad.
00200          * @param  finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used.
00201          * @param  xyId   The controller sends out three packets with the same structure.
00202          *                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.
00203          *                For that reason it will be set to 0 if the argument is omitted.
00204          * @return        Return the value of the counter, note that it is only a 7-bit value.
00205          */
00206         uint8_t getTouchCounter(uint8_t finger = 0, uint8_t xyId = 0) {
00207                 return ps4Data.xy[xyId].finger[finger].counter;
00208         };
00209 
00210         /**
00211          * Get the angle of the controller calculated using the accelerometer.
00212          * @param  a Either ::Pitch or ::Roll.
00213          * @return   Return the angle in the range of 0-360.
00214          */
00215         float getAngle(AngleEnum a) {
00216                 if (a == Pitch)
00217                         return (atan2f(ps4Data.accY, ps4Data.accZ) + M_PI) * RAD_TO_DEG;
00218                 else
00219                         return (atan2f(ps4Data.accX, ps4Data.accZ) + M_PI) * RAD_TO_DEG;
00220         };
00221 
00222         /**
00223          * Used to get the raw values from the 3-axis gyroscope and 3-axis accelerometer inside the PS4 controller.
00224          * @param  s The sensor to read.
00225          * @return   Returns the raw sensor reading.
00226          */
00227         int16_t getSensor(SensorEnum s) {
00228                 switch(s) {
00229                         case gX:
00230                                 return ps4Data.gyroX;
00231                         case gY:
00232                                 return ps4Data.gyroY;
00233                         case gZ:
00234                                 return ps4Data.gyroZ;
00235                         case aX:
00236                                 return ps4Data.accX;
00237                         case aY:
00238                                 return ps4Data.accY;
00239                         case aZ:
00240                                 return ps4Data.accZ;
00241                         default:
00242                                 return 0;
00243                 }
00244         };
00245 
00246         /**
00247          * Return the battery level of the PS4 controller.
00248          * @return The battery level in the range 0-15.
00249          */
00250         uint8_t getBatteryLevel() {
00251                 return ps4Data.status.battery;
00252         };
00253 
00254         /**
00255          * Use this to check if an USB cable is connected to the PS4 controller.
00256          * @return Returns true if an USB cable is connected.
00257          */
00258         bool getUsbStatus() {
00259                 return ps4Data.status.usb;
00260         };
00261 
00262         /**
00263          * Use this to check if an audio jack cable is connected to the PS4 controller.
00264          * @return Returns true if an audio jack cable is connected.
00265          */
00266         bool getAudioStatus() {
00267                 return ps4Data.status.audio;
00268         };
00269 
00270         /**
00271          * Use this to check if a microphone is connected to the PS4 controller.
00272          * @return Returns true if a microphone is connected.
00273          */
00274         bool getMicStatus() {
00275                 return ps4Data.status.mic;
00276         };
00277 
00278         /** Turn both rumble and the LEDs off. */
00279         void setAllOff() {
00280                 setRumbleOff();
00281                 setLedOff();
00282         };
00283 
00284         /** Set rumble off. */
00285         void setRumbleOff() {
00286                 setRumbleOn(0, 0);
00287         };
00288 
00289         /**
00290          * Turn on rumble.
00291          * @param mode Either ::RumbleHigh or ::RumbleLow.
00292          */
00293         void setRumbleOn(RumbleEnum mode) {
00294                 if (mode == RumbleLow)
00295                         setRumbleOn(0x00, 0xFF);
00296                 else
00297                         setRumbleOn(0xFF, 0x00);
00298         };
00299 
00300         /**
00301          * Turn on rumble.
00302          * @param bigRumble   Value for big motor.
00303          * @param smallRumble Value for small motor.
00304          */
00305         void setRumbleOn(uint8_t bigRumble, uint8_t smallRumble) {
00306                 ps4Output.bigRumble = bigRumble;
00307                 ps4Output.smallRumble = smallRumble;
00308                 ps4Output.reportChanged = true;
00309         };
00310 
00311         /** Turn all LEDs off. */
00312         void setLedOff() {
00313                 setLed(0, 0, 0);
00314         };
00315 
00316         /**
00317          * Use this to set the color using RGB values.
00318          * @param r,g,b RGB value.
00319          */
00320         void setLed(uint8_t r, uint8_t g, uint8_t b) {
00321                 ps4Output.r = r;
00322                 ps4Output.g = g;
00323                 ps4Output.b = b;
00324                 ps4Output.reportChanged = true;
00325         };
00326 
00327         /**
00328          * Use this to set the color using the predefined colors in ::ColorsEnum.
00329          * @param color The desired color.
00330          */
00331         void setLed(ColorsEnum color) {
00332                 setLed((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color));
00333         };
00334 
00335         /**
00336          * Set the LEDs flash time.
00337          * @param flashOn  Time to flash bright (255 = 2.5 seconds).
00338          * @param flashOff Time to flash dark (255 = 2.5 seconds).
00339          */
00340         void setLedFlash(uint8_t flashOn, uint8_t flashOff) {
00341                 ps4Output.flashOn = flashOn;
00342                 ps4Output.flashOff = flashOff;
00343                 ps4Output.reportChanged = true;
00344         };
00345         /**@}*/
00346 
00347 protected:
00348         /**
00349          * Used to parse data sent from the PS4 controller.
00350          * @param len Length of the data.
00351          * @param buf Pointer to the data buffer.
00352          */
00353         void Parse(uint8_t len, uint8_t *buf);
00354 
00355         /** Used to reset the different buffers to their default values */
00356         void Reset();
00357 
00358         /**
00359          * Send the output to the PS4 controller. This is implemented in PS4BT.h and PS4USB.h.
00360          * @param output Pointer to PS4Output buffer;
00361          */
00362         virtual void sendOutputReport(PS4Output *output) = 0;
00363 
00364 private:
00365         bool checkDpad(ButtonEnum b); // Used to check PS4 DPAD buttons
00366 
00367         PS4Data ps4Data;
00368         PS4Buttons oldButtonState, buttonClickState;
00369         PS4Output ps4Output;
00370         uint8_t oldDpad;
00371 };
00372 #endif