1 /* Copyright (C) 2014 Kristian Lauszus, TKJ Electronics. All rights reserved.
3 This software may be distributed and modified under the terms of the GNU
4 General Public License version 2 (GPL2) as published by the Free Software
5 Foundation and appearing in the file GPL2.TXT included in the packaging of
6 this file. Please note that GPL2 Section 2[b] requires that all works based
7 on this software must also be made publicly available under the terms of
13 Kristian Lauszus, TKJ Electronics
14 Web : http://www.tkjelectronics.com
15 e-mail : kristianl@tkjelectronics.com
22 #include "controllerEnums.h"
24 /** Buttons on the controller */
25 const uint8_t PS4_BUTTONS[] PROGMEM = {
69 uint8_t reportCounter : 6;
70 } __attribute__((packed));
72 } __attribute__((packed));
75 uint8_t dummy; // I can not figure out what this data is for, it seems to change randomly, maybe a timestamp?
77 uint8_t counter : 7; // Increments every time a finger is touching the touchpad
78 uint8_t touching : 1; // The top bit is cleared if the finger is touching the touchpad
81 } __attribute__((packed)) finger[2]; // 0 = first finger, 1 = second finger
82 } __attribute__((packed));
89 uint8_t unknown : 1; // Extension port?
90 } __attribute__((packed));
93 /* Button and joystick values */
98 /* Gyro and accelerometer values */
99 uint8_t dummy[3]; // First two looks random, while the third one might be some kind of status - it increments once in a while
100 int16_t gyroY, gyroZ, gyroX;
101 int16_t accX, accZ, accY;
107 /* The rest is data for the touchpad */
108 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.
109 // The last data is read from the last position in the array while the oldest measurement is from the first position.
110 // The first position will also keep it's value after the finger is released, while the other two will set them to zero.
111 // Note that if you read fast enough from the device, then only the first one will contain any data.
113 // The last three bytes are always: 0x00, 0x80, 0x00
114 } __attribute__((packed));
117 uint8_t bigRumble, smallRumble; // Rumble
118 uint8_t r, g, b; // RGB
119 uint8_t flashOn, flashOff; // Time to flash bright/dark (255 = 2.5 seconds)
120 bool reportChanged; // The data is send when data is received from the controller
121 } __attribute__((packed));
127 DPAD_RIGHT_DOWN = 0x3,
129 DPAD_DOWN_LEFT = 0x5,
135 /** This class parses all the data sent by the PS4 controller */
138 /** Constructor for the PS4Parser class. */
143 /** @name PS4 Controller functions */
145 * getButtonPress(ButtonEnum b) will return true as long as the button is held down.
147 * While getButtonClick(ButtonEnum b) will only return it once.
149 * So you instance if you need to increase a variable once you would use getButtonClick(ButtonEnum b),
150 * but if you need to drive a robot forward you would use getButtonPress(ButtonEnum b).
151 * @param b ::ButtonEnum to read.
152 * @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.
154 bool getButtonPress(ButtonEnum b);
155 bool getButtonClick(ButtonEnum b);
157 /** @name PS4 Controller functions */
159 * Used to get the analog value from button presses.
160 * @param b The ::ButtonEnum to read.
161 * The supported buttons are:
162 * ::UP, ::RIGHT, ::DOWN, ::LEFT, ::L1, ::L2, ::R1, ::R2,
163 * ::TRIANGLE, ::CIRCLE, ::CROSS, ::SQUARE, and ::T.
164 * @return Analog value in the range of 0-255.
166 uint8_t getAnalogButton(ButtonEnum b);
169 * Used to read the analog joystick.
170 * @param a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY.
171 * @return Return the analog value in the range of 0-255.
173 uint8_t getAnalogHat(AnalogHatEnum a);
176 * Get the x-coordinate of the touchpad. Position 0 is in the top left.
177 * @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used.
178 * @param xyId The controller sends out three packets with the same structure.
179 * 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.
180 * For that reason it will be set to 0 if the argument is omitted.
181 * @return Returns the x-coordinate of the finger.
183 uint16_t getX(uint8_t finger = 0, uint8_t xyId = 0) {
184 return ps4Data.xy[xyId].finger[finger].x;
188 * Get the y-coordinate of the touchpad. Position 0 is in the top left.
189 * @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used.
190 * @param xyId The controller sends out three packets with the same structure.
191 * 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.
192 * For that reason it will be set to 0 if the argument is omitted.
193 * @return Returns the y-coordinate of the finger.
195 uint16_t getY(uint8_t finger = 0, uint8_t xyId = 0) {
196 return ps4Data.xy[xyId].finger[finger].y;
200 * Returns whenever the user is toucing the touchpad.
201 * @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used.
202 * @param xyId The controller sends out three packets with the same structure.
203 * 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.
204 * For that reason it will be set to 0 if the argument is omitted.
205 * @return Returns true if the specific finger is touching the touchpad.
207 bool isTouching(uint8_t finger = 0, uint8_t xyId = 0) {
208 return !(ps4Data.xy[xyId].finger[finger].touching); // The bit is cleared when a finger is touching the touchpad
212 * This counter increments every time a finger touches the touchpad.
213 * @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used.
214 * @param xyId The controller sends out three packets with the same structure.
215 * 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.
216 * For that reason it will be set to 0 if the argument is omitted.
217 * @return Return the value of the counter, note that it is only a 7-bit value.
219 uint8_t getTouchCounter(uint8_t finger = 0, uint8_t xyId = 0) {
220 return ps4Data.xy[xyId].finger[finger].counter;
224 * Get the angle of the controller calculated using the accelerometer.
225 * @param a Either ::Pitch or ::Roll.
226 * @return Return the angle in the range of 0-360.
228 double getAngle(AngleEnum a) {
230 return (atan2(ps4Data.accY, ps4Data.accZ) + PI) * RAD_TO_DEG;
232 return (atan2(ps4Data.accX, ps4Data.accZ) + PI) * RAD_TO_DEG;
236 * Used to get the raw values from the 3-axis gyroscope and 3-axis accelerometer inside the PS4 controller.
237 * @param s The sensor to read.
238 * @return Returns the raw sensor reading.
240 int16_t getSensor(SensorEnum s) {
243 return ps4Data.gyroX;
245 return ps4Data.gyroY;
247 return ps4Data.gyroZ;
260 * Return the battery level of the PS4 controller.
261 * @return The battery level in the range 0-15.
263 uint8_t getBatteryLevel() {
264 return ps4Data.status.battery;
268 * Use this to check if an USB cable is connected to the PS4 controller.
269 * @return Returns true if an USB cable is connected.
271 bool getUsbStatus() {
272 return ps4Data.status.usb;
276 * Use this to check if an audio jack cable is connected to the PS4 controller.
277 * @return Returns true if an audio jack cable is connected.
279 bool getAudioStatus() {
280 return ps4Data.status.audio;
284 * Use this to check if a microphone is connected to the PS4 controller.
285 * @return Returns true if a microphone is connected.
287 bool getMicStatus() {
288 return ps4Data.status.mic;
291 /** Turn both rumble and the LEDs off. */
297 /** Set rumble off. */
298 void setRumbleOff() {
304 * @param mode Either ::RumbleHigh or ::RumbleLow.
306 void setRumbleOn(RumbleEnum mode) {
307 if (mode == RumbleLow)
308 setRumbleOn(0x00, 0xFF);
310 setRumbleOn(0xFF, 0x00);
315 * @param bigRumble Value for big motor.
316 * @param smallRumble Value for small motor.
318 void setRumbleOn(uint8_t bigRumble, uint8_t smallRumble) {
319 ps4Output.bigRumble = bigRumble;
320 ps4Output.smallRumble = smallRumble;
321 ps4Output.reportChanged = true;
324 /** Turn all LEDs off. */
330 * Use this to set the color using RGB values.
331 * @param r,g,b RGB value.
333 void setLed(uint8_t r, uint8_t g, uint8_t b) {
337 ps4Output.reportChanged = true;
341 * Use this to set the color using the predefined colors in ::ColorsEnum.
342 * @param color The desired color.
344 void setLed(ColorsEnum color) {
345 setLed((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color));
349 * Set the LEDs flash time.
350 * @param flashOn Time to flash bright (255 = 2.5 seconds).
351 * @param flashOff Time to flash dark (255 = 2.5 seconds).
353 void setLedFlash(uint8_t flashOn, uint8_t flashOff) {
354 ps4Output.flashOn = flashOn;
355 ps4Output.flashOff = flashOff;
356 ps4Output.reportChanged = true;
362 * Used to parse data sent from the PS4 controller.
363 * @param len Length of the data.
364 * @param buf Pointer to the data buffer.
366 void Parse(uint8_t len, uint8_t *buf);
368 /** Used to reset the different buffers to their default values */
371 for (i = 0; i < sizeof(ps4Data.hatValue); i++)
372 ps4Data.hatValue[i] = 127; // Center value
374 oldButtonState.val = 0;
375 for (i = 0; i < sizeof(ps4Data.trigger); i++)
376 ps4Data.trigger[i] = 0;
377 for (i = 0; i < sizeof(ps4Data.xy)/sizeof(ps4Data.xy[0]); i++) {
378 for (uint8_t j = 0; j < sizeof(ps4Data.xy[0].finger)/sizeof(ps4Data.xy[0].finger[0]); j++)
379 ps4Data.xy[i].finger[j].touching = 1; // The bit is cleared if the finger is touching the touchpad
382 ps4Data.btn.dpad = DPAD_OFF;
383 oldButtonState.dpad = DPAD_OFF;
384 buttonClickState.dpad = 0;
387 ps4Output.bigRumble = ps4Output.smallRumble = 0;
388 ps4Output.r = ps4Output.g = ps4Output.b = 0;
389 ps4Output.flashOn = ps4Output.flashOff = 0;
390 ps4Output.reportChanged = false;
394 * Send the output to the PS4 controller. This is implemented in PS4BT.h and PS4USB.h.
395 * @param output Pointer to PS4Output buffer;
397 virtual void sendOutputReport(PS4Output *output) = 0;
400 bool checkDpad(ButtonEnum b); // Used to check PS4 DPAD buttons
403 PS4Buttons oldButtonState, buttonClickState;