diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dbe9c82 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vscode/ \ No newline at end of file diff --git a/PS2X_lib/PS2X_lib.cpp b/PS2X_lib.cpp similarity index 64% rename from PS2X_lib/PS2X_lib.cpp rename to PS2X_lib.cpp index 74ef0f7..6c18740 100644 --- a/PS2X_lib/PS2X_lib.cpp +++ b/PS2X_lib.cpp @@ -56,7 +56,10 @@ byte PS2X::Analog(byte button) { /****************************************************************************************/ unsigned char PS2X::_gamepad_shiftinout (char byte) { - unsigned char tmp = 0; + if(_spi == NULL) { + /* software SPI */ + unsigned char tmp = 0; + for(unsigned char i=0;i<8;i++) { if(CHK(byte,i)) CMD_SET(); else CMD_CLR(); @@ -68,13 +71,18 @@ unsigned char PS2X::_gamepad_shiftinout (char byte) { if(DAT_CHK()) bitSet(tmp,i); CLK_SET(); -#if CTRL_CLK_HIGH - delayMicroseconds(CTRL_CLK_HIGH); -#endif + delayMicroseconds(CTRL_CLK); + } CMD_SET(); delayMicroseconds(CTRL_BYTE_DELAY); return tmp; + } else { + unsigned char tmp = _spi->transfer(byte); // hardware SPI + delayMicroseconds(CTRL_BYTE_DELAY); + return tmp; + } + } /****************************************************************************************/ @@ -100,11 +108,7 @@ boolean PS2X::read_gamepad(boolean motor1, byte motor2) { // Try a few times to get valid data... for (byte RetryCnt = 0; RetryCnt < 5; RetryCnt++) { - CMD_SET(); - CLK_SET(); - ATT_CLR(); // low enable joystick - - delayMicroseconds(CTRL_BYTE_DELAY); + BEGIN_SPI(); //Send the command to send button and joystick data; for (int i = 0; i<9; i++) { PS2data[i] = _gamepad_shiftinout(dword[i]); @@ -116,7 +120,8 @@ boolean PS2X::read_gamepad(boolean motor1, byte motor2) { } } - ATT_SET(); // HI disable joystick + END_SPI(); + // Check to see if we received valid data or not. // We should be in analog mode for our data to be valid (analog == 0x7_) if ((PS2data[1] & 0xf0) == 0x70) @@ -168,61 +173,102 @@ byte PS2X::config_gamepad(uint8_t clk, uint8_t cmd, uint8_t att, uint8_t dat) { /****************************************************************************************/ byte PS2X::config_gamepad(uint8_t clk, uint8_t cmd, uint8_t att, uint8_t dat, bool pressures, bool rumble) { - - byte temp[sizeof(type_read)]; - -#ifdef __AVR__ - _clk_mask = digitalPinToBitMask(clk); - _clk_oreg = portOutputRegister(digitalPinToPort(clk)); - _cmd_mask = digitalPinToBitMask(cmd); - _cmd_oreg = portOutputRegister(digitalPinToPort(cmd)); - _att_mask = digitalPinToBitMask(att); - _att_oreg = portOutputRegister(digitalPinToPort(att)); - _dat_mask = digitalPinToBitMask(dat); - _dat_ireg = portInputRegister(digitalPinToPort(dat)); -#else -#ifdef ESP8266 - _clk_pin = clk; - _cmd_pin = cmd; - _att_pin = att; - _dat_pin = dat; -#else +#if defined(HAVE_PORTREG_IO) + _clk_mask = (port_mask_t) digitalPinToBitMask(clk); + _clk_oreg = (port_reg_t*) portOutputRegister(digitalPinToPort(clk)); + _cmd_mask = (port_mask_t) digitalPinToBitMask(cmd); + _cmd_oreg = (port_reg_t*) portOutputRegister(digitalPinToPort(cmd)); + _att_mask = (port_mask_t) digitalPinToBitMask(att); + _att_oreg = (port_reg_t*) portOutputRegister(digitalPinToPort(att)); + _dat_mask = (port_mask_t) digitalPinToBitMask(dat); + _dat_ireg = (port_reg_t*) portInputRegister(digitalPinToPort(dat)); +#elif defined(HAVE_PORTREG_SC) // well it seems that this varies from platform to platform so... +#if defined(__PIC32__) uint32_t lport; // Port number for this pin - _clk_mask = digitalPinToBitMask(clk); + _clk_mask = (port_mask_t) digitalPinToBitMask(clk); lport = digitalPinToPort(clk); - _clk_lport_set = portOutputRegister(lport) + 2; - _clk_lport_clr = portOutputRegister(lport) + 1; + _clk_lport_set = (port_reg_t*) portOutputRegister(lport) + 2; + _clk_lport_clr = (port_reg_t*) portOutputRegister(lport) + 1; - _cmd_mask = digitalPinToBitMask(cmd); + _cmd_mask = (port_mask_t) digitalPinToBitMask(cmd); lport = digitalPinToPort(cmd); - _cmd_lport_set = portOutputRegister(lport) + 2; - _cmd_lport_clr = portOutputRegister(lport) + 1; + _cmd_lport_set = (port_reg_t*) portOutputRegister(lport) + 2; + _cmd_lport_clr = (port_reg_t*) portOutputRegister(lport) + 1; - _att_mask = digitalPinToBitMask(att); + _att_mask = (port_mask_t) digitalPinToBitMask(att); lport = digitalPinToPort(att); - _att_lport_set = portOutputRegister(lport) + 2; - _att_lport_clr = portOutputRegister(lport) + 1; + _att_lport_set = (port_reg_t*) portOutputRegister(lport) + 2; + _att_lport_clr = (port_reg_t*) portOutputRegister(lport) + 1; - _dat_mask = digitalPinToBitMask(dat); - _dat_lport = portInputRegister(digitalPinToPort(dat)); + _dat_mask = (port_mask_t) digitalPinToBitMask(dat); + _dat_lport = (port_reg_t*) portInputRegister(digitalPinToPort(dat)); #endif +#else + _clk_pin = clk; + _cmd_pin = cmd; + _att_pin = att; + _dat_pin = dat; #endif pinMode(clk, OUTPUT); //configure ports - pinMode(att, OUTPUT); + pinMode(att, OUTPUT); ATT_SET(); pinMode(cmd, OUTPUT); -#ifdef ESP8266 pinMode(dat, INPUT_PULLUP); // enable pull-up + + // CMD_SET(); // SET(*_cmd_oreg,_cmd_mask); + CLK_SET(); + + return config_gamepad_stub(pressures, rumble); +} + +byte PS2X::config_gamepad(SPIClass* spi, uint8_t att) { + return config_gamepad(spi, att, false, false, true); +} + +byte PS2X::config_gamepad(SPIClass* spi, uint8_t att, bool begin) { + return config_gamepad(spi, att, false, false, begin); +} + +byte PS2X::config_gamepad(SPIClass* spi, uint8_t att, bool pressures, bool rumble) { + return config_gamepad(spi, att, pressures, rumble, true); +} + +byte PS2X::config_gamepad(SPIClass* spi, uint8_t att, bool pressures, bool rumble, bool begin) { + _spi = spi; + #if defined(HAVE_PORTREG_IO) + _att_mask = (port_mask_t) digitalPinToBitMask(att); + _att_oreg = (port_reg_t*) portOutputRegister(digitalPinToPort(att)); +#elif defined(HAVE_PORTREG_SC) // well it seems that this varies from platform to platform so... +#if defined(__PIC32__) + uint32_t lport; // Port number for this pin + _att_mask = (port_mask_t) digitalPinToBitMask(att); + lport = digitalPinToPort(att); + _att_lport_set = (port_reg_t*) portOutputRegister(lport) + 2; + _att_lport_clr = (port_reg_t*) portOutputRegister(lport) + 1; +#endif #else - pinMode(dat, INPUT); + _att_pin = att; #endif -#if defined(__AVR__) - digitalWrite(dat, HIGH); //enable pull-up + pinMode(att, OUTPUT); ATT_SET(); + +#if defined(SPI_HAS_TRANSACTION) + _spi_settings = SPISettings(CTRL_BITRATE, LSBFIRST, SPI_MODE0); #endif - CMD_SET(); // SET(*_cmd_oreg,_cmd_mask); - CLK_SET(); + if(begin) _spi->begin(); // begin SPI with default settings + + /* some hardware SPI implementations incorrectly hold CLK low before the first transaction, so we'll try to fix that */ + BEGIN_SPI_NOATT(); + _spi->transfer(0x55); // anything will work here + END_SPI_NOATT(); + + return config_gamepad_stub(pressures, rumble); +} + +byte PS2X::config_gamepad_stub(bool pressures, bool rumble) { + byte temp[sizeof(type_read)]; + //new error checking. First, read gamepad a few times to see if it's talking read_gamepad(); @@ -242,23 +288,24 @@ byte PS2X::config_gamepad(uint8_t clk, uint8_t cmd, uint8_t att, uint8_t dat, bo //try setting mode, increasing delays if need be. read_delay = 1; + t_last_att = millis() + CTRL_PACKET_DELAY; // start reading right away + for(int y = 0; y <= 10; y++) { sendCommandString(enter_config, sizeof(enter_config)); //start config run //read type delayMicroseconds(CTRL_BYTE_DELAY); - CMD_SET(); - CLK_SET(); - ATT_CLR(); // low enable joystick + //CLK_SET(); // CLK should've been set to HIGH already + BEGIN_SPI(); - delayMicroseconds(CTRL_BYTE_DELAY); for (int i = 0; i<9; i++) { temp[i] = _gamepad_shiftinout(type_read[i]); } - ATT_SET(); // HI disable joystick + END_SPI(); + controller_type = temp[3]; @@ -296,13 +343,13 @@ byte PS2X::config_gamepad(uint8_t clk, uint8_t cmd, uint8_t att, uint8_t dat, bo void PS2X::sendCommandString(byte string[], byte len) { #ifdef PS2X_COM_DEBUG byte temp[len]; - ATT_CLR(); // low enable joystick - delayMicroseconds(CTRL_BYTE_DELAY); + BEGIN_SPI(); for (int y=0; y < len; y++) temp[y] = _gamepad_shiftinout(string[y]); - ATT_SET(); //high disable joystick + END_SPI(); + delay(read_delay); //wait a few Serial.println("OUT:IN Configure"); @@ -314,11 +361,11 @@ void PS2X::sendCommandString(byte string[], byte len) { } Serial.println(""); #else - ATT_CLR(); // low enable joystick - delayMicroseconds(CTRL_BYTE_DELAY); + BEGIN_SPI(); for (int y=0; y < len; y++) _gamepad_shiftinout(string[y]); - ATT_SET(); //high disable joystick + END_SPI(); + delay(read_delay); //wait a few #endif } @@ -401,112 +448,232 @@ void PS2X::reconfig_gamepad(){ } /****************************************************************************************/ -#ifdef __AVR__ +#if defined(HAVE_PORTREG_IO) inline void PS2X::CLK_SET(void) { +#if defined(__AVR__) // there should be a platform-independent way to do this register uint8_t old_sreg = SREG; cli(); +#endif *_clk_oreg |= _clk_mask; +#if defined(__AVR__) SREG = old_sreg; +#endif } inline void PS2X::CLK_CLR(void) { +#if defined(__AVR__) register uint8_t old_sreg = SREG; cli(); +#endif *_clk_oreg &= ~_clk_mask; +#if defined(__AVR__) SREG = old_sreg; +#endif } inline void PS2X::CMD_SET(void) { +#if defined(__AVR__) register uint8_t old_sreg = SREG; cli(); +#endif *_cmd_oreg |= _cmd_mask; // SET(*_cmd_oreg,_cmd_mask); +#if defined(__AVR__) SREG = old_sreg; +#endif } inline void PS2X::CMD_CLR(void) { +#if defined(__AVR__) register uint8_t old_sreg = SREG; cli(); +#endif *_cmd_oreg &= ~_cmd_mask; // SET(*_cmd_oreg,_cmd_mask); +#if defined(__AVR__) SREG = old_sreg; +#endif } inline void PS2X::ATT_SET(void) { +#if defined(__AVR__) register uint8_t old_sreg = SREG; cli(); +#endif *_att_oreg |= _att_mask ; +#if defined(__AVR__) SREG = old_sreg; +#endif } inline void PS2X::ATT_CLR(void) { +#if defined(__AVR__) register uint8_t old_sreg = SREG; cli(); +#endif *_att_oreg &= ~_att_mask; +#if defined(__AVR__) SREG = old_sreg; +#endif + } inline bool PS2X::DAT_CHK(void) { return (*_dat_ireg & _dat_mask) ? true : false; } -#else -#ifdef ESP8266 -// Let's just use digitalWrite() on ESP8266. +#elif defined(HAVE_PORTREG_SC) inline void PS2X::CLK_SET(void) { - digitalWrite(_clk_pin, HIGH); + *_clk_lport_set |= _clk_mask; } inline void PS2X::CLK_CLR(void) { - digitalWrite(_clk_pin, LOW); + *_clk_lport_clr |= _clk_mask; } inline void PS2X::CMD_SET(void) { - digitalWrite(_cmd_pin, HIGH); + *_cmd_lport_set |= _cmd_mask; } inline void PS2X::CMD_CLR(void) { - digitalWrite(_cmd_pin, LOW); + *_cmd_lport_clr |= _cmd_mask; } inline void PS2X::ATT_SET(void) { - digitalWrite(_att_pin, HIGH); + *_att_lport_set |= _att_mask; } inline void PS2X::ATT_CLR(void) { - digitalWrite(_att_pin, LOW); + *_att_lport_clr |= _att_mask; } inline bool PS2X::DAT_CHK(void) { - return digitalRead(_dat_pin) ? true : false; + return (*_dat_lport & _dat_mask) ? true : false; } #else -// On pic32, use the set/clr registers to make them atomic... inline void PS2X::CLK_SET(void) { - *_clk_lport_set |= _clk_mask; + digitalWrite(_clk_pin, HIGH); } inline void PS2X::CLK_CLR(void) { - *_clk_lport_clr |= _clk_mask; + digitalWrite(_clk_pin, LOW); } inline void PS2X::CMD_SET(void) { - *_cmd_lport_set |= _cmd_mask; + digitalWrite(_cmd_pin, HIGH); } inline void PS2X::CMD_CLR(void) { - *_cmd_lport_clr |= _cmd_mask; + digitalWrite(_cmd_pin, LOW); } inline void PS2X::ATT_SET(void) { - *_att_lport_set |= _att_mask; + digitalWrite(_att_pin, HIGH); } inline void PS2X::ATT_CLR(void) { - *_att_lport_clr |= _att_mask; + digitalWrite(_att_pin, LOW); } inline bool PS2X::DAT_CHK(void) { - return (*_dat_lport & _dat_mask) ? true : false; + return digitalRead(_dat_pin) ? true : false; +} + +#endif + +inline void PS2X::BEGIN_SPI_NOATT(void) { + if(_spi != NULL) { +#if defined(SPI_HAS_TRANSACTION) + _spi->beginTransaction(_spi_settings); +#else + // _spi->begin(); + _spi->setBitOrder(LSBFIRST); + _spi->setDataMode(SPI_MODE2); +#if defined(__AVR__) + _spi->setClockDivider(CTRL_DIVIDER); +#elif defined(__SAM3X8E__) + _spi->setClockDivider(F_CPU / CTRL_BITRATE); +#else + #error Unsupported method of setting clock divider without transaction, please update this library to support this platform, update the platform code to support SPI transaction, or use software SPI. +#endif +#endif + } else { + CMD_CLR(); + CLK_SET(); + } +} + +inline void PS2X::BEGIN_SPI(void) { + BEGIN_SPI_NOATT(); + while(millis() - t_last_att < CTRL_PACKET_DELAY); + ATT_CLR(); // low enable joystick + delayMicroseconds(CTRL_BYTE_DELAY); } +inline void PS2X::END_SPI_NOATT(void) { + if(_spi != NULL) { +#if defined(SPI_HAS_TRANSACTION) + _spi->endTransaction(); +#else + // _spi->end(); #endif + } else { + CMD_CLR(); + CLK_SET(); + } +} + +inline void PS2X::END_SPI(void) { + ATT_SET(); + END_SPI_NOATT(); + t_last_att = millis(); +} + +/****************************************************************************************/ +byte PS2X::config_gamepad_arduino_spi(uint8_t att) { + return config_gamepad_arduino_spi(att, false, false); +} + +byte PS2X::config_gamepad_arduino_spi(uint8_t att, bool pressures, bool rumble) { + return config_gamepad(&SPI, att, pressures, rumble); +} + +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 +#define VSPI FSPI #endif +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 +byte PS2X::config_gamepad_esp32_hspi(uint8_t att) { + return config_gamepad_esp32_hspi(att, false, false); +} + +byte PS2X::config_gamepad_esp32_hspi(uint8_t att, bool pressures, bool rumble) { + return config_gamepad(new SPIClass(HSPI), att, pressures, rumble); +} + +byte PS2X::config_gamepad_esp32_hspi(uint8_t clk, uint8_t cmd, uint8_t att, uint8_t dat) { + return config_gamepad_esp32_hspi(clk, cmd, att, dat, false, false); +} + +byte PS2X::config_gamepad_esp32_hspi(uint8_t clk, uint8_t cmd, uint8_t att, uint8_t dat, bool pressures, bool rumble) { + SPIClass* spi_class = new SPIClass(HSPI); + spi_class->begin(clk, dat, cmd, att); + return config_gamepad(spi_class, att, pressures, rumble, false); +} + +byte PS2X::config_gamepad_esp32_vspi(uint8_t att) { + return config_gamepad_esp32_vspi(att, false, false); +} + +byte PS2X::config_gamepad_esp32_vspi(uint8_t att, bool pressures, bool rumble) { + return config_gamepad(new SPIClass(VSPI), att, pressures, rumble); +} + +byte PS2X::config_gamepad_esp32_vspi(uint8_t clk, uint8_t cmd, uint8_t att, uint8_t dat) { + return config_gamepad_esp32_vspi(clk, cmd, att, dat, false, false); +} + +byte PS2X::config_gamepad_esp32_vspi(uint8_t clk, uint8_t cmd, uint8_t att, uint8_t dat, bool pressures, bool rumble) { + SPIClass* spi_class = new SPIClass(VSPI); + spi_class->begin(clk, dat, cmd, att); + return config_gamepad(spi_class, att, pressures, rumble, false); +} +#endif + diff --git a/PS2X_lib/PS2X_lib.h b/PS2X_lib.h similarity index 53% rename from PS2X_lib/PS2X_lib.h rename to PS2X_lib.h index 303f0e7..e440cc2 100644 --- a/PS2X_lib/PS2X_lib.h +++ b/PS2X_lib.h @@ -89,23 +89,55 @@ GNU General Public License for more details. #include #include #include -#ifdef __AVR__ - // AVR - #include - #define CTRL_CLK 4 - #define CTRL_BYTE_DELAY 3 +#include + +/* SPI timing configuration */ +#define CTRL_BITRATE 250000UL // SPI bitrate (Hz). Please note that on AVR Arduinos, the lowest bitrate possible is 125kHz. +#if (1000000UL / (2 * CTRL_BITRATE) > 0) +#define CTRL_CLK (1000000UL / (2 * CTRL_BITRATE)) // delay duration between SCK high and low #else -#ifdef ESP8266 - #define CTRL_CLK 5 - #define CTRL_CLK_HIGH 5 - #define CTRL_BYTE_DELAY 18 +#define CTRL_CLK 1 +#endif +#define CTRL_BYTE_DELAY 10 // delay duration between byte reads (uS) +#define CTRL_PACKET_DELAY 16 // delay duration between packets (mS) - according to playstation.txt this should be set to 16mS, but it seems that it can go down to 4mS without problems +#if !defined(SPI_HAS_TRANSACTION) && defined(__AVR__) +// SPI divider for AVR +#if (F_CPU / CTRL_BITRATE < 3) +#define CTRL_DIVIDER SPI_CLOCK_DIV2 +#elif (F_CPU / CTRL_BITRATE < 6) +#define CTRL_DIVIDER SPI_CLOCK_DIV4 +#elif (F_CPU / CTRL_BITRATE < 12) +#define CTRL_DIVIDER SPI_CLOCK_DIV8 +#elif (F_CPU / CTRL_BITRATE < 24) +#define CTRL_DIVIDER SPI_CLOCK_DIV16 +#elif (F_CPU / CTRL_BITRATE < 48) +#define CTRL_DIVIDER SPI_CLOCK_DIV32 +#elif (F_CPU / CTRL_BITRATE < 96) +#define CTRL_DIVIDER SPI_CLOCK_DIV64 #else - // Pic32... - #include - #define CTRL_CLK 5 - #define CTRL_CLK_HIGH 5 - #define CTRL_BYTE_DELAY 4 -#endif +#define CTRL_DIVIDER SPI_CLOCK_DIV128 +#endif +#endif + +/* port register data types */ +#if defined(__AVR__) +typedef volatile uint8_t port_reg_t; +typedef uint8_t port_mask_t; +#define HAVE_PORTREG_IO +#elif defined(__SAM3X8E__) +typedef volatile RwReg port_reg_t; +typedef uint32_t port_mask_t; +#define HAVE_PORTREG_IO +#elif defined(__PIC32__) // TODO: is this how we're supposed to detect PIC32? +typedef volatile uint32_t port_reg_t; +typedef uint16_t port_mask_t; +#define HAVE_PORTREG_SC +#elif (defined(__arm__) || defined(ARDUINO_FEATHER52)) && \ + !defined(ARDUINO_ARCH_MBED) && !defined(ARDUINO_ARCH_RP2040) +typedef volatile uint32_t port_reg_t; +typedef uint32_t port_mask_t; +#define HAVE_PORTREG_IO + #endif //These are our button constants @@ -183,8 +215,30 @@ class PS2X { void read_gamepad(); boolean read_gamepad(boolean, byte); byte readType(); - byte config_gamepad(uint8_t, uint8_t, uint8_t, uint8_t); - byte config_gamepad(uint8_t, uint8_t, uint8_t, uint8_t, bool, bool); + /* config_gamepad for software SPI */ + byte config_gamepad(uint8_t, uint8_t, uint8_t, uint8_t); // specify pins, pressure and rumble disabled + byte config_gamepad(uint8_t, uint8_t, uint8_t, uint8_t, bool, bool); // specify pins AND pressure&rumble mode + /* config_gamepad for hardware SPI */ + byte config_gamepad(SPIClass*, uint8_t); // specify SPIClass and ATT pin, begins SPI by itself + byte config_gamepad(SPIClass*, uint8_t, bool); // specify SPIClass and ATT pin, as well as whether to begin SPI + byte config_gamepad(SPIClass*, uint8_t, bool, bool); // specify SPIClass, ATT pin and pressure&rumble mode, begins SPI by itself + byte config_gamepad(SPIClass*, uint8_t, bool, bool, bool); // specify SPIClass, ATT pin, pressure&rumble mode, and whether to begin SPI + // ready-to-use config functions for select boards (right now only supports Arduino with default SPI port and ESP32 HSPI and VSPI) + byte config_gamepad_arduino_spi(uint8_t); // specify ATT pin. please note that using this on ESP32 is functionally similar to config_gamepad_esp32_vspi(uint8_t) + byte config_gamepad_arduino_spi(uint8_t, bool, bool); // specify ATT pin and pressure&rumble mode. please note that using this on ESP32 is functionally similar to config_gamepad_esp32_vspi(uint8_t, bool, bool) +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 + // HSPI + byte config_gamepad_esp32_hspi(uint8_t); // use HSPI with custom ATT pin + byte config_gamepad_esp32_hspi(uint8_t, bool, bool); // use HSPI with custom ATT pin, also specify whether to enable pressure and rumble + byte config_gamepad_esp32_hspi(uint8_t, uint8_t, uint8_t, uint8_t); // use HSPI with custom pins + byte config_gamepad_esp32_hspi(uint8_t, uint8_t, uint8_t, uint8_t, bool, bool); // use HSPI with custom pins, also specify whether to enable pressure and rumble + // VSPI + byte config_gamepad_esp32_vspi(uint8_t); // use VSPI with custom ATT pin + byte config_gamepad_esp32_vspi(uint8_t, bool, bool); // use VSPI with custom ATT pin, also specify whether to enable pressure and rumble + byte config_gamepad_esp32_vspi(uint8_t, uint8_t, uint8_t, uint8_t); // use VSPI with custom pins + byte config_gamepad_esp32_vspi(uint8_t, uint8_t, uint8_t, uint8_t, bool, bool); // use VSPI with custom pins, also specify whether to enable pressure and rumble +#endif + void enableRumble(); bool enablePressures(); byte Analog(byte); @@ -198,45 +252,60 @@ class PS2X { inline void ATT_SET(void); inline void ATT_CLR(void); inline bool DAT_CHK(void); + + inline void BEGIN_SPI_NOATT(void); + inline void END_SPI_NOATT(void); + + inline void BEGIN_SPI(void); + inline void END_SPI(void); + byte config_gamepad_stub(bool, bool); // common gamepad initialization sequence + unsigned char _gamepad_shiftinout (char); unsigned char PS2data[21]; void sendCommandString(byte*, byte); unsigned char i; unsigned int last_buttons; unsigned int buttons; - - #ifdef __AVR__ - uint8_t maskToBitNum(uint8_t); - uint8_t _clk_mask; - volatile uint8_t *_clk_oreg; - uint8_t _cmd_mask; - volatile uint8_t *_cmd_oreg; - uint8_t _att_mask; - volatile uint8_t *_att_oreg; - uint8_t _dat_mask; - volatile uint8_t *_dat_ireg; - #else - #ifdef ESP8266 + + /* pin I/O configuration, mostly relevant to software SPI support (except ATT which is used in both software and hardware SPI) */ + #if defined(HAVE_PORTREG_IO) // platform has port registers in input/output configuration (eg. AVR, STM32) + port_mask_t _clk_mask; + port_reg_t *_clk_oreg; + port_mask_t _cmd_mask; + port_reg_t *_cmd_oreg; + port_mask_t _att_mask; + port_reg_t *_att_oreg; + port_mask_t _dat_mask; + port_reg_t *_dat_ireg; + #elif defined(HAVE_PORTREG_SC) // platform has port registers in set/clear configuration (eg. PIC32) + port_mask_t _clk_mask; + port_reg_t *_clk_lport_set; + port_reg_t *_clk_lport_clr; + port_mask_t _cmd_mask; + port_reg_t *_cmd_lport_set; + port_reg_t *_cmd_lport_clr; + port_mask_t _att_mask; + port_reg_t *_att_lport_set; + port_reg_t *_att_lport_clr; + port_mask_t _dat_mask; + port_reg_t *_dat_lport; +#else // platform does not have port registers (eg. ESP8266, ESP32, ESP32C3, ESP32S3) + int _clk_pin; int _cmd_pin; int _att_pin; int _dat_pin; - #else - uint8_t maskToBitNum(uint8_t); - uint16_t _clk_mask; - volatile uint32_t *_clk_lport_set; - volatile uint32_t *_clk_lport_clr; - uint16_t _cmd_mask; - volatile uint32_t *_cmd_lport_set; - volatile uint32_t *_cmd_lport_clr; - uint16_t _att_mask; - volatile uint32_t *_att_lport_set; - volatile uint32_t *_att_lport_clr; - uint16_t _dat_mask; - volatile uint32_t *_dat_lport; #endif + + /* SPI configuration */ + SPIClass* _spi; // hardware SPI class (null = software SPI) + #if defined(SPI_HAS_TRANSACTION) + SPISettings _spi_settings; // hardware SPI transaction settings #endif + + volatile unsigned long t_last_att; // time since last ATT inactive + unsigned long last_read; byte read_delay; diff --git a/README.md b/README.md new file mode 100644 index 0000000..49bf132 --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ +## Giới thiệu + +Thư viện tay cầm PS2 dành cho mạch VIA Makerbot ESP32 +Thư viện này giúp các bạn có thể sử dụng tay cầm PS2 cho mạch VIA Makerbot + +Thư viện này là 1 bản sao thư viện tay cầm PS2 của 2 tác giả [madsci1016](https://github.com/madsci1016/Arduino-PS2X) và [MyArduinoLib](https://github.com/MyArduinoLib/Arduino-PS2X-ESP32) được chỉnh sửa lại để sử dụng với mạch VIA Makerbot ESP32 + +## Sử dụng thư viện PSX2 với mạch Makerbot BANHMI + + + +## Khởi tạo thư viện: + + + +``` + while (error != 0) { + delay(1000);// 1 second wait + //setup pins and settings: GamePad(clock, command, attention, data, Pressures?, Rumble?) check for error + error = ps2x.config_gamepad(PS2_CLK, PS2_CMD, PS2_SEL, PS2_DAT, pressures, rumble); + Serial.print("#try config "); + Serial.println(tryNum); + tryNum ++; + } +``` + + + diff --git a/PS2X_lib/examples/PS2XMouse/PS2XMouse.ino b/examples/PS2XMouse/PS2XMouse.ino similarity index 99% rename from PS2X_lib/examples/PS2XMouse/PS2XMouse.ino rename to examples/PS2XMouse/PS2XMouse.ino index c50a7cb..2c8f617 100644 --- a/PS2X_lib/examples/PS2XMouse/PS2XMouse.ino +++ b/examples/PS2XMouse/PS2XMouse.ino @@ -147,4 +147,5 @@ int readAxis(int thisAxis) { // return the distance for this axis: return distance; -} + +} diff --git a/PS2X_lib/examples/PS2X_Example/PS2X_Example.ino b/examples/PS2X_Example/PS2X_Example.ino similarity index 56% rename from PS2X_lib/examples/PS2X_Example/PS2X_Example.ino rename to examples/PS2X_Example/PS2X_Example.ino index f1c64c8..3a82a07 100644 --- a/PS2X_lib/examples/PS2X_Example/PS2X_Example.ino +++ b/examples/PS2X_Example/PS2X_Example.ino @@ -1,189 +1,226 @@ -#include //for v1.6 - -/****************************************************************** - * set pins connected to PS2 controller: - * - 1e column: original - * - 2e colmun: Stef? - * replace pin numbers by the ones you use - ******************************************************************/ -#define PS2_DAT 13 //14 -#define PS2_CMD 11 //15 -#define PS2_SEL 10 //16 -#define PS2_CLK 12 //17 - -/****************************************************************** - * select modes of PS2 controller: - * - pressures = analog reading of push-butttons - * - rumble = motor rumbling - * uncomment 1 of the lines for each mode selection - ******************************************************************/ -//#define pressures true -#define pressures false -//#define rumble true -#define rumble false - -PS2X ps2x; // create PS2 Controller Class - -//right now, the library does NOT support hot pluggable controllers, meaning -//you must always either restart your Arduino after you connect the controller, -//or call config_gamepad(pins) again after connecting the controller. - -int error = 0; -byte type = 0; -byte vibrate = 0; - -void setup(){ - - Serial.begin(57600); - - delay(300); //added delay to give wireless ps2 module some time to startup, before configuring it - - //CHANGES for v1.6 HERE!!! **************PAY ATTENTION************* - - //setup pins and settings: GamePad(clock, command, attention, data, Pressures?, Rumble?) check for error - error = ps2x.config_gamepad(PS2_CLK, PS2_CMD, PS2_SEL, PS2_DAT, pressures, rumble); - - if(error == 0){ - Serial.print("Found Controller, configured successful "); - Serial.print("pressures = "); - if (pressures) - Serial.println("true "); - else - Serial.println("false"); - Serial.print("rumble = "); - if (rumble) - Serial.println("true)"); - else - Serial.println("false"); - Serial.println("Try out all the buttons, X will vibrate the controller, faster as you press harder;"); - Serial.println("holding L1 or R1 will print out the analog stick values."); - Serial.println("Note: Go to www.billporter.info for updates and to report bugs."); - } - else if(error == 1) - Serial.println("No controller found, check wiring, see readme.txt to enable debug. visit www.billporter.info for troubleshooting tips"); - - else if(error == 2) - Serial.println("Controller found but not accepting commands. see readme.txt to enable debug. Visit www.billporter.info for troubleshooting tips"); - - else if(error == 3) - Serial.println("Controller refusing to enter Pressures mode, may not support it. "); - -// Serial.print(ps2x.Analog(1), HEX); - - type = ps2x.readType(); - switch(type) { - case 0: - Serial.print("Unknown Controller type found "); - break; - case 1: - Serial.print("DualShock Controller found "); - break; - case 2: - Serial.print("GuitarHero Controller found "); - break; - case 3: - Serial.print("Wireless Sony DualShock Controller found "); - break; - } -} - -void loop() { - /* You must Read Gamepad to get new values and set vibration values - ps2x.read_gamepad(small motor on/off, larger motor strenght from 0-255) - if you don't enable the rumble, use ps2x.read_gamepad(); with no values - You should call this at least once a second - */ - if(error == 1) //skip loop if no controller found - return; - - if(type == 2){ //Guitar Hero Controller - ps2x.read_gamepad(); //read controller - - if(ps2x.ButtonPressed(GREEN_FRET)) - Serial.println("Green Fret Pressed"); - if(ps2x.ButtonPressed(RED_FRET)) - Serial.println("Red Fret Pressed"); - if(ps2x.ButtonPressed(YELLOW_FRET)) - Serial.println("Yellow Fret Pressed"); - if(ps2x.ButtonPressed(BLUE_FRET)) - Serial.println("Blue Fret Pressed"); - if(ps2x.ButtonPressed(ORANGE_FRET)) - Serial.println("Orange Fret Pressed"); - - if(ps2x.ButtonPressed(STAR_POWER)) - Serial.println("Star Power Command"); - - if(ps2x.Button(UP_STRUM)) //will be TRUE as long as button is pressed - Serial.println("Up Strum"); - if(ps2x.Button(DOWN_STRUM)) - Serial.println("DOWN Strum"); - - if(ps2x.Button(PSB_START)) //will be TRUE as long as button is pressed - Serial.println("Start is being held"); - if(ps2x.Button(PSB_SELECT)) - Serial.println("Select is being held"); - - if(ps2x.Button(ORANGE_FRET)) { // print stick value IF TRUE - Serial.print("Wammy Bar Position:"); - Serial.println(ps2x.Analog(WHAMMY_BAR), DEC); - } - } - else { //DualShock Controller - ps2x.read_gamepad(false, vibrate); //read controller and set large motor to spin at 'vibrate' speed - - if(ps2x.Button(PSB_START)) //will be TRUE as long as button is pressed - Serial.println("Start is being held"); - if(ps2x.Button(PSB_SELECT)) - Serial.println("Select is being held"); - - if(ps2x.Button(PSB_PAD_UP)) { //will be TRUE as long as button is pressed - Serial.print("Up held this hard: "); - Serial.println(ps2x.Analog(PSAB_PAD_UP), DEC); - } - if(ps2x.Button(PSB_PAD_RIGHT)){ - Serial.print("Right held this hard: "); - Serial.println(ps2x.Analog(PSAB_PAD_RIGHT), DEC); - } - if(ps2x.Button(PSB_PAD_LEFT)){ - Serial.print("LEFT held this hard: "); - Serial.println(ps2x.Analog(PSAB_PAD_LEFT), DEC); - } - if(ps2x.Button(PSB_PAD_DOWN)){ - Serial.print("DOWN held this hard: "); - Serial.println(ps2x.Analog(PSAB_PAD_DOWN), DEC); - } - - vibrate = ps2x.Analog(PSAB_CROSS); //this will set the large motor vibrate speed based on how hard you press the blue (X) button - if (ps2x.NewButtonState()) { //will be TRUE if any button changes state (on to off, or off to on) - if(ps2x.Button(PSB_L3)) - Serial.println("L3 pressed"); - if(ps2x.Button(PSB_R3)) - Serial.println("R3 pressed"); - if(ps2x.Button(PSB_L2)) - Serial.println("L2 pressed"); - if(ps2x.Button(PSB_R2)) - Serial.println("R2 pressed"); - if(ps2x.Button(PSB_TRIANGLE)) - Serial.println("Triangle pressed"); - } - - if(ps2x.ButtonPressed(PSB_CIRCLE)) //will be TRUE if button was JUST pressed - Serial.println("Circle just pressed"); - if(ps2x.NewButtonState(PSB_CROSS)) //will be TRUE if button was JUST pressed OR released - Serial.println("X just changed"); - if(ps2x.ButtonReleased(PSB_SQUARE)) //will be TRUE if button was JUST released - Serial.println("Square just released"); - - if(ps2x.Button(PSB_L1) || ps2x.Button(PSB_R1)) { //print stick values if either is TRUE - Serial.print("Stick Values:"); - Serial.print(ps2x.Analog(PSS_LY), DEC); //Left stick, Y axis. Other options: LX, RY, RX - Serial.print(","); - Serial.print(ps2x.Analog(PSS_LX), DEC); - Serial.print(","); - Serial.print(ps2x.Analog(PSS_RY), DEC); - Serial.print(","); - Serial.println(ps2x.Analog(PSS_RX), DEC); - } - } - delay(50); -} +#include //for v1.6 +#include // for hardware SPI support + +/****************************************************************** + * set pins connected to PS2 controller: + * - 1e column: original + * - 2e colmun: Stef? + * - 3e column: itsmevjnk (for ESP32 HSPI) + * replace pin numbers by the ones you use + ******************************************************************/ +#define PS2_DAT 13 //14 12 +#define PS2_CMD 11 //15 13 +#define PS2_SEL 10 //16 15 +#define PS2_CLK 12 //17 14 + +/****************************************************************** + * select modes of PS2 controller: + * - pressures = analog reading of push-butttons + * - rumble = motor rumbling + * uncomment 1 of the lines for each mode selection + ******************************************************************/ +//#define pressures true +#define pressures false +//#define rumble true +#define rumble false + +PS2X ps2x; // create PS2 Controller Class + +//right now, the library does NOT support hot pluggable controllers, meaning +//you must always either restart your Arduino after you connect the controller, +//or call config_gamepad(pins) again after connecting the controller. + +int error = 0; +byte type = 0; +byte vibrate = 0; + +void setup(){ + + Serial.begin(57600); + + /* support more flexible waiting times for wireless PS2 module to start up */ + unsigned long t_start = millis(); + Serial.println("Initializing PS2 controller."); + while(1) { + /* + * There are multiple ways to initialize the gamepad, which can be categorized into three levels: + * Level 1: Beginner + * The gamepad can be initialized using these ready-to-use functions, which make use of the platform's hardware SPI bus: + * error = ps2x.config_gamepad_arduino_spi(PS2_SEL); // please note that unless specified with the pressures and rumble arguments, these features will not be used + * error = ps2x.config_gamepad_arduino_spi(PS2_SEL, pressures, rumble); + * A few other functions are available exclusively for the ESP32 to make use of its HSPI and VSPI buses (the examples shown below are for HSPI, to use VSPI just change hspi to vspi): + * error = ps2x.config_gamepad_esp32_hspi(PS2_SEL); + * error = ps2x.config_gamepad_esp32_hspi(PS2_SEL, pressures, rumble); + * error = ps2x.config_gamepad_esp32_hspi(PS2_CLK, PS2_CMD, PS2_SEL, PS2_DAT); // this and the below function use ESP32's SPI pin routing features so that connection is not just limited to the designated pins + * error = ps2x.config_gamepad_esp32_hspi(PS2_CLK, PS2_CMD, PS2_SEL, PS2_DAT, pressures, rumble); + * If hardware SPI is not available, this library also provides a software (bitbanged) SPI solution. To use it, use one of these functions: + * error = ps2x.config_gamepad(PS2_CLK, PS2_CMD, PS2_SEL, PS2_DAT); + * error = ps2x.config_gamepad(PS2_CLK, PS2_CMD, PS2_SEL, PS2_DAT, pressures, rumble); // used below + * Level 2: Intermediate + * Alternatively, if you choose to use a custom SPI class (e.g. software SPI library), or you want to tinker with pointers, these functions are available: + * error = ps2x.config_gamepad(&SPI, PS2_SEL); + * error = ps2x.config_gamepad(&SPI, PS2_SEL, pressures, rumble); + * If you're using something other than the default SPI bus, make sure that you replace &SPI with a pointer (SPIClass*) pointing to the SPI class of your choice. + * Please note that the above functions automatically initialize the SPI class using its begin() function. If you are looking for functions that don't do so, check out Level 3. + * NOTE: On ESP32, the default SPI class refers to the VSPI bus. If you're using HSPI, you have to change &SPI to `new SPIClass(HSPI)` (without the backticks). + * Level 3: Advanced + * Some SPI class implementations (e.g. ESP32) allows for custom configuration in their begin() function (e.g. pin routing). If you wish to be in control of this configuration, use one of these instead: + * error = ps2x.config_gamepad(&SPI, PS2_SEL, false); + * error = ps2x.config_gamepad(&SPI, PS2_SEL, pressures, rumble, false); + * Note the `false` argument at the end. + * You MUST run the SPI class' begin() function (e.g. SPI.begin() in the above example) prior to running the functions above, otherwise initialization will fail. + */ + error = ps2x.config_gamepad(PS2_CLK, PS2_CMD, PS2_SEL, PS2_DAT, pressures, rumble); // software SPI initialization + + if(error == 0){ + Serial.print("Found Controller, configured successful after "); + Serial.print(millis() - t_start, DEC); + Serial.print("ms (pressures = "); + if (pressures) + Serial.print("true"); + else + Serial.print("false"); + Serial.print(", rumble = "); + if (rumble) + Serial.println("true)"); + else + Serial.println("false"); + Serial.println("Try out all the buttons, X will vibrate the controller, faster as you press harder;"); + Serial.println("holding L1 or R1 will print out the analog stick values."); + Serial.println("Note: Go to www.billporter.info for updates and to report bugs."); + break; + } + else if(error == 1) { + Serial.println("No controller found, check wiring, see readme.txt to enable debug. visit www.billporter.info for troubleshooting tips"); + continue; + } + + else if(error == 2) { + Serial.println("Controller found but not accepting commands. see readme.txt to enable debug. Visit www.billporter.info for troubleshooting tips"); + continue; + } + + else if(error == 3) { + Serial.println("Controller refusing to enter Pressures mode, may not support it. "); + break; // non-fatal error + } + } + + type = ps2x.readType(); + switch(type) { + case 0: + Serial.print("Unknown Controller type found "); + break; + case 1: + Serial.print("DualShock Controller found "); + break; + case 2: + Serial.print("GuitarHero Controller found "); + break; + case 3: + Serial.print("Wireless Sony DualShock Controller found "); + break; + } +} + +void loop() { + /* You must Read Gamepad to get new values and set vibration values + ps2x.read_gamepad(small motor on/off, larger motor strenght from 0-255) + if you don't enable the rumble, use ps2x.read_gamepad(); with no values + You should call this at least once a second + */ + if(error == 1) //skip loop if no controller found + return; + + if(type == 2){ //Guitar Hero Controller + ps2x.read_gamepad(); //read controller + + if(ps2x.ButtonPressed(GREEN_FRET)) + Serial.println("Green Fret Pressed"); + if(ps2x.ButtonPressed(RED_FRET)) + Serial.println("Red Fret Pressed"); + if(ps2x.ButtonPressed(YELLOW_FRET)) + Serial.println("Yellow Fret Pressed"); + if(ps2x.ButtonPressed(BLUE_FRET)) + Serial.println("Blue Fret Pressed"); + if(ps2x.ButtonPressed(ORANGE_FRET)) + Serial.println("Orange Fret Pressed"); + + if(ps2x.ButtonPressed(STAR_POWER)) + Serial.println("Star Power Command"); + + if(ps2x.Button(UP_STRUM)) //will be TRUE as long as button is pressed + Serial.println("Up Strum"); + if(ps2x.Button(DOWN_STRUM)) + Serial.println("DOWN Strum"); + + if(ps2x.Button(PSB_START)) //will be TRUE as long as button is pressed + Serial.println("Start is being held"); + if(ps2x.Button(PSB_SELECT)) + Serial.println("Select is being held"); + + if(ps2x.Button(ORANGE_FRET)) { // print stick value IF TRUE + Serial.print("Wammy Bar Position:"); + Serial.println(ps2x.Analog(WHAMMY_BAR), DEC); + } + } + else { //DualShock Controller + ps2x.read_gamepad(false, vibrate); //read controller and set large motor to spin at 'vibrate' speed + + if(ps2x.Button(PSB_START)) //will be TRUE as long as button is pressed + Serial.println("Start is being held"); + if(ps2x.Button(PSB_SELECT)) + Serial.println("Select is being held"); + + if(ps2x.Button(PSB_PAD_UP)) { //will be TRUE as long as button is pressed + Serial.print("Up held this hard: "); + Serial.println(ps2x.Analog(PSAB_PAD_UP), DEC); + } + if(ps2x.Button(PSB_PAD_RIGHT)){ + Serial.print("Right held this hard: "); + Serial.println(ps2x.Analog(PSAB_PAD_RIGHT), DEC); + } + if(ps2x.Button(PSB_PAD_LEFT)){ + Serial.print("LEFT held this hard: "); + Serial.println(ps2x.Analog(PSAB_PAD_LEFT), DEC); + } + if(ps2x.Button(PSB_PAD_DOWN)){ + Serial.print("DOWN held this hard: "); + Serial.println(ps2x.Analog(PSAB_PAD_DOWN), DEC); + } + + vibrate = ps2x.Analog(PSAB_CROSS); //this will set the large motor vibrate speed based on how hard you press the blue (X) button + if (ps2x.NewButtonState()) { //will be TRUE if any button changes state (on to off, or off to on) + if(ps2x.Button(PSB_L3)) + Serial.println("L3 pressed"); + if(ps2x.Button(PSB_R3)) + Serial.println("R3 pressed"); + if(ps2x.Button(PSB_L2)) + Serial.println("L2 pressed"); + if(ps2x.Button(PSB_R2)) + Serial.println("R2 pressed"); + if(ps2x.Button(PSB_TRIANGLE)) + Serial.println("Triangle pressed"); + } + + if(ps2x.ButtonPressed(PSB_CIRCLE)) //will be TRUE if button was JUST pressed + Serial.println("Circle just pressed"); + if(ps2x.NewButtonState(PSB_CROSS)) //will be TRUE if button was JUST pressed OR released + Serial.println("X just changed"); + if(ps2x.ButtonReleased(PSB_SQUARE)) //will be TRUE if button was JUST released + Serial.println("Square just released"); + + if(ps2x.Button(PSB_L1) || ps2x.Button(PSB_R1)) { //print stick values if either is TRUE + Serial.print("Stick Values:"); + Serial.print(ps2x.Analog(PSS_LY), DEC); //Left stick, Y axis. Other options: LX, RY, RX + Serial.print(","); + Serial.print(ps2x.Analog(PSS_LX), DEC); + Serial.print(","); + Serial.print(ps2x.Analog(PSS_RY), DEC); + Serial.print(","); + Serial.println(ps2x.Analog(PSS_RX), DEC); + } + } + delay(50); +} + diff --git a/examples/PS2X_Example_VIA_Makerbot_ESP32/PS2X_Example_VIA_Makerbot_ESP32.ino b/examples/PS2X_Example_VIA_Makerbot_ESP32/PS2X_Example_VIA_Makerbot_ESP32.ino new file mode 100644 index 0000000..dd1fae6 --- /dev/null +++ b/examples/PS2X_Example_VIA_Makerbot_ESP32/PS2X_Example_VIA_Makerbot_ESP32.ino @@ -0,0 +1,121 @@ +#include +/****************************************************************** + * Cài đặt chân cho thư viện : + * - Trên mạch Motorshield của VIA Makerbot BANHMI, có header 6 chân + * được thiết kế để cắm tay cầm PS2. + * Sơ đồ chân header và sơ đồ GPIO tương ứng: + * MOSI | MISO | GND | 3.3V | CS | CLK + * 12 13 GND 3.3V 15 14 + ******************************************************************/ + +#define PS2_DAT 12 // MISO +#define PS2_CMD 13 // MOSI +#define PS2_SEL 15 // SS +#define PS2_CLK 14 // SLK + +/****************************************************************** + * Lựa chọn chế độ cho tay cầm PS2 : + * - pressures = đọc giá trị analog từ các nút bấm + * - rumble = bật/tắt chế độ rung + ******************************************************************/ +#define pressures false +#define rumble false + +PS2X ps2x; // khởi tạo class PS2x + +void setup() +{ + Serial.begin(115200); + Serial.print("Ket noi voi tay cam PS2:"); + + int error = -1; + for (int i = 0; i < 10; i++) // thử kết nối với tay cầm ps2 trong 10 lần + { + delay(1000); // đợi 1 giây + // cài đặt chân và các chế độ: GamePad(clock, command, attention, data, Pressures?, Rumble?) check for error + error = ps2x.config_gamepad(PS2_CLK, PS2_CMD, PS2_SEL, PS2_DAT, pressures, rumble); + Serial.print("."); + } + + switch (error) // kiểm tra lỗi nếu sau 10 lần không kết nối được + { + case 0: + Serial.println(" Ket noi tay cam PS2 thanh cong"); + break; + case 1: + Serial.println(" LOI: Khong tim thay tay cam, hay kiem tra day ket noi vơi tay cam "); + break; + case 2: + Serial.println(" LOI: khong gui duoc lenh"); + break; + case 3: + Serial.println(" LOI: Khong vao duoc Pressures mode "); + break; + } +} + +void loop() +{ + ps2x.read_gamepad(false, false); // gọi hàm để đọc tay điều khiển + + // các trả về giá trị TRUE (1) khi nút được giữ + if (ps2x.Button(PSB_START)) // nếu nút Start được giữ, in ra Serial monitor + Serial.println("Start is being held"); + if (ps2x.Button(PSB_SELECT)) // nếu nút Select được giữ, in ra Serial monitor + Serial.println("Select is being held"); + + if (ps2x.Button(PSB_PAD_UP)) // tương tự như trên kiểm tra nút Lên (PAD UP) + { + Serial.print("Up held this hard: "); + Serial.println(ps2x.Analog(PSAB_PAD_UP), DEC); // đọc giá trị analog ở nút này, xem nút này được bấm mạnh hay nhẹ + } + if (ps2x.Button(PSB_PAD_RIGHT)) + { + Serial.print("Right held this hard: "); + Serial.println(ps2x.Analog(PSAB_PAD_RIGHT), DEC); + } + if (ps2x.Button(PSB_PAD_LEFT)) + { + Serial.print("LEFT held this hard: "); + Serial.println(ps2x.Analog(PSAB_PAD_LEFT), DEC); + } + if (ps2x.Button(PSB_PAD_DOWN)) + { + Serial.print("DOWN held this hard: "); + Serial.println(ps2x.Analog(PSAB_PAD_DOWN), DEC); + } + + if (ps2x.NewButtonState()) + { // Trả về giá trị TRUE khi nút được thay đổi trạng thái (bật sang tắt, or tắt sang bật) + if (ps2x.Button(PSB_L3)) + Serial.println("L3 pressed"); + if (ps2x.Button(PSB_R3)) + Serial.println("R3 pressed"); + if (ps2x.Button(PSB_L2)) + Serial.println("L2 pressed"); + if (ps2x.Button(PSB_R2)) + Serial.println("R2 pressed"); + if (ps2x.Button(PSB_TRIANGLE)) + Serial.println("△ pressed"); + } + //△□○× + if (ps2x.ButtonPressed(PSB_CIRCLE)) // Trả về giá trị TRUE khi nút được ấn (từ tắt sang bật) + Serial.println("○ just pressed"); + if (ps2x.NewButtonState(PSB_CROSS)) // Trả về giá trị TRUE khi nút được thay đổi trạng thái + Serial.println("× just changed"); + if (ps2x.ButtonReleased(PSB_SQUARE)) // Trả về giá trị TRUE khi nút được ấn (từ tắt sang bật) + Serial.println("□ just released"); + + if (ps2x.Button(PSB_L1) || ps2x.Button(PSB_R1)) // các trả về giá trị TRUE khi nút được giữ + { // Đọc giá trị 2 joystick khi nút L1 hoặc R1 được giữ + Serial.print("Stick Values:"); + Serial.print(ps2x.Analog(PSS_LY)); // đọc trục Y của joystick bên trái. Other options: LX, RY, RX + Serial.print(","); + Serial.print(ps2x.Analog(PSS_LX), DEC); + Serial.print(","); + Serial.print(ps2x.Analog(PSS_RY), DEC); + Serial.print(","); + Serial.println(ps2x.Analog(PSS_RX), DEC); + } + delay(50); +} diff --git a/PS2X_lib/keywords.txt b/keywords.txt similarity index 100% rename from PS2X_lib/keywords.txt rename to keywords.txt