/*--------------------------------------------------------------------------
プレイステーションパッド→USB変換(メガドライブミニ対応)
プレイステーション用パッド(デジタルパッド)をメガドライブミニで使えるように
変換する。
注意:
このスケッチは、Arduino Leonardo/Pro Micro(ATmega 32U4)専用です。
パッド側のピン読み出しを最速で行うためポート(PinD)アクセスを利用しているため、
他マイコンと互換性がありませんのでご注意ください。
[参考資料]
このスケッチ作成には以下のURLを参考にしています。
JoystickMD
https://github.com/NibblesLab/JoystickMD
メガドライブミニ を ジョイスティック で遊ぶ ジョイスティックアダプターの作成
https://tounosumura302.netlify.app/posts/201910191643/
Arduino Joystick Library
https://github.com/MHeironimus/ArduinoJoystickLibrary
Arduino PSX Library
https://playground.arduino.cc/Main/PSXLibrary/
SONY PLAYSTATIONR CONTROLLER INFORMATION
https://gamesx.com/controldata/psxcont/psxcont.htm
2020.4.22 BLUE
-----------------------------------------------------------------------------*/
#include <Joystick.h>
#include <Psx.h> // Includes the Psx Library
#define __Debug 0 // 1:シリアルデバッグON
#define __IF_SEGA 1 // 1:SEGA純正パッドを模擬する
// Joystickライブラリ定義
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,JOYSTICK_TYPE_JOYSTICK,
10, 0, // Button Count, Hat Switch Count
true, true, false, // X, Y, and Z Axis
false, false, false, // Rx, but no Ry or Rz
false, false, // No rudder or throttle
false, false, false); // No accelerator, brake, or steering
// PSXコントローラライブラリ定義
Psx Psx;
//PSXコントローラー制御ピン定義
#define dataPin 7 // データ信号
#define cmndPin 8 // Command送信
#define attPin 9 // セレクト信号
#define clockPin 10 // 制御クロック信号
#define DELAY_TIME 10 // 遅延時間(10μs/10ms)
// 方向キー移動量(MEGA DRIVE mini向け)
#define AXIS_MIN 0 // アナログ方向キー最小値
#define AXIS_MAX 255 // アナログ方向キー最大値
#define AXIS_CENTER 127 // アナログ方向キーセンター位置
// Joystick PAD番号定義
#if __IF_SEGA
//SEGA 純正パッド模擬(VID=0x0CA3、PID=0x0024)
#define PAD_X 3 // Xボタン
#define PAD_A 2 // Aボタン
#define PAD_B 1 // Bボタン
#define PAD_Y 0 // Yボタン
#define PAD_C 5 // Cボタン
#define PAD_Z 4 // Zボタン
#define PAD_MODE 8 // MODEボタン
#define PAD_START 9 // STARTボタン
#else
//DragonRise製パッド模擬(VID=0x0079、PID=0x0011)
#define PAD_X 0 // Xボタン
#define PAD_A 1 // Aボタン
#define PAD_B 2 // Bボタン
#define PAD_Y 3 // Yボタン
#define PAD_C 4 // Cボタン
#define PAD_Z 5 // Zボタン
#define PAD_MODE 8 // MODEボタン
#define PAD_START 9 // STARTボタン
#endif
unsigned int cur_psx_data = 0; // PSXコントローラボタン状態受信
//////////////////////////////////////
// PSXパッド→Joystickパッド変換
// mask = チェック対象ボタンマスク値
// 戻り:Joystickボタン値
//////////////////////////////////////
int get_psx2joy( unsigned int mask )
{
switch(mask)
{
case psxStrt:
return PAD_START;
case psxSlct:
return PAD_MODE;
case psxSqu:
return PAD_X;
case psxX:
return PAD_A;
case psxO:
return PAD_B;
case psxTri:
return PAD_Y;
case psxR1:
return PAD_C;
case psxL1:
return PAD_Z;
case psxR2:
return PAD_MODE;
case psxL2:
default:
break;
}
return -1;
}
//////////////////////////////////////
// PSXパッド制御処理
// psx_data = PSXコントローラ状態
// mask = チェック対象ボタンマスク値
//////////////////////////////////////
bool check_psx_button(unsigned int psx_data ,unsigned int mask )
{
// ボタン状態変化あり
if ( (cur_psx_data & mask) != (psx_data & mask) )
{
// Joystickボタン値取得
int pad = get_psx2joy(mask);
// ボタン押下?
if((psx_data & mask))
{
// 方向キーである
if(mask<=psxUp)
{
switch(mask)
{
case psxUp:
// Y軸を最小
Joystick.setYAxis(AXIS_MIN);
#if __Debug
///////////////////////////////////////////////////////////////////////////////
Serial.print("Joystick.setYAxis(AXIS_MIN)\n");
///////////////////////////////////////////////////////////////////////////////
#endif //__Debug
break;
case psxDown:
// Y軸を最大
Joystick.setYAxis(AXIS_MAX);
#if __Debug
///////////////////////////////////////////////////////////////////////////////
Serial.print("Joystick.setYAxis(AXIS_MAX)\n");
///////////////////////////////////////////////////////////////////////////////
#endif //__Debug
break;
case psxLeft:
// X軸を最小
Joystick.setXAxis(AXIS_MIN);
#if __Debug
///////////////////////////////////////////////////////////////////////////////
Serial.print("Joystick.setXAxis(AXIS_MIN)\n");
///////////////////////////////////////////////////////////////////////////////
#endif //__Debug
break;
case psxRight:
// X軸を最大
Joystick.setXAxis(AXIS_MAX);
#if __Debug
///////////////////////////////////////////////////////////////////////////////
Serial.print("Joystick.setXAxis(AXIS_MAX)\n");
///////////////////////////////////////////////////////////////////////////////
#endif //__Debug
break;
default:
break;
}
}
else
{
#if __Debug
///////////////////////////////////////////////////////////////////////////////
Serial.print(pad,DEC);
Serial.print(" Press\n");
///////////////////////////////////////////////////////////////////////////////
#endif //__Debug
// 無効ボタンなら処理終了
if( pad== -1 )
return false;
// ボタン押下セット
Joystick.pressButton(pad);
}
}
// 離した
else
{
// 方向キーである
if(mask<=psxUp)
{
switch(mask)
{
case psxUp:
case psxDown:
// Y軸をセンターに戻す
Joystick.setYAxis(AXIS_CENTER);
#if __Debug
///////////////////////////////////////////////////////////////////////////////
Serial.print("Joystick.setYAxis(AXIS_CENTER)\n");
///////////////////////////////////////////////////////////////////////////////
#endif //__Debug
break;
case psxLeft:
case psxRight:
// X軸をセンターに戻す
Joystick.setXAxis(AXIS_CENTER);
#if __Debug
///////////////////////////////////////////////////////////////////////////////
Serial.print("Joystick.setXAxis(AXIS_CENTER)\n");
///////////////////////////////////////////////////////////////////////////////
#endif //__Debug
break;
default:
break;
}
}
else
{
#if __Debug
///////////////////////////////////////////////////////////////////////////////
Serial.print(pad,DEC);
Serial.print(" Release\n");
///////////////////////////////////////////////////////////////////////////////
#endif //__Debug
// 無効ボタンなら処理終了
if( pad== -1 )
return false;
// ボタン離す
Joystick.releaseButton(pad);
}
}
// ボタン状態を変更する
cur_psx_data ^= mask;
// 変化あり
return true;
}
// 変化なし
return false;
}
//////////////////////////////////////
// 初期化
//////////////////////////////////////
void setup() {
// put your setup code here, to run once:
// Joystick Library初期化
Joystick.begin(false);
// PAD方向キー初期化
Joystick.setXAxisRange(AXIS_MIN, AXIS_MAX);
Joystick.setYAxisRange(AXIS_MIN, AXIS_MAX);
Joystick.setXAxis(AXIS_CENTER);
Joystick.setYAxis(AXIS_CENTER);
// PSX制御I/O初期化
Psx.setupPins(dataPin, cmndPin, attPin, clockPin, DELAY_TIME);
// 各I/Oピン番号を指定する(data,cmd,att,clock)
// Delay:各ステート応答遅延時間。μs単位で指定
// (5より小さいと動作しない)
#if __Debug
Serial.begin(38400);
#endif //__Debug
}
//////////////////////////////////////
// メインループ
//////////////////////////////////////
void loop() {
// put your main code here, to run repeatedly:
bool change=false; //JoyStick状態変化なし(通信制御しない)
////////////////////////////////////////////
//プレステコントローラ状態読み出し
////////////////////////////////////////////
unsigned int psx_data = Psx.read();
// 各ボタン制御
change = false;
change |= check_psx_button(psx_data,psxLeft);
change |= check_psx_button(psx_data,psxDown);
change |= check_psx_button(psx_data,psxRight);
change |= check_psx_button(psx_data,psxUp);
change |= check_psx_button(psx_data,psxStrt);
change |= check_psx_button(psx_data,psxSlct);
change |= check_psx_button(psx_data,psxSqu);
change |= check_psx_button(psx_data,psxX);
change |= check_psx_button(psx_data,psxO);
change |= check_psx_button(psx_data,psxTri);
change |= check_psx_button(psx_data,psxR1);
change |= check_psx_button(psx_data,psxL1);
change |= check_psx_button(psx_data,psxR2);
change |= check_psx_button(psx_data,psxL2);
// Joystick情報送信
if(change)
{
Joystick.sendState();
}
//1シーケンス終了
delay(DELAY_TIME);
}