MatrixMiniR4 1.1.4
Matrix Mini R4 Arduino Library API Documentation
Loading...
Searching...
No Matches
MiniR4PS2X_lib.cpp
Go to the documentation of this file.
1
6#include "MiniR4PS2X_lib.h"
7#include <math.h>
8#include <stdint.h>
9#include <stdio.h>
10
11#if ARDUINO > 22
12# include "Arduino.h"
13#else
14# include "WProgram.h"
15# include "pins_arduino.h"
16#endif
17
18static byte enter_config[] = {0x01, 0x43, 0x00, 0x01, 0x00};
19static byte set_mode[] = {0x01, 0x44, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00};
20static byte set_bytes_large[] = {0x01, 0x4F, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00};
21static byte exit_config[] = {0x01, 0x43, 0x00, 0x00, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A};
22static byte enable_rumble[] = {0x01, 0x4D, 0x00, 0x00, 0x01};
23static byte type_read[] = {0x01, 0x45, 0x00, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A};
24
25/****************************************************************************************/
27{
28 return ((last_buttons ^ buttons) > 0);
29}
30
31/****************************************************************************************/
32boolean PS2X::NewButtonState(unsigned int button)
33{
34 return (((last_buttons ^ buttons) & button) > 0);
35}
36
37/****************************************************************************************/
38boolean PS2X::ButtonPressed(unsigned int button)
39{
40 return (NewButtonState(button) & Button(button));
41}
42
43/****************************************************************************************/
44boolean PS2X::ButtonReleased(unsigned int button)
45{
46 return ((NewButtonState(button)) & ((~last_buttons & button) > 0));
47}
48
49/****************************************************************************************/
50boolean PS2X::Button(uint16_t button)
51{
52 return ((~buttons & button) > 0);
53}
54
55/****************************************************************************************/
57{
58 return (~buttons) & 0xFFFF;
59}
60
61/****************************************************************************************/
62byte PS2X::Analog(byte button)
63{
64 return PS2data[button];
65}
66
67/****************************************************************************************/
68unsigned char PS2X::_gamepad_shiftinout(char byte)
69{
70 unsigned char tmp = 0;
71 for (unsigned char i = 0; i < 8; i++) {
72 if (CHK(byte, i))
73 CMD_SET();
74 else
75 CMD_CLR();
76
77 CLK_CLR();
78 delayMicroseconds(CTRL_CLK);
79
80 // if(DAT_CHK()) SET(tmp,i);
81 if (DAT_CHK()) bitSet(tmp, i);
82
83 CLK_SET();
84#if CTRL_CLK_HIGH
85 delayMicroseconds(CTRL_CLK_HIGH);
86#endif
87 }
88 CMD_SET();
89 delayMicroseconds(CTRL_BYTE_DELAY);
90 return tmp;
91}
92
93/****************************************************************************************/
95{
96 read_gamepad(false, 0x00);
97}
98
99/****************************************************************************************/
100boolean PS2X::read_gamepad(boolean motor1, byte motor2)
101{
102 double temp = millis() - last_read;
103
104 if (temp > 1500) // waited to long
106
107 if (temp < read_delay) // waited too short
108 delay(read_delay - temp);
109
110 if (motor2 != 0x00)
111 motor2 = map(motor2, 0, 255, 0x40, 0xFF); // noting below 40 will make it spin
112
113 byte dword[9] = {0x01, 0x42, 0, motor1, motor2, 0, 0, 0, 0};
114 byte dword2[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
115
116 // Try a few times to get valid data...
117 for (byte RetryCnt = 0; RetryCnt < 5; RetryCnt++) {
118 CMD_SET();
119 CLK_SET();
120 ATT_CLR(); // low enable joystick
121
122 delayMicroseconds(CTRL_BYTE_DELAY);
123 // Send the command to send button and joystick data;
124 for (int i = 0; i < 9; i++) {
125 PS2data[i] = _gamepad_shiftinout(dword[i]);
126 }
127
128 if (PS2data[1] == 0x79) { // if controller is in full data return mode, get
129 // the rest of data
130 for (int i = 0; i < 12; i++) {
131 PS2data[i + 9] = _gamepad_shiftinout(dword2[i]);
132 }
133 }
134
135 ATT_SET(); // HI disable joystick
136 // Check to see if we received valid data or not.
137 // We should be in analog mode for our data to be valid (analog == 0x7_)
138 if ((PS2data[1] & 0xf0) == 0x70) break;
139
140 // If we got to here, we are not in analog mode, try to recover...
141 reconfig_gamepad(); // try to get back into Analog mode.
142 delay(read_delay);
143 }
144
145 // If we get here and still not in analog mode (=0x7_), try increasing the
146 // read_delay...
147 if ((PS2data[1] & 0xf0) != 0x70) {
148 if (read_delay < 10) read_delay++; // see if this helps out...
149 }
150
151#ifdef PS2X_COM_DEBUG
152 Serial.print("OUT:IN ");
153 for (int i = 0; i < 9; i++) {
154 Serial.print(dword[i], HEX);
155 Serial.print(":");
156 Serial.print(PS2data[i], HEX);
157 Serial.print(" ");
158 }
159 for (int i = 0; i < 12; i++) {
160 Serial.print(dword2[i], HEX);
161 Serial.print(":");
162 Serial.print(PS2data[i + 9], HEX);
163 Serial.print(" ");
164 }
165 Serial.println("");
166#endif
167
168 last_buttons = buttons; // store the previous buttons states
169
170 buttons =
171 (uint16_t)(PS2data[4] << 8) + PS2data[3]; // store as one value for multiple functions
172
173 last_read = millis();
174 return ((PS2data[1] & 0xf0) == 0x70); // 1 = OK = analog mode - 0 = NOK
175}
176
177/****************************************************************************************/
178byte PS2X::config_gamepad(uint8_t clk, uint8_t cmd, uint8_t att, uint8_t dat)
179{
180 return config_gamepad(clk, cmd, att, dat, false, false);
181}
182
183/****************************************************************************************/
185 uint8_t clk, uint8_t cmd, uint8_t att, uint8_t dat, bool pressures, bool rumble)
186{
187
188 byte temp[sizeof(type_read)];
189
190 _clk_pin = clk;
191 _cmd_pin = cmd;
192 _att_pin = att;
193 _dat_pin = dat;
194
195 pinMode(clk, OUTPUT); // configure ports
196 pinMode(att, OUTPUT);
197 pinMode(cmd, OUTPUT);
198 // #ifdef ESP8266
199 // pinMode(dat, INPUT_PULLUP); // enable pull-up
200 // #else
201 pinMode(dat, INPUT);
202
203 CMD_SET(); // SET(*_cmd_oreg,_cmd_mask);
204 CLK_SET();
205
206 // new error checking. First, read gamepad a few times to see if it's talking
207 read_gamepad();
208 read_gamepad();
209
210 // see if it talked - see if mode came back.
211 // If still anything but 41, 73 or 79, then it's not talking
212 if (PS2data[1] != 0x41 && PS2data[1] != 0x42 && PS2data[1] != 0x73 && PS2data[1] != 0x79) {
213#ifdef PS2X_DEBUG
214 Serial.println("Controller mode not matched or no controller found");
215 Serial.print("Expected 0x41, 0x42, 0x73 or 0x79, but got ");
216 Serial.println(PS2data[1], HEX);
217#endif
218 return 1; // return error code 1
219 }
220
221 // try setting mode, increasing delays if need be.
222 read_delay = 1;
223
224 for (int y = 0; y <= 10; y++) {
225 sendCommandString(enter_config, sizeof(enter_config)); // start config run
226
227 // read type
228 delayMicroseconds(CTRL_BYTE_DELAY);
229
230 CMD_SET();
231 CLK_SET();
232 ATT_CLR(); // low enable joystick
233
234 delayMicroseconds(CTRL_BYTE_DELAY);
235
236 for (int i = 0; i < 9; i++) {
237 temp[i] = _gamepad_shiftinout(type_read[i]);
238 }
239
240 ATT_SET(); // HI disable joystick
241
242 controller_type = temp[3];
243
244 sendCommandString(set_mode, sizeof(set_mode));
245 if (rumble) {
246 sendCommandString(enable_rumble, sizeof(enable_rumble));
247 en_Rumble = true;
248 }
249 if (pressures) {
250 sendCommandString(set_bytes_large, sizeof(set_bytes_large));
251 en_Pressures = true;
252 }
253 sendCommandString(exit_config, sizeof(exit_config));
254
255 read_gamepad();
256
257 if (pressures) {
258 if (PS2data[1] == 0x79) break;
259 if (PS2data[1] == 0x73) return 3;
260 }
261
262 if (PS2data[1] == 0x73) break;
263
264 if (y == 10) {
265#ifdef PS2X_DEBUG
266 Serial.println("Controller not accepting commands");
267 Serial.print("mode still set at");
268 Serial.println(PS2data[1], HEX);
269#endif
270 return 2; // exit function with error
271 }
272 read_delay += 1; // add 1ms to read_delay
273 }
274 return 0; // no error if here
275}
276
277/****************************************************************************************/
278void PS2X::sendCommandString(byte string[], byte len)
279{
280#ifdef PS2X_COM_DEBUG
281 byte temp[len];
282 ATT_CLR(); // low enable joystick
283 delayMicroseconds(CTRL_BYTE_DELAY);
284
285 for (int y = 0; y < len; y++) temp[y] = _gamepad_shiftinout(string[y]);
286
287 ATT_SET(); // high disable joystick
288 delay(read_delay); // wait a few
289
290 Serial.println("OUT:IN Configure");
291 for (int i = 0; i < len; i++) {
292 Serial.print(string[i], HEX);
293 Serial.print(":");
294 Serial.print(temp[i], HEX);
295 Serial.print(" ");
296 }
297 Serial.println("");
298#else
299 ATT_CLR(); // low enable joystick
300 delayMicroseconds(CTRL_BYTE_DELAY);
301 for (int y = 0; y < len; y++) _gamepad_shiftinout(string[y]);
302 ATT_SET(); // high disable joystick
303 delay(read_delay); // wait a few
304#endif
305}
306
307/****************************************************************************************/
309{
310 /*
311 byte temp[sizeof(type_read)];
312
313 sendCommandString(enter_config, sizeof(enter_config));
314
315 delayMicroseconds(CTRL_BYTE_DELAY);
316
317 CMD_SET();
318 CLK_SET();
319 ATT_CLR(); // low enable joystick
320
321 delayMicroseconds(CTRL_BYTE_DELAY);
322
323 for (int i = 0; i<9; i++) {
324 temp[i] = _gamepad_shiftinout(type_read[i]);
325 }
326
327 sendCommandString(exit_config, sizeof(exit_config));
328
329 if(temp[3] == 0x03)
330 return 1;
331 else if(temp[3] == 0x01)
332 return 2;
333
334 return 0;
335 */
336 Serial.print("Controller_type: ");
337 Serial.println(controller_type, HEX);
338 if (controller_type == 0x03)
339 return 1;
340 else if (controller_type == 0x01 && PS2data[1] == 0x42)
341 return 4;
342 else if (controller_type == 0x01 && PS2data[1] != 0x42)
343 return 2;
344 else if (controller_type == 0x0C)
345 return 3; // 2.4G Wireless Dual Shock PS2 Game Controller
346
347 return 0;
348}
349
350/****************************************************************************************/
352{
353 sendCommandString(enter_config, sizeof(enter_config));
354 sendCommandString(enable_rumble, sizeof(enable_rumble));
355 sendCommandString(exit_config, sizeof(exit_config));
356 en_Rumble = true;
357}
358
359/****************************************************************************************/
361{
362 sendCommandString(enter_config, sizeof(enter_config));
363 sendCommandString(set_bytes_large, sizeof(set_bytes_large));
364 sendCommandString(exit_config, sizeof(exit_config));
365
366 read_gamepad();
367 read_gamepad();
368
369 if (PS2data[1] != 0x79) return false;
370
371 en_Pressures = true;
372 return true;
373}
374
375/****************************************************************************************/
377{
378 sendCommandString(enter_config, sizeof(enter_config));
379 sendCommandString(set_mode, sizeof(set_mode));
380 if (en_Rumble) sendCommandString(enable_rumble, sizeof(enable_rumble));
381 if (en_Pressures) sendCommandString(set_bytes_large, sizeof(set_bytes_large));
382 sendCommandString(exit_config, sizeof(exit_config));
383}
384
385/****************************************************************************************/
386// Let's just use digitalWrite() on ESP8266.
387inline void PS2X::CLK_SET(void)
388{
389 digitalWrite(_clk_pin, HIGH);
390}
391
392inline void PS2X::CLK_CLR(void)
393{
394 digitalWrite(_clk_pin, LOW);
395}
396
397inline void PS2X::CMD_SET(void)
398{
399 digitalWrite(_cmd_pin, HIGH);
400}
401
402inline void PS2X::CMD_CLR(void)
403{
404 digitalWrite(_cmd_pin, LOW);
405}
406
407inline void PS2X::ATT_SET(void)
408{
409 digitalWrite(_att_pin, HIGH);
410}
411
412inline void PS2X::ATT_CLR(void)
413{
414 digitalWrite(_att_pin, LOW);
415}
416
417inline bool PS2X::DAT_CHK(void)
418{
419 return digitalRead(_dat_pin) ? true : false;
420}
@ y
Merge PS2X Lib into Mini R4.
#define CTRL_BYTE_DELAY
#define CTRL_CLK_HIGH
#define CTRL_CLK
#define CHK(x, y)
byte Analog(byte)
Reads the analog value from the specified analog stick.
byte config_gamepad(uint8_t, uint8_t, uint8_t, uint8_t)
Configures the gamepad.
boolean NewButtonState()
Checks for new button state.
boolean Button(uint16_t)
Checks if a button is currently pressed.
unsigned int ButtonDataByte()
Reads the button data byte.
bool enablePressures()
Enables pressure sensitivity on the controller.
void reconfig_gamepad()
Reconfigures the gamepad.
boolean ButtonPressed(unsigned int)
Checks if a button was just pressed.
boolean ButtonReleased(unsigned int)
Checks if a button was just released.
void read_gamepad()
Reads the gamepad state.
void enableRumble()
Enables rumble functionality on the controller.
byte readType()
Returns the controller type.