diff options
Diffstat (limited to 'lib/usbhost/USB_Host_Shield_2.0/PS4Parser.h')
| -rw-r--r-- | lib/usbhost/USB_Host_Shield_2.0/PS4Parser.h | 407 | 
1 files changed, 407 insertions, 0 deletions
| diff --git a/lib/usbhost/USB_Host_Shield_2.0/PS4Parser.h b/lib/usbhost/USB_Host_Shield_2.0/PS4Parser.h new file mode 100644 index 0000000000..51f0806361 --- /dev/null +++ b/lib/usbhost/USB_Host_Shield_2.0/PS4Parser.h @@ -0,0 +1,407 @@ +/* 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 "Usb.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 reportCounter : 6; +        } __attribute__((packed)); +        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? +        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 +                uint16_t x : 12; +                uint16_t y : 12; +        } __attribute__((packed)) finger[2]; // 0 = first finger, 1 = second finger +} __attribute__((packed)); + +struct PS4Status { +        uint8_t battery : 4; +        uint8_t usb : 1; +        uint8_t audio : 1; +        uint8_t mic : 1; +        uint8_t unknown : 1; // Extension port? +} __attribute__((packed)); + +struct PS4Data { +        /* Button and joystick values */ +        uint8_t hatValue[4]; +        PS4Buttons btn; +        uint8_t trigger[2]; + +        /* 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; +        int16_t accX, accZ, accY; + +        uint8_t dummy2[5]; +        PS4Status status; +        uint8_t dummy3[3]; + +        /* The rest is data for the touchpad */ +        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. + +        // 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, +        DPAD_RIGHT = 0x2, +        DPAD_RIGHT_DOWN = 0x3, +        DPAD_DOWN = 0x4, +        DPAD_DOWN_LEFT = 0x5, +        DPAD_LEFT = 0x6, +        DPAD_LEFT_UP = 0x7, +        DPAD_OFF = 0x8, +}; + +/** 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  b 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 b); + +        /** +         * 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); + +        /** +         * 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; +        }; + +        /** +         * 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; +                else +                        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: +                                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; +                } +        }; + +        /** +         * Return the battery level of the PS4 controller. +         * @return The battery level in the range 0-15. +         */ +        uint8_t getBatteryLevel() { +                return ps4Data.status.battery; +        }; + +        /** +         * Use this to check if an USB cable is connected to the PS4 controller. +         * @return Returns true if an USB cable is connected. +         */ +        bool getUsbStatus() { +                return ps4Data.status.usb; +        }; + +        /** +         * Use this to check if an audio jack cable is connected to the PS4 controller. +         * @return Returns true if an audio jack cable is connected. +         */ +        bool getAudioStatus() { +                return ps4Data.status.audio; +        }; + +        /** +         * Use this to check if a microphone is connected to the PS4 controller. +         * @return Returns true if a microphone is connected. +         */ +        bool getMicStatus() { +                return ps4Data.status.mic; +        }; + +        /** 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(0x00, 0xFF); +                else +                        setRumbleOn(0xFF, 0x00); +        }; + +        /** +         * 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: +        /** +         * 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; +                for (i = 0; i < sizeof(ps4Data.hatValue); i++) +                        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++) { +                        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; + +                ps4Output.bigRumble = ps4Output.smallRumble = 0; +                ps4Output.r = ps4Output.g = ps4Output.b = 0; +                ps4Output.flashOn = ps4Output.flashOff = 0; +                ps4Output.reportChanged = false; +        }; + +        /** +         * 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 + +        PS4Data ps4Data; +        PS4Buttons oldButtonState, buttonClickState; +        PS4Output ps4Output; +        uint8_t oldDpad; +}; +#endif | 
