PPI.java
     1: //========================================================================================
     2: //  PPI.java
     3: //    en:8255 PPI -- It emulates joystick ports.
     4: //    ja:8255 PPI -- ジョイスティックポートをエミュレートします。
     5: //  Copyright (C) 2003-2024 Makoto Kamada
     6: //
     7: //  This file is part of the XEiJ (X68000 Emulator in Java).
     8: //  You can use, modify and redistribute the XEiJ if the conditions are met.
     9: //  Read the XEiJ License for more details.
    10: //  https://stdkmd.net/xeij/
    11: //========================================================================================
    12: 
    13: package xeij;
    14: 
    15: import java.awt.*;
    16: import java.awt.event.*;
    17: import java.io.*;
    18: import java.util.*;
    19: import javax.swing.*;
    20: import javax.swing.event.*;
    21: 
    22: import com.fazecast.jSerialComm.*;
    23: 
    24: public class PPI {
    25: 
    26:   //ポート
    27:   //  0x00e9a000-0x00e9bfffは下位3ビットだけデコードされる
    28:   //  偶数アドレスをバイトサイズでリード/ライトするとバスエラーになる
    29:   //  偶数アドレスをワードサイズでリードすると上位バイトは0xffになる
    30:   //
    31:   //  0x00e9a001  PPIポートA  ジョイスティック1
    32:   //         7        6        5        4        3        2        1        0
    33:   //    +--------+--------+--------+--------+--------+--------+--------+--------+
    34:   //    |   PA7  |   PA6  |   PA5  |   PA4  |   PA3  |   PA2  |   PA1  |   PA0  |
    35:   //    |    1   |   JS7  |   JS6  |    1   |   JS4  |   JS3  |   JS2  |   JS1  |
    36:   //    |        |    B   |    A   |        |   →   |   ←   |   ↓   |   ↑   |
    37:   //    +--------+--------+--------+--------+--------+--------+--------+--------+
    38:   //    bit7    PA7  1
    39:   //    bit6    PA6  JS7入力。0=Bが押されている
    40:   //    bit5    PA5  JS6入力。0=Aが押されている
    41:   //    bit4    PA4  1
    42:   //    bit3    PA3  JS4入力。0=→が押されている
    43:   //    bit2    PA2  JS3入力。0=←が押されている
    44:   //    bit1    PA1  JS2入力。0=↓が押されている
    45:   //    bit0    PA0  JS1入力。0=↑が押されている
    46:   //
    47:   //  0x00e9a003  PPIポートB  ジョイスティック2
    48:   //         7        6        5        4        3        2        1        0
    49:   //    +--------+--------+--------+--------+--------+--------+--------+--------+
    50:   //    |   PB7  |   PB6  |   PB5  |   PB4  |   PB3  |   PB2  |   PB1  |   PB0  |
    51:   //    |    1   |   JT7  |   JT6  |    1   |   JT4  |   JT3  |   JT2  |   JT1  |
    52:   //    |        |    B   |    A   |        |   →   |   ←   |   ↓   |   ↑   |
    53:   //    +--------+--------+--------+--------+--------+--------+--------+--------+
    54:   //    bit7    PB7  1
    55:   //    bit6    PB6  JT7入力。0=Bが押されている
    56:   //    bit5    PB5  JT6入力。0=Aが押されている
    57:   //    bit4    PB4  1
    58:   //    bit3    PB3  JT4入力。0=→が押されている
    59:   //    bit2    PB2  JT3入力。0=←が押されている
    60:   //    bit1    PB1  JT2入力。0=↓が押されている
    61:   //    bit0    PB0  JT1入力。0=↑が押されている
    62:   //
    63:   //  0x00e9a005  PPIポートC  ADPCMコントロール。初期値は0x0b
    64:   //         7        6        5        4        3        2        1        0
    65:   //    +--------+--------+--------+--------+--------+--------+--------+--------+
    66:   //    |   PC7  |   PC6  |   PC5  |   PC4  |   PC3  |   PC2  |   PC1  |   PC0  |
    67:   //    |   JS7  |   JS6  |   JT8  |   JS8  |      RATIO      |  LEFT  |  RIGHT |
    68:   //    +--------+--------+--------+--------+--------+--------+--------+--------+
    69:   //    bit7    PC7    JS7出力(負論理)
    70:   //    bit6    PC6    JS6出力(負論理)
    71:   //    bit5    PC5    JT8出力
    72:   //    bit4    PC4    JS8出力
    73:   //    bit3-2  PC3-2  ADPCM分周比。00=1/1024,01=1/768,10=1/512,11=inhibited
    74:   //    bit1    PC1    ADPCM出力LEFT。0=出力する,1=出力しない
    75:   //    bit0    PC0    ADPCM出力RIGHT。0=出力する,1=出力しない
    76:   //
    77:   //  0x00e9a007  PPIコントロール
    78:   //    bit7=0  ポートCで出力に設定されているビットの操作
    79:   //      bit3-1  ビット番号
    80:   //      bit0    設定値
    81:   //    bit7=1  モードの設定。0x92に固定
    82:   //      bit6-5  グループA(ポートAとポートCの上位)のモード(0=モード0,1=モード1,2/3=モード2)。モード0に固定
    83:   //      bit4    ポートAの方向(0=出力,1=入力)。入力に固定
    84:   //      bit3    ポートCの上位の方向(0=出力,1=入力)。出力に固定
    85:   //      bit2    グループB(ポートBとポートCの下位)のモード(0=モード0,1=モード1)。モード0に固定
    86:   //      bit1    ポートBの方向(0=出力,1=入力)。入力に固定
    87:   //      bit0    ポートCの下位の方向(0=出力,1=入力)。出力に固定
    88:   //
    89:   //  ボタンのマスク
    90:   //    上と下または左と右のキーが同時に押された場合は両方キャンセルする
    91:   //    SELECTボタンは上下同時押し、RUNボタンは左右同時押しに割り当てられる
    92:   //
    93:   //  bit4とbit7は入力できない
    94:   //    8255の足がプルアップされているので実機ではどうすることもできない(外付けの回路でどうにかなるものではない)
    95:   //    エミュレータで入力できるようにするのは簡単だか対応しているソフトは存在しないだろう
    96:   //
    97:   //  参考
    98:   //    電脳倶楽部67号  B/MDPAD/M6PAD_AN.DOC
    99:   //    電脳倶楽部77号  B/6B/T_EXPAD.DOC
   100:   //
   101:   public static final int PPI_PORT_A  = 0x00e9a001;   //PPIポートA
   102:   public static final int PPI_PORT_B  = 0x00e9a003;   //PPIポートB
   103:   public static final int PPI_PORT_C  = 0x00e9a005;   //PPIポートC
   104:   public static final int PPI_CONTROL = 0x00e9a007;   //PPIコントロール
   105: 
   106:   //ジョイスティック
   107:   public static Joystick[] ppiJoysticks;
   108:   public static Joystick ppiJoystick1;
   109:   public static Joystick ppiJoystick2;
   110: 
   111:   //モード
   112:   public static boolean ppiJoyKey;  //true=キーボードの一部をジョイスティックとみなす
   113:   public static boolean ppiJoyAuto;  //true=ポートが繰り返し読み出されている間だけ有効
   114:   public static boolean ppiJoyBlock;  //true=ジョイスティック操作として処理されたキー入力データを取り除く
   115: 
   116:   //じょいぽーとU君
   117:   public static final boolean PPI_UKUN_ON = true;  //じょいぽーとU君。false=使わない,true=使う
   118:   public static final boolean PPI_UKUN_DEBUG = false;  //デバッグメッセージ。false=出力しない,true=出力する
   119:   //  接続
   120:   public static final int PPI_UKUN_VID = 0x04d8;  //ベンダーID
   121:   public static final int PPI_UKUN_PID = 0xe6b3;  //プロダクトID
   122:   public static boolean ppiUkunRequestedConnection;  //要求された接続。false=接続しない,true=接続する
   123:   public static boolean ppiUkunCurrentConnection;  //現在の接続。false=接続していない,true=接続している
   124:   //  シリアルポート
   125:   public static OldSerialPort ppiUkunOldSerialPort;  //(!jSerialComm)シリアルポート
   126:   public static String ppiUkunPortName;  //ポート名。"COM4"など
   127:   public static OldSerialPort.SerialInputStream ppiUkunOldInputStream;  //(!jSerialComm)入力ストリーム
   128:   public static OldSerialPort.SerialOutputStream ppiUkunOldOutputStream;  //(!jSerialComm)出力ストリーム
   129:   //  モード
   130:   public static final int PPI_UKUN_NOTIFY_A   = 0b0000_0000_0011_0001;  //Notify(A)モード
   131:   public static final int PPI_UKUN_NOTIFY_B   = 0b0000_0001_0011_0001;  //Notify(B)モード
   132:   public static final int PPI_UKUN_COMMAND    = 0b0000_0000_0011_0010;  //Commandモード
   133:   public static final int PPI_UKUN_TRANSITION = 0b0000_0000_0000_0000;  //モード遷移中。I/Oポートのリードは前回の値が返り、ライトは無視される
   134:   public static volatile int ppiUkunRequestedMode;  //要求されたモード。PPI_UKUN_NOTIFY_AまたはPPI_UKUN_COMMANDまたはPPI_UKUN_NOTIFY_B
   135:   public static volatile int ppiUkunCurrentMode;  //現在のモード。PPI_UKUN_NOTIFY_AまたはPPI_UKUN_COMMANDまたはPPI_UKUN_NOTIFY_BまたはPPI_UKUN_TRANSITION
   136:   //  データ
   137:   public static volatile int ppiUkunPortA;  //ポートAのデータ。0b1..1_....
   138:   public static volatile int ppiUkunPortB;  //ポートBのデータ。0b1..1_....
   139:   public static volatile int ppiUkunPortC;  //ポートCのデータ。0b...._0000
   140:   //  受信スレッド
   141:   public static volatile boolean ppiUkunSending;  //false=送信中ではない,true=送信中
   142:   public static volatile Thread ppiUkunThread;  //(!jSerialComm)受信スレッド
   143:   //  ナノタイマー
   144:   public static final boolean PPI_UKUN_NANO = false;  //I/Oポートのアクセス時間を計測する
   145:   public static boolean ppiUkunNanoMeasuring;  //true=計測中
   146:   public static long[] ppiUkunNanoBestArray;  //最短アクセス時間(ns)
   147:   public static long[] ppiUkunNanoWorstArray;  //最長アクセス時間(ns)
   148:   public static long[] ppiUkunNanoTotalArray;  //合計アクセス時間(ns)
   149:   public static long[] ppiUkunNanoCountArray;  //アクセス回数
   150:   //  ウェイト
   151:   public static final long PPI_UKUN_WAIT = XEiJ.TMR_FREQ / (1000000 / 100);  //I/Oポートのアクセスに追加するウェイト(XEiJ.TMR_FREQ単位)。100us
   152:   //  出力間隔調整
   153:   public static final boolean PPI_UKUN_INTERVAL = true;
   154:   public static final long PPI_UKUN_INTERVAL_LIMIT = XEiJ.TMR_FREQ / (1000000L / 500L);  //調整する間隔のずれの上限。500us
   155:   public static boolean ppiUkunIntervalOn;  //true=出力間隔調整を行う
   156:   public static long ppiUkunLastVirtualTime;  //前回のXEiJ.mpuClockTime
   157:   public static long ppiUkunLastRealTime;  //前回のSystem.nanoTime()
   158:   //  メニュー
   159:   public static JCheckBox ppiUkunConnectCheckbox;  //接続チェックボックス
   160:   public static JRadioButton ppiUkunNotifyAModeRadioButton;  //Notify(A)モードラジオボタン
   161:   public static JRadioButton ppiUkunNotifyBModeRadioButton;  //Notify(B)モードラジオボタン
   162:   public static JRadioButton ppiUkunCommandModeRadioButton;  //Commandモードラジオボタン
   163:   //  jSerialComm
   164:   public static final boolean PPI_UKUN_JSERIALCOMM = true;  //false=xeijwin.dllのみ,true=jSerialCommを併用
   165:   public static final String PPI_UKUN_DESCRIPTION = "8255 emulator";  //プロダクト概要
   166:   public static boolean ppiUkunJSerialCommOn;  //じょいぽーとU君でjSerialCommを使う。Windows以外は常にtrue
   167:   public static SerialPort ppiUkunSerialPort;  //シリアルポート
   168:   public static UkunDataListener ppiUkunDataListener;  //シリアルポートデータリスナー
   169:   public static JCheckBox ppiUkunJSerialCommCheckbox;  //jSerialCommチェックボックス。接続していないときだけ有効
   170: 
   171: 
   172:   //ポートの値
   173:   public static int ppiPortCData;
   174: 
   175:   //自動切り替え
   176:   //  PPIのポートが参照されてから一定時間だけJOYKEYを有効にする
   177:   public static final long PPI_CONTINUOUS_ACCESS_SPAN = XEiJ.TMR_FREQ / 10;  //自動切り替えの有効期間(TMR_FREQ単位)。1/10秒
   178:   public static long ppiLastAccessTime;  //最後にPPIのポートがアクセスされた時刻
   179: 
   180:   //XInput
   181:   public static final boolean PPI_XINPUT_ON = true;  //false=使わない,true=使う
   182:   public static boolean ppiXInputOn;  //false=使わない,true=使う
   183:   public static XInput ppiXInput;  //XInput。nullでなければ動作中
   184:   public static int ppiXInputLastButtons;
   185: 
   186:   //ウインドウ
   187:   public static JFrame ppiFrame;
   188: 
   189:   public static JScrollPane ppiConfigurationScrollPane;
   190: 
   191:   //ppiInit ()
   192:   //  PPIを初期化する
   193:   public static void ppiInit () {
   194:     ppiJoyKey = Settings.sgsGetOnOff ("joykey");
   195:     ppiJoyAuto = Settings.sgsGetOnOff ("joyauto");
   196:     ppiJoyBlock = Settings.sgsGetOnOff ("joyblock");
   197: 
   198:     ppiJoysticks = new Joystick[] {
   199:       new DummyPad (),
   200:       new Normal2ButtonPad (1),
   201:       new Normal2ButtonPad (2),
   202:       new MegaDrive3ButtonPad (1),
   203:       new MegaDrive3ButtonPad (2),
   204:       new MegaDrive6ButtonPad (1),
   205:       new MegaDrive6ButtonPad (2),
   206:       new CyberStickAnalog (1),
   207:       new CyberStickAnalog (2),
   208:       new CyberStickDigital (1),
   209:       new CyberStickDigital (2),
   210:       new Shiromadokun (1),
   211:       new Shiromadokun (2),
   212:     };
   213: 
   214:     String id1 = Settings.sgsGetString ("joystick1");  //ジョイスティックポート1に接続するデバイス
   215:     ppiJoystick1 = ppiJoysticks[0];  //DummyPad
   216:     for (Joystick joystick : ppiJoysticks) {
   217:       if (joystick.getId ().equalsIgnoreCase (id1)) {
   218:         ppiJoystick1 = joystick;
   219:       }
   220:     }
   221: 
   222:     String id2 = Settings.sgsGetString ("joystick2");  //ジョイスティックポート2に接続するデバイス
   223:     ppiJoystick2 = ppiJoysticks[0];  //DummyPad
   224:     for (Joystick joystick : ppiJoysticks) {
   225:       if (joystick.getId ().equalsIgnoreCase (id2)) {
   226:         ppiJoystick2 = joystick;
   227:       }
   228:     }
   229: 
   230:     if (PPI_UKUN_ON) {
   231:       ppiUkunRequestedConnection = (PPI_UKUN_JSERIALCOMM || XEiJ.prgWindllLoaded) && Settings.sgsGetOnOff ("joyportukun");
   232:       ppiUkunCurrentConnection = false;
   233:       ppiUkunPortName = null;
   234:       ppiUkunOldSerialPort = null;
   235:       ppiUkunOldInputStream = null;
   236:       ppiUkunOldOutputStream = null;
   237:       String paramUkunmode = Settings.sgsGetString ("ukunmode");
   238:       ppiUkunRequestedMode = (paramUkunmode.equalsIgnoreCase ("notifya") ? PPI_UKUN_NOTIFY_A :
   239:                               paramUkunmode.equalsIgnoreCase ("notifyb") ? PPI_UKUN_NOTIFY_B :
   240:                               paramUkunmode.equalsIgnoreCase ("command") ? PPI_UKUN_COMMAND :
   241:                               PPI_UKUN_NOTIFY_A);
   242:       ppiUkunCurrentMode = ppiUkunRequestedMode;
   243:       if (PPI_UKUN_DEBUG) {
   244:         System.out.printf ("UkunCurrentMode 0x%04x\n", ppiUkunCurrentMode);
   245:       }
   246:       ppiUkunPortA = 0b1111_1111;  //0b1..1_....
   247:       ppiUkunPortB = 0b1111_1111;  //0b1..1_....
   248:       ppiUkunPortC = 0b0000_0000;  //0b...._0000
   249:       ppiUkunSending = false;
   250:       ppiUkunThread = null;
   251:       if (PPI_UKUN_NANO) {
   252:         ppiUkunNanoMeasuring = false;
   253:         ppiUkunNanoBestArray = new long[8];
   254:         ppiUkunNanoWorstArray = new long[8];
   255:         ppiUkunNanoTotalArray = new long[8];
   256:         ppiUkunNanoCountArray = new long[8];
   257:       }
   258:       if (PPI_UKUN_INTERVAL) {
   259:         ppiUkunIntervalOn = Settings.sgsGetOnOff ("ukuninterval");
   260:         ppiUkunLastVirtualTime = XEiJ.mpuClockTime;
   261:         ppiUkunLastRealTime = System.nanoTime ();
   262:       }
   263:       if (PPI_UKUN_JSERIALCOMM) {
   264:         ppiUkunJSerialCommOn = !XEiJ.prgIsWindows || Settings.sgsGetOnOff ("ukunjsc");  //Windows以外は常にtrue
   265:         ppiUkunSerialPort = null;
   266:         ppiUkunDataListener = null;
   267:       }  //if PPI_UKUN_JSERIALCOMM
   268:     }  //if PPI_UKUN_ON
   269: 
   270:     if (PPI_XINPUT_ON) {
   271:       ppiXInputOn = XEiJ.prgWindllLoaded && Settings.sgsGetOnOff ("xinput");
   272:       if (ppiXInputOn) {
   273:         ppiXInputStart ();
   274:       }
   275:       ppiXInputLastButtons = 0;
   276:     }
   277: 
   278:     ppiReset ();
   279:   }  //ppiInit
   280: 
   281:   //ppiTini ()
   282:   //  後始末
   283:   public static void ppiTini () {
   284:     Settings.sgsPutOnOff ("joykey", ppiJoyKey);
   285:     Settings.sgsPutOnOff ("joyauto", ppiJoyAuto);
   286:     Settings.sgsPutOnOff ("joyblock", ppiJoyBlock);
   287:     for (Joystick joystick : ppiJoysticks) {
   288:       joystick.tini ();
   289:     }
   290:     Settings.sgsPutString ("joystick1", ppiJoystick1.getId ());
   291:     Settings.sgsPutString ("joystick2", ppiJoystick2.getId ());
   292:     if (PPI_UKUN_ON) {
   293:       Settings.sgsPutOnOff ("joyportukun", ppiUkunRequestedConnection);
   294:       Settings.sgsPutString ("ukunmode",
   295:                              ppiUkunRequestedMode == PPI_UKUN_NOTIFY_A ? "notifya" :
   296:                              ppiUkunRequestedMode == PPI_UKUN_NOTIFY_B ? "notifyb" :
   297:                              ppiUkunRequestedMode == PPI_UKUN_COMMAND ? "command" :
   298:                              "notifya");
   299:       if (PPI_UKUN_INTERVAL) {
   300:         Settings.sgsPutOnOff ("ukuninterval", ppiUkunIntervalOn);
   301:       }
   302:       if (PPI_UKUN_JSERIALCOMM) {
   303:         Settings.sgsPutOnOff ("ukunjsc", !XEiJ.prgIsWindows ? false : ppiUkunJSerialCommOn);  //Windows以外はデフォルトのfalseを保存する。次回再び強制的にtrueになる
   304:       }
   305:       ppiUkunDisconnect ();
   306:     }
   307:     //XInput
   308:     if (PPI_XINPUT_ON) {
   309:       Settings.sgsPutOnOff ("xinput", ppiXInputOn);
   310:       if (ppiXInputOn) {
   311:         ppiXInputOn = false;
   312:         ppiXInputEnd ();
   313:       }
   314:     }
   315:   }  //ppiTini
   316: 
   317:   //ppiReset ()
   318:   //  リセット
   319:   public static void ppiReset () {
   320:     ppiPortCData = 0;
   321:     ppiLastAccessTime = 0L;
   322:   }
   323: 
   324: 
   325:   public static void ppiXInputStart () {
   326:     if (ppiXInput == null) {
   327:       System.out.println (Multilingual.mlnJapanese ?
   328:                           "XInput のポーリングを開始します" :
   329:                           "Starts polling XInput");
   330:       ppiXInput = new XInput ();
   331:     }
   332:   }
   333: 
   334:   public static void ppiXInputEnd () {
   335:     if (ppiXInput != null) {
   336:       System.out.println (Multilingual.mlnJapanese ?
   337:                           "XInput のポーリングを終了します" :
   338:                           "Ends polling XInput");
   339:       ppiXInput.end ();
   340:       ppiXInput = null;
   341:     }
   342:   }
   343: 
   344: 
   345:   //ppiUkunConnect ()
   346:   //  接続する
   347:   //  MPU動作中はI/Oポートのアクセスと衝突させないためコアのスレッドで呼び出すこと
   348:   //  接続はここで完結するので遷移中の状態は考慮しない
   349:   public static void ppiUkunConnect () {
   350:     if (PPI_UKUN_ON && (PPI_UKUN_JSERIALCOMM || XEiJ.prgWindllLoaded)) {
   351:       if (PPI_UKUN_DEBUG) {
   352:         System.out.println ("ppiUkunConnect start");
   353:       }
   354:       ppiUkunRequestedConnection = true;
   355:       if (ppiUkunCurrentConnection) {  //接続している
   356:         ppiUkunAdjustMenu ();
   357:         return;
   358:       }
   359:       if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
   360:         //ジョイポートU君を探して開く
   361:         if (ppiUkunSerialPort == null) {
   362:           for (SerialPort serialPort : SerialPort.getCommPorts ()) {
   363:             if (serialPort.getPortDescription ().startsWith (PPI_UKUN_DESCRIPTION) &&  //見つかった
   364:                 serialPort.openPort ()) {  //開けた
   365:               ppiUkunSerialPort = serialPort;
   366:               break;
   367:             }
   368:           }
   369:         }
   370:         if (ppiUkunSerialPort == null) {  //開けなかった
   371:           System.out.printf (Multilingual.mlnJapanese ?
   372:                              "じょいぽーと U 君 (%s) のシリアルポートが見つかりません\n" :
   373:                              "Serial port for JoyPortUkun (%s) not found\n",
   374:                              PPI_UKUN_DESCRIPTION);
   375:           ppiUkunRequestedConnection = false;
   376:           //ppiUkunCurrentConnection = false;
   377:           ppiUkunAdjustMenu ();
   378:           return;
   379:         }
   380:         ppiUkunPortName = ppiUkunSerialPort.getSystemPortName ();
   381:         ppiUkunSerialPort.setComPortParameters (480000000, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);
   382:         ppiUkunSerialPort.setComPortTimeouts (SerialPort.TIMEOUT_WRITE_BLOCKING | SerialPort.TIMEOUT_READ_BLOCKING, 0, 0);
   383:       } else {  //!jSerialComm
   384:         //ポートを開く
   385:         if (ppiUkunOldSerialPort == null) {
   386:           try {
   387:             ppiUkunOldSerialPort = new OldSerialPort (PPI_UKUN_VID, PPI_UKUN_PID);
   388:           } catch (IOException ioe) {
   389:             System.out.printf (Multilingual.mlnJapanese ?
   390:                                "じょいぽーと U 君 (VID=%04X, PID=%04X) の COM ポートが見つかりません\n" :
   391:                                "COM port for JoyPortUkun (VID=%04X, PID=%04X) not found\n",
   392:                                PPI_UKUN_VID, PPI_UKUN_PID);
   393:             ppiUkunRequestedConnection = false;
   394:             //ppiUkunCurrentConnection = false;
   395:             ppiUkunAdjustMenu ();
   396:             return;
   397:           }
   398:         }
   399:         try {
   400:           ppiUkunPortName = ppiUkunOldSerialPort.getPortName ();
   401:           ppiUkunOldSerialPort.speed ("480000000 b8 pn s1 none");
   402:           ppiUkunOldInputStream = ppiUkunOldSerialPort.getInputStream ();
   403:           ppiUkunOldOutputStream = ppiUkunOldSerialPort.getOutputStream ();
   404:         } catch (IOException ioe) {
   405:           ioe.printStackTrace ();
   406:         }
   407:       }  //if jSerialComm/!
   408:       //接続完了
   409:       ppiUkunCurrentMode = PPI_UKUN_TRANSITION;
   410:       if (PPI_UKUN_DEBUG) {
   411:         System.out.printf ("UkunCurrentMode 0x%04x\n", ppiUkunCurrentMode);
   412:       }
   413:       ppiUkunCurrentConnection = true;  //接続している
   414:       ppiUkunAdjustMenu ();
   415:       if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
   416:         System.out.printf (Multilingual.mlnJapanese ?
   417:                            "じょいぽーと U 君 (%s, %s) に接続しました\n" :
   418:                            "Connected to JoyPortUkun (%s, %s)\n",
   419:                            ppiUkunPortName, ppiUkunSerialPort.getPortDescription ());
   420:         //シリアルポートデータリスナーを登録する
   421:         if (ppiUkunDataListener == null) {
   422:           ppiUkunSending = false;
   423:           ppiUkunDataListener = new UkunDataListener ();
   424:           ppiUkunSerialPort.addDataListener (ppiUkunDataListener);
   425:         }
   426:         //要求されたモードを送信する
   427:         ppiUkunSerialPort.writeBytes (new byte[] { (byte) ppiUkunRequestedMode }, 1);
   428:       } else {  //!jSerialComm
   429:         System.out.printf (Multilingual.mlnJapanese ?
   430:                            "じょいぽーと U 君 (%s, VID=%04X, PID=%04X) に接続しました\n" :
   431:                            "Connected to JoyPortUkun (%s, VID=%04X, PID=%04X)\n",
   432:                            ppiUkunPortName, PPI_UKUN_VID, PPI_UKUN_PID);
   433:         //受信スレッドを開始する
   434:         if (ppiUkunThread == null) {
   435:           ppiUkunSending = false;
   436:           ppiUkunThread = new UkunThread ();
   437:           ppiUkunThread.start ();
   438:         }
   439:         //要求されたモードを送信する
   440:         try {
   441:           ppiUkunOldOutputStream.write (ppiUkunRequestedMode);
   442:         } catch (IOException ioe) {
   443:           ioe.printStackTrace ();
   444:         }
   445:       }  //if jSerialComm/!
   446:       if (PPI_UKUN_DEBUG) {
   447:         System.out.println ("ppiUkunConnect end");
   448:       }
   449:     }
   450:   }  //ppiUkunConnect
   451: 
   452:   //ppiUkunDisconnect ()
   453:   //  切断する
   454:   //  MPU動作中はI/Oポートのアクセスと衝突させないためコアのスレッドで呼び出すこと
   455:   //  切断はここで完結するので遷移中の状態は考慮しない
   456:   public static void ppiUkunDisconnect () {
   457:     if (PPI_UKUN_ON) {
   458:       if (PPI_UKUN_DEBUG) {
   459:         System.out.println ("ppiUkunDisconnect start");
   460:       }
   461:       ppiUkunRequestedConnection = false;
   462:       if (!ppiUkunCurrentConnection) {  //接続していない
   463:         ppiUkunAdjustMenu ();
   464:         return;
   465:       }
   466:       //切断開始
   467:       ppiUkunCurrentMode = PPI_UKUN_TRANSITION;
   468:       if (PPI_UKUN_DEBUG) {
   469:         System.out.printf ("UkunCurrentMode 0x%04x\n", ppiUkunCurrentMode);
   470:       }
   471:       ppiUkunCurrentConnection = false;  //接続していない
   472:       ppiUkunAdjustMenu ();
   473:       if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
   474:         if (ppiUkunSerialPort != null) {
   475:           //シリアルポートデータリスナーを解除する
   476:           ppiUkunSerialPort.removeDataListener ();
   477:           ppiUkunDataListener = null;
   478:           //ポートを閉じる
   479:           ppiUkunSerialPort.closePort ();
   480:           ppiUkunSerialPort = null;
   481:         }
   482:       } else {  //!jSerialComm
   483:         //ポートを閉じる
   484:         if (ppiUkunOldSerialPort != null) {
   485:           try {
   486:             ppiUkunOldSerialPort.close ();
   487:           } catch (IOException ioe) {
   488:             ioe.printStackTrace ();
   489:           }
   490:           ppiUkunOldSerialPort = null;
   491:           ppiUkunOldInputStream = null;
   492:           ppiUkunOldOutputStream = null;
   493:         }
   494:         //受信スレッドが終了するまで待つ
   495:         while (ppiUkunThread != null) {
   496:         }
   497:       }  //if jSerialComm/!
   498:       ppiUkunSending = false;
   499:       //切断完了
   500:       ppiUkunCurrentMode = ppiUkunRequestedMode;
   501:       if (PPI_UKUN_DEBUG) {
   502:         System.out.printf ("UkunCurrentMode 0x%04x\n", ppiUkunCurrentMode);
   503:       }
   504:       ppiUkunAdjustMenu ();
   505:       System.out.printf (Multilingual.mlnJapanese ?
   506:                          "じょいぽーと U 君 (%s) を切り離しました\n" :
   507:                          "Disconnected JoyPortUkun (%s)\n",
   508:                          ppiUkunPortName);
   509:       ppiUkunPortName = null;
   510:       if (PPI_UKUN_DEBUG) {
   511:         System.out.println ("ppiUkunDisconnect end");
   512:       }
   513:     }
   514:   }  //ppiUkunDisconnect
   515: 
   516:   //ppiUkunNotifyAMode ()
   517:   //  Notify(A)モード
   518:   public static void ppiUkunNotifyAMode () {
   519:     if (PPI_UKUN_ON) {
   520:       if (PPI_UKUN_DEBUG) {
   521:         System.out.println ("ppiUkunNotifyAMode start");
   522:       }
   523:       if (!ppiUkunRequestedConnection &&
   524:           !ppiUkunCurrentConnection) {  //接続していない
   525:         //Notify(A)モード
   526:         ppiUkunRequestedMode = PPI_UKUN_NOTIFY_A;
   527:         ppiUkunCurrentMode = PPI_UKUN_NOTIFY_A;
   528:         if (PPI_UKUN_DEBUG) {
   529:           System.out.printf ("UkunCurrentMode 0x%04x\n", ppiUkunCurrentMode);
   530:         }
   531:         ppiUkunAdjustMenu ();
   532:       } else if (ppiUkunRequestedConnection &&
   533:                  ppiUkunCurrentConnection &&  //接続している
   534:                  ((ppiUkunRequestedMode == PPI_UKUN_COMMAND &&
   535:                    ppiUkunCurrentMode == PPI_UKUN_COMMAND) ||  //Commandモード
   536:                   (ppiUkunRequestedMode == PPI_UKUN_NOTIFY_B &&
   537:                    ppiUkunCurrentMode == PPI_UKUN_NOTIFY_B))) {  //Notify(B)モード
   538:         //遷移中
   539:         ppiUkunRequestedMode = PPI_UKUN_NOTIFY_A;
   540:         ppiUkunCurrentMode = PPI_UKUN_TRANSITION;
   541:         if (PPI_UKUN_DEBUG) {
   542:           System.out.printf ("UkunCurrentMode 0x%04x\n", ppiUkunCurrentMode);
   543:         }
   544:         ppiUkunAdjustMenu ();
   545:         if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
   546:           //シリアルポートデータリスナーを登録する
   547:           if (ppiUkunDataListener == null) {
   548:             ppiUkunSending = false;
   549:             ppiUkunDataListener = new UkunDataListener ();
   550:             ppiUkunSerialPort.addDataListener (ppiUkunDataListener);
   551:           }
   552:           //Notify(A)モードを送信する
   553:           ppiUkunSerialPort.writeBytes (new byte[] { (byte) PPI_UKUN_NOTIFY_A }, 1);
   554:         } else {  //!jSerialComm
   555:           //受信スレッドを開始する
   556:           if (ppiUkunThread == null) {
   557:             ppiUkunSending = false;
   558:             ppiUkunThread = new UkunThread ();
   559:             ppiUkunThread.start ();
   560:           }
   561:           //Notify(A)モードを送信する
   562:           try {
   563:             ppiUkunOldOutputStream.write (PPI_UKUN_NOTIFY_A & 0xff);
   564:           } catch (IOException ioe) {
   565:             ioe.printStackTrace ();
   566:           }
   567:         }  //if jSerialComm/!
   568:       }
   569:       if (PPI_UKUN_DEBUG) {
   570:         System.out.println ("ppiUkunNotifyAMode end");
   571:       }
   572:     }
   573:   }  //ppiUkunNotifyAMode
   574: 
   575:   //ppiUkunNotifyBMode ()
   576:   //  Notify(B)モード
   577:   public static void ppiUkunNotifyBMode () {
   578:     if (PPI_UKUN_ON) {
   579:       if (PPI_UKUN_DEBUG) {
   580:         System.out.println ("ppiUkunNotifyBMode start");
   581:       }
   582:       if (!ppiUkunRequestedConnection &&
   583:           !ppiUkunCurrentConnection) {  //接続していない
   584:         //Notify(B)モード
   585:         ppiUkunRequestedMode = PPI_UKUN_NOTIFY_B;
   586:         ppiUkunCurrentMode = PPI_UKUN_NOTIFY_B;
   587:         if (PPI_UKUN_DEBUG) {
   588:           System.out.printf ("UkunCurrentMode 0x%04x\n", ppiUkunCurrentMode);
   589:         }
   590:         ppiUkunAdjustMenu ();
   591:       } else if (ppiUkunRequestedConnection &&
   592:                  ppiUkunCurrentConnection &&  //接続している
   593:                  ((ppiUkunRequestedMode == PPI_UKUN_NOTIFY_A &&
   594:                    ppiUkunCurrentMode == PPI_UKUN_NOTIFY_A) ||  //Notify(A)モード
   595:                   (ppiUkunRequestedMode == PPI_UKUN_COMMAND &&
   596:                    ppiUkunCurrentMode == PPI_UKUN_COMMAND))) {  //Commandモード
   597:         //遷移中
   598:         ppiUkunRequestedMode = PPI_UKUN_NOTIFY_B;
   599:         ppiUkunCurrentMode = PPI_UKUN_TRANSITION;
   600:         if (PPI_UKUN_DEBUG) {
   601:           System.out.printf ("UkunCurrentMode 0x%04x\n", ppiUkunCurrentMode);
   602:         }
   603:         ppiUkunAdjustMenu ();
   604:         if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
   605:           //シリアルポートデータリスナーを登録する
   606:           if (ppiUkunDataListener == null) {
   607:             ppiUkunSending = false;
   608:             ppiUkunDataListener = new UkunDataListener ();
   609:             ppiUkunSerialPort.addDataListener (ppiUkunDataListener);
   610:           }
   611:           //Notify(B)モードを送信する
   612:           ppiUkunSerialPort.writeBytes (new byte[] { (byte) PPI_UKUN_NOTIFY_B }, 1);
   613:         } else {  //!jSerialComm
   614:           //受信スレッドを開始する
   615:           if (ppiUkunThread == null) {
   616:             ppiUkunSending = false;
   617:             ppiUkunThread = new UkunThread ();
   618:             ppiUkunThread.start ();
   619:           }
   620:           //Notify(B)モードを送信する
   621:           try {
   622:             ppiUkunOldOutputStream.write (PPI_UKUN_NOTIFY_B & 0xff);
   623:           } catch (IOException ioe) {
   624:             ioe.printStackTrace ();
   625:           }
   626:         }  //if jSerialComm/!
   627:       }
   628:       if (PPI_UKUN_DEBUG) {
   629:         System.out.println ("ppiUkunNotifyBMode end");
   630:       }
   631:     }
   632:   }  //ppiUkunNotifyBMode
   633: 
   634:   //ppiUkunCommandMode ()
   635:   //  Commandモード
   636:   public static void ppiUkunCommandMode () {
   637:     if (PPI_UKUN_ON) {
   638:       if (PPI_UKUN_DEBUG) {
   639:         System.out.println ("ppiUkunCommandMode start");
   640:       }
   641:       if (!ppiUkunRequestedConnection &&
   642:           !ppiUkunCurrentConnection) {  //接続していない
   643:         //Commandモード
   644:         ppiUkunRequestedMode = PPI_UKUN_COMMAND;
   645:         ppiUkunCurrentMode = PPI_UKUN_COMMAND;
   646:         if (PPI_UKUN_DEBUG) {
   647:           System.out.printf ("UkunCurrentMode 0x%04x\n", ppiUkunCurrentMode);
   648:         }
   649:         ppiUkunAdjustMenu ();
   650:       } else if (ppiUkunRequestedConnection &&
   651:                  ppiUkunCurrentConnection &&  //接続している
   652:                  ((ppiUkunRequestedMode == PPI_UKUN_NOTIFY_A &&
   653:                    ppiUkunCurrentMode == PPI_UKUN_NOTIFY_A) ||  //Notify(A)モード
   654:                   (ppiUkunRequestedMode == PPI_UKUN_NOTIFY_B &&
   655:                    ppiUkunCurrentMode == PPI_UKUN_NOTIFY_B))) {  //Notify(B)モード
   656:         //遷移中
   657:         ppiUkunRequestedMode = PPI_UKUN_COMMAND;
   658:         ppiUkunCurrentMode = PPI_UKUN_TRANSITION;
   659:         if (PPI_UKUN_DEBUG) {
   660:           System.out.printf ("UkunCurrentMode 0x%04x\n", ppiUkunCurrentMode);
   661:         }
   662:         ppiUkunAdjustMenu ();
   663:         if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
   664:           //シリアルポートデータリスナーを登録する
   665:           if (ppiUkunDataListener == null) {
   666:             ppiUkunSending = false;
   667:             ppiUkunDataListener = new UkunDataListener ();
   668:             ppiUkunSerialPort.addDataListener (ppiUkunDataListener);
   669:           }
   670:           //Commandモードを送信する
   671:           ppiUkunSerialPort.writeBytes (new byte[] { (byte) PPI_UKUN_COMMAND }, 1);
   672:         } else {  //!jSerialComm
   673:           //受信スレッドを開始する
   674:           if (ppiUkunThread == null) {
   675:             ppiUkunSending = false;
   676:             ppiUkunThread = new UkunThread ();
   677:             ppiUkunThread.start ();
   678:           }
   679:           //Commandモードを送信する
   680:           try {
   681:             ppiUkunOldOutputStream.write (PPI_UKUN_COMMAND);
   682:           } catch (IOException ioe) {
   683:             ioe.printStackTrace ();
   684:           }
   685:         }  //if jSerialComm/!
   686:       }
   687:       if (PPI_UKUN_DEBUG) {
   688:         System.out.println ("ppiUkunCommandMode end");
   689:       }
   690:     }
   691:   }  //ppiUkunCommandMode
   692: 
   693:   //ppiUkunMenuConnect ()
   694:   //  メニューからの接続
   695:   public static void ppiUkunMenuConnect () {
   696:     if (PPI_UKUN_ON) {
   697:       XEiJ.tmrTimer.schedule (new TimerTask () {
   698:         @Override public void run () {
   699:           ppiUkunConnect ();
   700:         }
   701:       }, 0L);
   702:     }
   703:   }  //ppiUkunMenuConnect
   704: 
   705:   //ppiUkunMenuDisconnect ()
   706:   //  メニューからの切断
   707:   public static void ppiUkunMenuDisconnect () {
   708:     if (PPI_UKUN_ON) {
   709:       XEiJ.tmrTimer.schedule (new TimerTask () {
   710:         @Override public void run () {
   711:           ppiUkunDisconnect ();
   712:         }
   713:       }, 0L);
   714:     }
   715:   }  //ppiUkunMenuDisconnect
   716: 
   717:   //ppiUkunMenuNotifyAMode ()
   718:   //  メニューからのNotify(A)モード
   719:   public static void ppiUkunMenuNotifyAMode () {
   720:     if (PPI_UKUN_ON) {
   721:       XEiJ.tmrTimer.schedule (new TimerTask () {
   722:         @Override public void run () {
   723:           ppiUkunNotifyAMode ();
   724:         }
   725:       }, 0L);
   726:     }
   727:   }  //ppiUkunMenuNotifyAMode
   728: 
   729:   //ppiUkunMenuNotifyBMode ()
   730:   //  メニューからのNotify(B)モード
   731:   public static void ppiUkunMenuNotifyBMode () {
   732:     if (PPI_UKUN_ON) {
   733:       XEiJ.tmrTimer.schedule (new TimerTask () {
   734:         @Override public void run () {
   735:           ppiUkunNotifyBMode ();
   736:         }
   737:       }, 0L);
   738:     }
   739:   }  //ppiUkunMenuNotifyBMode
   740: 
   741:   //ppiUkunMenuCommandMode ()
   742:   //  メニューからのCommandモード
   743:   public static void ppiUkunMenuCommandMode () {
   744:     if (PPI_UKUN_ON) {
   745:       XEiJ.tmrTimer.schedule (new TimerTask () {
   746:         @Override public void run () {
   747:           ppiUkunCommandMode ();
   748:         }
   749:       }, 0L);
   750:     }
   751:   }  //ppiUkunMenuCommandMode
   752: 
   753:   //ppiUkunAdjustMenu ()
   754:   //  メニューを調整する
   755:   public static void ppiUkunAdjustMenu () {
   756:     if (PPI_UKUN_ON) {
   757:       if (ppiUkunConnectCheckbox != null) {
   758:         //接続チェックボックスと要求された接続を合わせる
   759:         if (ppiUkunConnectCheckbox.isSelected () != ppiUkunRequestedConnection) {
   760:           ppiUkunConnectCheckbox.setSelected (ppiUkunRequestedConnection);
   761:         }
   762:         //  遷移中は操作禁止
   763:         if (ppiUkunConnectCheckbox.isEnabled () != (ppiUkunRequestedConnection == ppiUkunCurrentConnection)) {
   764:           ppiUkunConnectCheckbox.setEnabled (ppiUkunRequestedConnection == ppiUkunCurrentConnection);
   765:         }
   766:       }
   767:       if (ppiUkunNotifyAModeRadioButton != null) {
   768:         //Notify(A)モードラジオボタンと要求されたモードを合わせる
   769:         if (ppiUkunNotifyAModeRadioButton.isSelected () != (ppiUkunRequestedMode == PPI_UKUN_NOTIFY_A)) {
   770:           ppiUkunNotifyAModeRadioButton.setSelected (ppiUkunRequestedMode == PPI_UKUN_NOTIFY_A);
   771:         }
   772:         //  接続中かつ遷移中は操作禁止
   773:         if (ppiUkunNotifyAModeRadioButton.isEnabled () != !(ppiUkunCurrentConnection && ppiUkunRequestedMode != ppiUkunCurrentMode)) {
   774:           ppiUkunNotifyAModeRadioButton.setEnabled (!(ppiUkunCurrentConnection && ppiUkunRequestedMode != ppiUkunCurrentMode));
   775:         }
   776:       }
   777:       if (ppiUkunNotifyBModeRadioButton != null) {
   778:         //Notify(B)モードラジオボタンと要求されたモードを合わせる
   779:         if (ppiUkunNotifyBModeRadioButton.isSelected () != (ppiUkunRequestedMode == PPI_UKUN_NOTIFY_B)) {
   780:           ppiUkunNotifyBModeRadioButton.setSelected (ppiUkunRequestedMode == PPI_UKUN_NOTIFY_B);
   781:         }
   782:         //  接続中かつ遷移中は操作禁止
   783:         if (ppiUkunNotifyBModeRadioButton.isEnabled () != !(ppiUkunCurrentConnection && ppiUkunRequestedMode != ppiUkunCurrentMode)) {
   784:           ppiUkunNotifyBModeRadioButton.setEnabled (!(ppiUkunCurrentConnection && ppiUkunRequestedMode != ppiUkunCurrentMode));
   785:         }
   786:       }
   787:       if (ppiUkunCommandModeRadioButton != null) {
   788:         //Commandモードラジオボタンと要求されたモードを合わせる
   789:         if (ppiUkunCommandModeRadioButton.isSelected () != (ppiUkunRequestedMode == PPI_UKUN_COMMAND)) {
   790:           ppiUkunCommandModeRadioButton.setSelected (ppiUkunRequestedMode == PPI_UKUN_COMMAND);
   791:         }
   792:         //  接続中かつ遷移中は操作禁止
   793:         if (ppiUkunCommandModeRadioButton.isEnabled () != !(ppiUkunCurrentConnection && ppiUkunRequestedMode != ppiUkunCurrentMode)) {
   794:           ppiUkunCommandModeRadioButton.setEnabled (!(ppiUkunCurrentConnection && ppiUkunRequestedMode != ppiUkunCurrentMode));
   795:         }
   796:       }
   797:       if (PPI_UKUN_JSERIALCOMM) {
   798:         if (ppiUkunJSerialCommCheckbox != null) {
   799:           //jSerialCommチェックボックスと現在の状態を合わせる
   800:           if (ppiUkunJSerialCommCheckbox.isSelected () != ppiUkunJSerialCommOn) {
   801:             ppiUkunJSerialCommCheckbox.setSelected (ppiUkunJSerialCommOn);
   802:           }
   803:           //  Windows以外と接続中は操作禁止
   804:           if (ppiUkunJSerialCommCheckbox.isEnabled () != (XEiJ.prgIsWindows && !ppiUkunCurrentConnection)) {
   805:             ppiUkunJSerialCommCheckbox.setEnabled (XEiJ.prgIsWindows && !ppiUkunCurrentConnection);
   806:           }
   807:         }
   808:       }
   809:     }
   810:   }  //ppiUkunAdjustMenu
   811: 
   812:   //class UkunDataListener
   813:   //  シリアルポートデータリスナー
   814:   public static class UkunDataListener implements SerialPortDataListener {
   815:     @Override public int getListeningEvents () {
   816:       return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;
   817:     }
   818:     @Override public void serialEvent (SerialPortEvent spe) {
   819:       if (spe.getEventType () != SerialPort.LISTENING_EVENT_DATA_AVAILABLE) {
   820:         return;
   821:       }
   822:       byte[] bytes = new byte[1];
   823:       while (ppiUkunSerialPort.bytesAvailable () != 0 &&
   824:              ppiUkunSerialPort.readBytes (bytes, 1) != 0) {  //1バイトずつ受信する
   825:         int data = bytes[0] & 0xff;
   826:         if (PPI_UKUN_DEBUG) {
   827:           System.out.printf ("UkunDataListener received 0x%02x\n", data);
   828:         }
   829:         //変化通知
   830:         //  0b1..0_....  portA  0b1..1_....
   831:         //  0b1..1_....  portB  0b1..1_....
   832:         //  0b0000_....  portC  0b...._0000
   833:         //完了通知
   834:         //  0b0011_1111  completed
   835:         //モード通知
   836:         //  0b0011_0001  Notify mode
   837:         //  0b0011_0010  Command mode
   838:         if ((data & 0b1001_0000) == 0b1000_0000) {  //0b1..0_.... portA
   839:           ppiUkunPortA = 0b1001_0000 | data;  //0b1..1_....
   840:         } else if ((data & 0b1001_0000) == 0b1001_0000) {  //0b1..1_.... portB
   841:           ppiUkunPortB = data;  //0b1..1_....
   842:         } else if (data <= 0b0000_1111) {  //0b0000_.... portC
   843:           ppiUkunPortC = data << 4;  //0b...._0000
   844:         } else if (data == 0b0011_1111) {  //completed
   845:           ppiUkunSending = false;
   846:         } else if (data == 0b0011_0001) {  //Notify mode
   847:           if (ppiUkunRequestedMode == PPI_UKUN_NOTIFY_B) {
   848:             System.out.printf (Multilingual.mlnJapanese ?
   849:                                "じょいぽーと U 君 (%s) は Notify(B) モードで初期化されました\n" :
   850:                                "JoyPortUkun (%s) has been initialized in Notify(B) mode\n",
   851:                                ppiUkunPortName);
   852:             //ppiUkunRequestedMode = PPI_UKUN_NOTIFY_B;
   853:             ppiUkunCurrentMode = PPI_UKUN_NOTIFY_B;
   854:           } else {
   855:             System.out.printf (Multilingual.mlnJapanese ?
   856:                                "じょいぽーと U 君 (%s) は Notify(A) モードで初期化されました\n" :
   857:                                "JoyPortUkun (%s) has been initialized in Notify(A) mode\n",
   858:                                ppiUkunPortName);
   859:             ppiUkunRequestedMode = PPI_UKUN_NOTIFY_A;
   860:             ppiUkunCurrentMode = PPI_UKUN_NOTIFY_A;
   861:           }
   862:           if (PPI_UKUN_DEBUG) {
   863:             System.out.printf ("UkunCurrentMode 0x%04x\n", ppiUkunCurrentMode);
   864:           }
   865:           ppiUkunAdjustMenu ();
   866:         } else if (data == 0b0011_0010) {  //Command mode
   867:           ppiUkunRequestedMode = PPI_UKUN_COMMAND;
   868:           ppiUkunCurrentMode = PPI_UKUN_COMMAND;
   869:           if (PPI_UKUN_DEBUG) {
   870:             System.out.printf ("UkunCurrentMode 0x%04x\n", ppiUkunCurrentMode);
   871:           }
   872:           ppiUkunAdjustMenu ();
   873:           System.out.printf (Multilingual.mlnJapanese ?
   874:                              "じょいぽーと U 君 (%s) は Command モードで初期化されました\n" :
   875:                              "JoyPortUkun (%s) has been initialized in Command mode\n",
   876:                              ppiUkunPortName);
   877:           //シリアルポートデータリスナーを解除する
   878:           ppiUkunSerialPort.removeDataListener ();
   879:           ppiUkunDataListener = null;
   880:           break;
   881:         } else {
   882:           System.out.printf ("UkunDataListener received unknown data 0x%02x\n", data);
   883:           //シリアルポートデータリスナーを解除する
   884:           ppiUkunSerialPort.removeDataListener ();
   885:           ppiUkunDataListener = null;
   886:           break;
   887:         }
   888:       }  //while
   889:     }  //serialEvent
   890:   }  //class UkunDataListener
   891: 
   892:   //class UkunThread
   893:   //  受信スレッド
   894:   public static class UkunThread extends Thread {
   895:     @Override public void run () {
   896:       if (PPI_UKUN_DEBUG) {
   897:         System.out.println ("UkunThread start");
   898:       }
   899:       try {
   900:         while (ppiUkunCurrentConnection) {
   901:           //受信する
   902:           //  受信するかキャンセルされるまでブロックする
   903:           int data = ppiUkunOldInputStream.read ();
   904:           if (PPI_UKUN_DEBUG) {
   905:             System.out.printf ("UkunThread received 0x%02x\n", data);
   906:           }
   907:           //変化通知
   908:           //  0b1..0_....  portA  0b1..1_....
   909:           //  0b1..1_....  portB  0b1..1_....
   910:           //  0b0000_....  portC  0b...._0000
   911:           //完了通知
   912:           //  0b0011_1111  completed
   913:           //モード通知
   914:           //  0b0011_0001  Notify mode
   915:           //  0b0011_0010  Command mode
   916:           if ((data & 0b1001_0000) == 0b1000_0000) {  //0b1..0_.... portA
   917:             ppiUkunPortA = 0b1001_0000 | data;  //0b1..1_....
   918:           } else if ((data & 0b1001_0000) == 0b1001_0000) {  //0b1..1_.... portB
   919:             ppiUkunPortB = data;  //0b1..1_....
   920:           } else if (data <= 0b0000_1111) {  //0b0000_.... portC
   921:             ppiUkunPortC = data << 4;  //0b...._0000
   922:           } else if (data == 0b0011_1111) {  //completed
   923:             ppiUkunSending = false;
   924:           } else if (data == 0b0011_0001) {  //Notify mode
   925:             if (ppiUkunRequestedMode == PPI_UKUN_NOTIFY_B) {
   926:               System.out.printf (Multilingual.mlnJapanese ?
   927:                                  "じょいぽーと U 君 (%s) は Notify(B) モードで初期化されました\n" :
   928:                                  "JoyPortUkun (%s) has been initialized in Notify(B) mode\n",
   929:                                  ppiUkunPortName);
   930:               //ppiUkunRequestedMode = PPI_UKUN_NOTIFY_B;
   931:               ppiUkunCurrentMode = PPI_UKUN_NOTIFY_B;
   932:             } else {
   933:               System.out.printf (Multilingual.mlnJapanese ?
   934:                                  "じょいぽーと U 君 (%s) は Notify(A) モードで初期化されました\n" :
   935:                                  "JoyPortUkun (%s) has been initialized in Notify(A) mode\n",
   936:                                  ppiUkunPortName);
   937:               ppiUkunRequestedMode = PPI_UKUN_NOTIFY_A;
   938:               ppiUkunCurrentMode = PPI_UKUN_NOTIFY_A;
   939:             }
   940:             if (PPI_UKUN_DEBUG) {
   941:               System.out.printf ("UkunCurrentMode 0x%04x\n", ppiUkunCurrentMode);
   942:             }
   943:             ppiUkunAdjustMenu ();
   944:           } else if (data == 0b0011_0010) {  //Command mode
   945:             ppiUkunRequestedMode = PPI_UKUN_COMMAND;
   946:             ppiUkunCurrentMode = PPI_UKUN_COMMAND;
   947:             if (PPI_UKUN_DEBUG) {
   948:               System.out.printf ("UkunCurrentMode 0x%04x\n", ppiUkunCurrentMode);
   949:             }
   950:             ppiUkunAdjustMenu ();
   951:             System.out.printf (Multilingual.mlnJapanese ?
   952:                                "じょいぽーと U 君 (%s) は Command モードで初期化されました\n" :
   953:                                "JoyPortUkun (%s) has been initialized in Command mode\n",
   954:                                ppiUkunPortName);
   955:             //受信スレッドを終了する
   956:             break;
   957:           } else if (data < 0) {  //キャンセルされた
   958:             //受信スレッドを終了する
   959:             break;
   960:           } else {
   961:             System.out.printf ("UkunThread received unknown data 0x%02x\n", data);
   962:             //受信スレッドを終了する
   963:             break;
   964:           }
   965:         }  //while
   966:       } catch (IOException ioe) {
   967:         ioe.printStackTrace ();
   968:       }
   969:       ppiUkunThread = null;
   970:       if (PPI_UKUN_DEBUG) {
   971:         System.out.println ("UkunThread end");
   972:       }
   973:     }
   974:   }  //class UkunThread
   975: 
   976:   //ppiUkunNanoStart ()
   977:   //  計測開始
   978:   public static void ppiUkunNanoStart () {
   979:     if (PPI_UKUN_ON && PPI_UKUN_NANO) {
   980:       XEiJ.tmrTimer.schedule (new TimerTask () {
   981:         @Override public void run () {
   982:           if (!ppiUkunNanoMeasuring) {
   983:             ppiUkunNanoMeasuring = true;
   984:             Arrays.fill (ppiUkunNanoBestArray, Long.MAX_VALUE);
   985:             Arrays.fill (ppiUkunNanoWorstArray, 0L);
   986:             Arrays.fill (ppiUkunNanoTotalArray, 0L);
   987:             Arrays.fill (ppiUkunNanoCountArray, 0L);
   988:           }
   989:         }
   990:       }, 0L);
   991:     }
   992:   }
   993: 
   994:   //ppiUkunNanoEnd ()
   995:   //  計測終了
   996:   public static void ppiUkunNanoEnd () {
   997:     if (PPI_UKUN_ON && PPI_UKUN_NANO) {
   998:       XEiJ.tmrTimer.schedule (new TimerTask () {
   999:         @Override public void run () {
  1000:           if (ppiUkunNanoMeasuring) {
  1001:             ppiUkunNanoMeasuring = false;
  1002:             System.out.println ("Nano timer");
  1003:             for (int i = 0; i < 8; i++) {
  1004:               long best = ppiUkunNanoBestArray[i];
  1005:               long worst = ppiUkunNanoWorstArray[i];
  1006:               long total = ppiUkunNanoTotalArray[i];
  1007:               long count = ppiUkunNanoCountArray[i];
  1008:               if (count != 0L) {
  1009:                 System.out.printf ("  %s %s best=%d(ns) average=%d(ns) worst=%d(ns) total=%d(ns) count=%d\n",
  1010:                                    i < 2 ? "PORT A" : i < 4 ? "PORT B" : i < 6 ? "PORT C" : "CONTROL WORD",
  1011:                                    (i & 1) == 0 ? "READ" : "WRITE",
  1012:                                    best,
  1013:                                    total / count,
  1014:                                    worst,
  1015:                                    total,
  1016:                                    count);
  1017:               }
  1018:             }
  1019:           }
  1020:         }
  1021:       }, 0L);
  1022:     }
  1023:   }
  1024: 
  1025: 
  1026:   //ppiStart ()
  1027:   public static void ppiStart () {
  1028:     if (RestorableFrame.rfmGetOpened (Settings.SGS_PPI_FRAME_KEY)) {
  1029:       ppiOpen ();
  1030:     }
  1031:     if (PPI_UKUN_ON) {
  1032:       if (ppiUkunRequestedConnection) {
  1033:         ppiUkunConnect ();
  1034:       }
  1035:     }
  1036:   }
  1037: 
  1038:   //ppiOpen ()
  1039:   //  ジョイスティックの設定ウインドウを開く
  1040:   public static void ppiOpen () {
  1041:     if (ppiFrame == null) {
  1042:       ppiMakeFrame ();
  1043:     }
  1044:     XEiJ.pnlExitFullScreen (false);
  1045:     ppiFrame.setVisible (true);
  1046:   }
  1047: 
  1048:   //ppiMakeFrame ()
  1049:   //  ジョイスティックポートの設定ウインドウを作る
  1050:   //  ここでは開かない
  1051:   public static void ppiMakeFrame () {
  1052: 
  1053:     //アクションリスナー
  1054:     ActionListener actionListener = new ActionListener () {
  1055:       @Override public void actionPerformed (ActionEvent ae) {
  1056:         Object source = ae.getSource ();
  1057:         String command = ae.getActionCommand ();
  1058:         switch (command) {
  1059:         case "Consider part of keyboard as joystick":
  1060:           //キーボードの一部をジョイスティックとみなす
  1061:           ppiJoyKey = ((JCheckBox) ae.getSource ()).isSelected ();
  1062:           break;
  1063:         case "Enabled only while the port is read repeatedly":
  1064:           //ポートが繰り返し読み出されている間だけ有効
  1065:           ppiJoyAuto = ((JCheckBox) ae.getSource ()).isSelected ();
  1066:           break;
  1067:         case "Remove key input data processed as a joystick operation":
  1068:           //ジョイスティック操作として処理されたキー入力データを取り除く
  1069:           ppiJoyBlock = ((JCheckBox) ae.getSource ()).isSelected ();
  1070:           break;
  1071:           //
  1072:         case "JoyPortUkun":  //じょいぽーと U 君
  1073:           if (PPI_UKUN_ON) {
  1074:             if (((JCheckBox) ae.getSource ()).isSelected ()) {  //接続
  1075:               ppiUkunMenuConnect ();
  1076:             } else {  //切断
  1077:               ppiUkunMenuDisconnect ();
  1078:             }
  1079:           }
  1080:           break;
  1081:         case "Notify(A) mode":  //Notify(A) モード
  1082:           if (PPI_UKUN_ON) {
  1083:             ppiUkunMenuNotifyAMode ();
  1084:           }
  1085:           break;
  1086:         case "Notify(B) mode":  //Notify(B) モード
  1087:           if (PPI_UKUN_ON) {
  1088:             ppiUkunMenuNotifyBMode ();
  1089:           }
  1090:           break;
  1091:         case "Command mode":  //Command モード
  1092:           if (PPI_UKUN_ON) {
  1093:             ppiUkunMenuCommandMode ();
  1094:           }
  1095:           break;
  1096:         case "jSerialComm":
  1097:           if (PPI_UKUN_ON && PPI_UKUN_JSERIALCOMM && !ppiUkunCurrentConnection) {  //接続中は操作禁止
  1098:             ppiUkunJSerialCommOn = !XEiJ.prgIsWindows || ((JCheckBox) ae.getSource ()).isSelected ();  //Windows以外は常にtrue
  1099:             ppiUkunAdjustMenu ();
  1100:           }
  1101:           break;
  1102:         case "Output interval adjustment":  //出力間隔調整
  1103:           if (PPI_UKUN_ON && PPI_UKUN_INTERVAL) {
  1104:             boolean on = ((JCheckBox) ae.getSource ()).isSelected ();
  1105:             if (ppiUkunIntervalOn != on) {
  1106:               if (on) {
  1107:                 XEiJ.tmrTimer.schedule (new TimerTask () {
  1108:                   @Override public void run () {
  1109:                     ppiUkunLastVirtualTime = XEiJ.mpuClockTime;
  1110:                     ppiUkunLastRealTime = System.nanoTime ();
  1111:                     ppiUkunIntervalOn = true;
  1112:                   }
  1113:                 }, 0L);                
  1114:               } else {
  1115:                 XEiJ.tmrTimer.schedule (new TimerTask () {
  1116:                   @Override public void run () {
  1117:                     ppiUkunIntervalOn = false;
  1118:                   }
  1119:                 }, 0L);                
  1120:               }
  1121:             }
  1122:           }
  1123:           break;
  1124:         case "Nano timer":  //ナノタイマー
  1125:           if (PPI_UKUN_ON && PPI_UKUN_NANO) {
  1126:             if (((JCheckBox) ae.getSource ()).isSelected ()) {  //計測開始
  1127:               ppiUkunNanoStart ();
  1128:             } else {  //計測終了
  1129:               ppiUkunNanoEnd ();
  1130:             }
  1131:           }
  1132:           break;
  1133:         case "XInput":
  1134:           if (PPI_XINPUT_ON) {
  1135:             if (((JCheckBox) ae.getSource ()).isSelected ()) {  //on
  1136:               if (!ppiXInputOn) {  //off→on
  1137:                 ppiXInputOn = true;
  1138:                 ppiXInputStart ();
  1139:               }
  1140:             } else {  //off
  1141:               if (ppiXInputOn) {  //on→off
  1142:                 ppiXInputOn = false;
  1143:                 ppiXInputEnd ();
  1144:               }
  1145:             }
  1146:           }
  1147:         }
  1148:       }
  1149:     };
  1150: 
  1151:     //ジョイスティックポートのメニュー
  1152:     //       0   1  2
  1153:     //   0  ポート  接続
  1154:     //   1   1   2
  1155:     //   2  -------------------------
  1156:     //   3  RB  RB  なし
  1157:     //   4  RB  RB  ノーマル2ボタンパッド#1
  1158:     //   5  RB  RB  ノーマル2ボタンパッド#2
  1159:     //   6  RB  RB  メガドラ3ボタンパッド#1
  1160:     //   7  RB  RB  メガドラ3ボタンパッド#2
  1161:     //   8  RB  RB  メガドラ6ボタンパッド#1
  1162:     //   9  RB  RB  メガドラ6ボタンパッド#2
  1163:     //  10  RB  RB  サイバースティック(デジタルモード)#1
  1164:     //  12  RB  RB  サイバースティック(デジタルモード)#2
  1165:     //  13  RB  RB  サイバースティック(アナログモード)#1
  1166:     //  14  RB  RB  サイバースティック(アナログモード)#2
  1167:     //  15  RB  RB  白窓君#1
  1168:     //  16  RB  RB  白窓君#2
  1169:     ButtonGroup port1Group = new ButtonGroup ();
  1170:     ButtonGroup port2Group = new ButtonGroup ();
  1171:     ActionListener port1Listener = new ActionListener () {
  1172:       @Override public void actionPerformed (ActionEvent ae) {
  1173:         Joystick joyStick = ppiJoysticks[Integer.parseInt (ae.getActionCommand ())];
  1174:         if (ppiJoystick1 != joyStick) {
  1175:           ppiJoystick1.reset ();
  1176:           ppiJoystick1 = joyStick;
  1177:         }
  1178:         ppiConfigurationScrollPane.setViewportView (joyStick.getConfigurationPanel ());
  1179:       }
  1180:     };
  1181:     ActionListener port2Listener = new ActionListener () {
  1182:       @Override public void actionPerformed (ActionEvent ae) {
  1183:         Joystick joyStick = ppiJoysticks[Integer.parseInt (ae.getActionCommand ())];
  1184:         if (ppiJoystick2 != joyStick) {
  1185:           ppiJoystick2.reset ();
  1186:           ppiJoystick2 = joyStick;
  1187:         }
  1188:         ppiConfigurationScrollPane.setViewportView (joyStick.getConfigurationPanel ());
  1189:       }
  1190:     };
  1191:     ArrayList<Object> cellList = new ArrayList<Object> ();
  1192:     cellList.add (Multilingual.mlnText (ComponentFactory.createLabel ("Port"), "ja", "ポート"));  //(0,0)-(1,0)
  1193:     cellList.add (Multilingual.mlnText (ComponentFactory.createLabel ("Connect to"), "ja", "接続"));  //(2,0)-(2,1)
  1194:     cellList.add ("1");  //(0,1)
  1195:     cellList.add ("2");  //(1,1)
  1196:     cellList.add (ComponentFactory.createHorizontalSeparator ());  //(0,2)-(2,2)
  1197:     for (int i = 0; i < ppiJoysticks.length; i++) {
  1198:       Joystick joyStick = ppiJoysticks[i];
  1199:       cellList.add (ComponentFactory.setText (ComponentFactory.createRadioButton (
  1200:         port1Group, joyStick == ppiJoystick1, String.valueOf (i), port1Listener), ""));  //(0,3+i)
  1201:       cellList.add (ComponentFactory.setText (ComponentFactory.createRadioButton (
  1202:         port2Group, joyStick == ppiJoystick2, String.valueOf (i), port2Listener), ""));  //(1,3+i)
  1203:       cellList.add (Multilingual.mlnText (ComponentFactory.createLabel (joyStick.getNameEn ()), "ja", joyStick.getNameJa ()));  //(3,3)
  1204:     }
  1205:     JScrollPane portMenuPanel = new JScrollPane (
  1206:       ComponentFactory.createGridPanel (
  1207:         3, 3 + ppiJoysticks.length,
  1208:         "paddingLeft=3,paddingRight=3,center",   //gridStyles
  1209:         "",  //colStyles
  1210:         "italic;italic;colSpan=3,widen",  //rowStyles
  1211:         "colSpan=2;rowSpan=2",  //cellStyles
  1212:         cellList.toArray (new Object[0])));
  1213: 
  1214:     //個々のジョイスティックの設定パネル
  1215:     ppiConfigurationScrollPane = new JScrollPane ((((ppiJoystick1 instanceof DummyPad) &&
  1216:                                                     !(ppiJoystick2 instanceof DummyPad)) ||  //2だけ接続されている
  1217:                                                    (!(ppiJoystick1 instanceof Shiromadokun) &&
  1218:                                                     (ppiJoystick2 instanceof Shiromadokun))  //2だけ白窓君
  1219:                                                    ? ppiJoystick2 : ppiJoystick1).getConfigurationPanel ());
  1220: 
  1221:     //ウインドウ
  1222:     ButtonGroup ukunGroup = new ButtonGroup ();
  1223:     ppiFrame = Multilingual.mlnTitle (
  1224:       ComponentFactory.createRestorableSubFrame (
  1225:         Settings.SGS_PPI_FRAME_KEY,
  1226:         "Joystick port settings",
  1227:         null,
  1228:         ComponentFactory.setEmptyBorder (
  1229:           ComponentFactory.createVerticalBox (
  1230:             //
  1231:             ComponentFactory.createFlowPanel (
  1232:               ppiUkunConnectCheckbox =
  1233:               !(PPI_UKUN_ON && (PPI_UKUN_JSERIALCOMM || XEiJ.prgWindllLoaded)) ? null :
  1234:               Multilingual.mlnText (
  1235:                 ComponentFactory.setEnabled (
  1236:                   ComponentFactory.createCheckBox (ppiUkunRequestedConnection, "JoyPortUkun", actionListener),
  1237:                   ppiUkunRequestedConnection == ppiUkunCurrentConnection),
  1238:                 "ja", "じょいぽーと U 君")
  1239:               ),
  1240:             !(PPI_UKUN_ON && (PPI_UKUN_JSERIALCOMM || XEiJ.prgWindllLoaded)) ? null :
  1241:             ComponentFactory.createFlowPanel (
  1242:               20, 0,
  1243:               ppiUkunNotifyAModeRadioButton =
  1244:               Multilingual.mlnText (
  1245:                 ComponentFactory.setEnabled (
  1246:                   ComponentFactory.createRadioButton (ukunGroup, ppiUkunRequestedMode == PPI_UKUN_NOTIFY_A, "Notify(A) mode", actionListener),
  1247:                   !(ppiUkunCurrentConnection && ppiUkunRequestedMode != ppiUkunCurrentMode)),
  1248:                 "ja", "Notify(A) モード"),
  1249:               ppiUkunNotifyBModeRadioButton =
  1250:               Multilingual.mlnText (
  1251:                 ComponentFactory.setEnabled (
  1252:                   ComponentFactory.createRadioButton (ukunGroup, ppiUkunRequestedMode == PPI_UKUN_NOTIFY_B, "Notify(B) mode", actionListener),
  1253:                   !(ppiUkunCurrentConnection && ppiUkunRequestedMode != ppiUkunCurrentMode)),
  1254:                 "ja", "Notify(B) モード"),
  1255:               ppiUkunCommandModeRadioButton =
  1256:               Multilingual.mlnText (
  1257:                 ComponentFactory.setEnabled (
  1258:                   ComponentFactory.createRadioButton (ukunGroup, ppiUkunRequestedMode == PPI_UKUN_COMMAND, "Command mode", actionListener),
  1259:                   !(ppiUkunCurrentConnection && ppiUkunRequestedMode != ppiUkunCurrentMode)),
  1260:                 "ja", "Command モード")
  1261:               ),
  1262:             !(PPI_UKUN_ON && (PPI_UKUN_JSERIALCOMM || XEiJ.prgWindllLoaded)) ? null :
  1263:             ComponentFactory.createFlowPanel (
  1264:               20, 0,
  1265:               ppiUkunJSerialCommCheckbox =
  1266:               ComponentFactory.setEnabled (
  1267:                 ComponentFactory.createCheckBox (ppiUkunJSerialCommOn, "jSerialComm", actionListener),
  1268:                 XEiJ.prgIsWindows && !ppiUkunCurrentConnection),
  1269:               Multilingual.mlnText (
  1270:                 ComponentFactory.createCheckBox (ppiUkunIntervalOn, "Output interval adjustment", actionListener),
  1271:                 "ja", "出力間隔調整"),
  1272:               !PPI_UKUN_NANO ? null :
  1273:               Multilingual.mlnText (
  1274:                 ComponentFactory.createCheckBox (ppiUkunNanoMeasuring, "Nano timer", actionListener),
  1275:                 "ja", "ナノタイマー")
  1276:               ),
  1277:             !(PPI_UKUN_ON && (PPI_UKUN_JSERIALCOMM || XEiJ.prgWindllLoaded)) ? null : ComponentFactory.createHorizontalSeparator (),
  1278:             //
  1279:             !(PPI_XINPUT_ON && XEiJ.prgWindllLoaded) ? null :
  1280:             ComponentFactory.createFlowPanel (
  1281:               ComponentFactory.createCheckBox (ppiXInputOn, "XInput", actionListener)
  1282:               ),
  1283:             !(PPI_XINPUT_ON && XEiJ.prgWindllLoaded) ? null : ComponentFactory.createHorizontalSeparator (),
  1284:             //
  1285:             ComponentFactory.createFlowPanel (
  1286:               Multilingual.mlnText (
  1287:                 ComponentFactory.createCheckBox (
  1288:                   ppiJoyKey,
  1289:                   "Consider part of keyboard as joystick",
  1290:                   actionListener),
  1291:                 "ja", "キーボードの一部をジョイスティックとみなす")
  1292:               ),
  1293:             ComponentFactory.createFlowPanel (
  1294:               Multilingual.mlnText (
  1295:                 ComponentFactory.createCheckBox (
  1296:                   ppiJoyAuto,
  1297:                   "Enabled only while the port is read repeatedly",
  1298:                   actionListener),
  1299:                 "ja", "ポートが繰り返し読み出されている間だけ有効")
  1300:               ),
  1301:             ComponentFactory.createFlowPanel (
  1302:               Multilingual.mlnText (
  1303:                 ComponentFactory.createCheckBox (
  1304:                   ppiJoyBlock,
  1305:                   "Remove key input data processed as a joystick operation",
  1306:                   actionListener),
  1307:                 "ja", "ジョイスティック操作として処理されたキー入力データを取り除く")
  1308:               ),
  1309:             Box.createVerticalStrut (5),
  1310:             ComponentFactory.createHorizontalBox (
  1311:               ComponentFactory.createHorizontalSplitPane (
  1312:                 portMenuPanel,
  1313:                 ppiConfigurationScrollPane)
  1314:               )
  1315:             ),
  1316:           5, 5, 5, 5)),
  1317:       "ja", "ジョイスティックポート設定");
  1318:   }  //ppiMakeFrame()
  1319: 
  1320:   //consume = ppiInput (ke, pressed)
  1321:   //  JOYKEYの処理
  1322:   //  consume  true=入力をキーボードに渡さない
  1323:   public static boolean ppiInput (KeyEvent ke, boolean pressed) {
  1324:     boolean consume = false;
  1325:     if (ppiJoyKey && (!ppiJoyAuto || XEiJ.mpuClockTime < ppiLastAccessTime + PPI_CONTINUOUS_ACCESS_SPAN)) {
  1326:       if (ppiJoystick1.input (ke, pressed) ||
  1327:           ppiJoystick2.input (ke, pressed)) {
  1328:         //押されたときだけキーボード入力を取り除く
  1329:         //  特に自動有効化のときは、押されている間に有効になって離されたデータだけ取り除かれると、
  1330:         //  キーボード側は押されたままになっていると判断してリピートが止まらなくなる
  1331:         consume = pressed && ppiJoyBlock;
  1332:       }
  1333:     }
  1334:     return consume;
  1335:   }
  1336: 
  1337: 
  1338:   //ppiUkunAdjustInterval ()
  1339:   //  出力間隔調整
  1340:   //  PPIへの書き込みの間隔を仮想時間と実時間でそれぞれ計測し、
  1341:   //  500usを上限として、
  1342:   //  仮想時間の間隔の方が短ければウェイトを、
  1343:   //  実時間の間隔の方が短ければ空ループを追加することで、
  1344:   //  仮想時間の間隔と実時間の間隔のずれを軽減する。
  1345:   //  空ループを追加するとき負荷率が高くなる。
  1346:   public static void ppiUkunAdjustInterval () {
  1347:     long virtualTime = XEiJ.mpuClockTime;  //仮想時間。ピコ秒
  1348:     long realTime = System.nanoTime ();  //実時間。ナノ秒
  1349:     long virtualInterval = virtualTime - ppiUkunLastVirtualTime;  //仮想時間の間隔
  1350:     long realInterval = realTime - ppiUkunLastRealTime;  //実時間の間隔
  1351:     ppiUkunLastVirtualTime = virtualTime;
  1352:     ppiUkunLastRealTime = realTime;
  1353:     realInterval *= XEiJ.TMR_FREQ / 1000000000L;  //ナノ秒→ピコ秒
  1354:     if (virtualInterval <= realInterval) {  //仮想時間の間隔の方が短い。ウェイトを追加する
  1355:       long adjustmentTime = realInterval - virtualInterval;
  1356:       adjustmentTime = Math.min (PPI_UKUN_INTERVAL_LIMIT, adjustmentTime);
  1357:       XEiJ.mpuClockTime += adjustmentTime;
  1358:     } else {  //実時間の間隔の方が短い。空ループを追加する
  1359:       long adjustmentTime = virtualInterval - realInterval;
  1360:       adjustmentTime = Math.min (PPI_UKUN_INTERVAL_LIMIT, adjustmentTime);
  1361:       adjustmentTime /= XEiJ.TMR_FREQ / 1000000000L;  //ピコ秒→ナノ秒
  1362:       if (adjustmentTime != 0L) {
  1363:         if (true) {  //空ループを追加する
  1364:           while (System.nanoTime () < realTime + adjustmentTime) {
  1365:           }
  1366:         } else {  //スリープを追加する
  1367:           try {
  1368:             Thread.sleep (adjustmentTime / 1000000L, (int) (adjustmentTime % 1000000L));
  1369:           } catch (InterruptedException ie) {
  1370:           }
  1371:         }
  1372:       }
  1373:     }
  1374:   }  //ppiUkunAdjustInterval
  1375: 
  1376: 
  1377:   //  リード
  1378:   //  FM音源レジスタのアクセスウェイトのためのPPIの空読みは、ジョイスティックのデータを得ることが目的ではないので、
  1379:   //  ジョイスティックポートが連続的に読み出されているとみなさない
  1380:   public static int ppiReadByte (int a) {
  1381:     int d;
  1382:     //
  1383:     long t;
  1384:     if (PPI_UKUN_NANO) {
  1385:       t = System.nanoTime ();
  1386:     }
  1387:     //
  1388:     switch (a & 7) {
  1389:       //
  1390:     case PPI_PORT_A & 7:
  1391:       if (PPI_UKUN_ON &&
  1392:           ppiUkunCurrentConnection) {  //接続している
  1393:         if (ppiUkunCurrentMode == PPI_UKUN_NOTIFY_B) {  //Notify(B)モード
  1394:           if (ppiUkunSending) {
  1395:             XEiJ.mpuClockTime += PPI_UKUN_WAIT;
  1396:             do {
  1397:             } while (ppiUkunSending);
  1398:           }
  1399:         } else if (ppiUkunCurrentMode == PPI_UKUN_COMMAND) {  //Commandモード
  1400:           XEiJ.mpuClockTime += PPI_UKUN_WAIT;
  1401:           if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1402:             byte[] b = new byte[] { (byte) 0b0011_1010 };  //リードポートA
  1403:             ppiUkunSerialPort.writeBytes (b, 1);
  1404:             ppiUkunSerialPort.readBytes (b, 1);
  1405:             ppiUkunPortA = b[0] & 0xff;
  1406:           } else {  //!jSerialComm
  1407:             try {
  1408:               ppiUkunOldOutputStream.write (0b0011_1010);  //リードポートA
  1409:               ppiUkunPortA = ppiUkunOldInputStream.read ();
  1410:             } catch (IOException ioe) {
  1411:               ioe.printStackTrace ();
  1412:               ppiUkunDisconnect ();
  1413:             }
  1414:           }  //if jSerialComm/!
  1415:         }
  1416:         d = ppiUkunPortA;
  1417:       } else {  //接続していない
  1418:         if (XEiJ.regOC >> 6 != 0b0100_101_000) {  //TST.B以外
  1419:           ppiLastAccessTime = XEiJ.mpuClockTime;
  1420:         }
  1421:         d = ppiJoystick1.readByte () & 0xff;
  1422:       }
  1423:       break;
  1424:       //
  1425:     case PPI_PORT_B & 7:
  1426:       if (PPI_UKUN_ON &&
  1427:           ppiUkunCurrentConnection) {  //接続している
  1428:         if (ppiUkunCurrentMode == PPI_UKUN_NOTIFY_B) {  //Notify(B)モード
  1429:           if (ppiUkunSending) {
  1430:             XEiJ.mpuClockTime += PPI_UKUN_WAIT;
  1431:             do {
  1432:             } while (ppiUkunSending);
  1433:           }
  1434:         } else if (ppiUkunCurrentMode == PPI_UKUN_COMMAND) {  //Commandモード
  1435:           XEiJ.mpuClockTime += PPI_UKUN_WAIT;
  1436:           if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1437:             byte[] b = new byte[] { (byte) 0b0011_1011 };  //リードポートB
  1438:             ppiUkunSerialPort.writeBytes (b, 1);
  1439:             ppiUkunSerialPort.readBytes (b, 1);
  1440:             ppiUkunPortB = b[0] & 0xff;
  1441:           } else {  //!jSerialComm
  1442:             try {
  1443:               ppiUkunOldOutputStream.write (0b0011_1011);  //リードポートB
  1444:               ppiUkunPortB = ppiUkunOldInputStream.read ();
  1445:             } catch (IOException ioe) {
  1446:               ioe.printStackTrace ();
  1447:               ppiUkunDisconnect ();
  1448:             }
  1449:           }  //if jSerialComm/!
  1450:         }
  1451:         d = ppiUkunPortB;
  1452:       } else {  //接続していない
  1453:         if (XEiJ.regOC >> 6 != 0b0100_101_000) {  //TST.B以外
  1454:           ppiLastAccessTime = XEiJ.mpuClockTime;
  1455:         }
  1456:         d = ppiJoystick2.readByte () & 0xff;
  1457:       }
  1458:       break;
  1459:       //
  1460:     case PPI_PORT_C & 7:
  1461:       if (PPI_UKUN_ON &&
  1462:           ppiUkunCurrentConnection) {  //接続している
  1463:         XEiJ.mpuClockTime += PPI_UKUN_WAIT;
  1464:         if (ppiUkunCurrentMode == PPI_UKUN_NOTIFY_B) {  //Notify(B)モード
  1465:           if (ppiUkunSending) {
  1466:             XEiJ.mpuClockTime += PPI_UKUN_WAIT;
  1467:             do {
  1468:             } while (ppiUkunSending);
  1469:           }
  1470:         } else if (ppiUkunCurrentMode == PPI_UKUN_COMMAND) {  //Commandモード
  1471:           XEiJ.mpuClockTime += PPI_UKUN_WAIT;
  1472:           if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1473:             byte[] b = new byte[] { (byte) 0b0011_1100 };  //リードポートC
  1474:             ppiUkunSerialPort.writeBytes (b, 1);
  1475:             ppiUkunSerialPort.readBytes (b, 1);
  1476:             ppiUkunPortC = b[0] & 0xf0;
  1477:           } else {  //!jSerialComm
  1478:             try {
  1479:               ppiUkunOldOutputStream.write (0b0011_1100);  //リードポートC
  1480:               ppiUkunPortC = ppiUkunOldInputStream.read () & 0xf0;
  1481:             } catch (IOException ioe) {
  1482:               ioe.printStackTrace ();
  1483:               ppiUkunDisconnect ();
  1484:             }
  1485:           }  //if jSerialComm/!
  1486:         }
  1487:         d = (ppiUkunPortC |  //上位4ビット
  1488:              (ppiPortCData & 0x0f));  //下位4ビット
  1489:       } else {  //接続していない
  1490:         d = ppiPortCData;
  1491:       }
  1492:       break;
  1493:     default:
  1494:       d = 0xff;
  1495:     }  //switch a&7
  1496:     //
  1497:     if (PPI_UKUN_NANO) {
  1498:       t = System.nanoTime () - t;
  1499:       int i = a & 6;  //0,2,4,6
  1500:       if (t < ppiUkunNanoBestArray[i]) {
  1501:         ppiUkunNanoBestArray[i] = t;
  1502:       }
  1503:       if (ppiUkunNanoWorstArray[i] < t) {
  1504:         ppiUkunNanoWorstArray[i] = t;
  1505:       }
  1506:       ppiUkunNanoTotalArray[i] += t;
  1507:       ppiUkunNanoCountArray[i]++;
  1508:     }
  1509:     //
  1510:     return d;
  1511:   }  //ppiReadByte
  1512: 
  1513:   //  ライト
  1514:   public static void ppiWriteByte (int a, int d) {
  1515:     d &= 0xff;
  1516:     //
  1517:     long t;
  1518:     if (PPI_UKUN_NANO) {
  1519:       t = System.nanoTime ();
  1520:     }
  1521:     //
  1522:     switch (a & 7) {
  1523:       //
  1524:     case PPI_PORT_A & 7:
  1525:       if (PPI_UKUN_ON &&
  1526:           ppiUkunCurrentConnection) {  //接続している
  1527:         if (PPI_UKUN_INTERVAL && ppiUkunIntervalOn) {
  1528:           ppiUkunAdjustInterval ();
  1529:         } else {
  1530:           XEiJ.mpuClockTime += PPI_UKUN_WAIT;
  1531:         }
  1532:         if (ppiUkunCurrentMode == PPI_UKUN_NOTIFY_A) {  //Notify(A)モード
  1533:           ppiUkunSending = true;
  1534:           if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1535:             ppiUkunSerialPort.writeBytes (new byte[] { (byte) (0b1000_0000 | (d & 0b0110_1111)) }, 1);  //ライトポートA
  1536:           } else {  //!jSerialComm
  1537:             try {
  1538:               ppiUkunOldOutputStream.write (0b1000_0000 | (d & 0b0110_1111));  //ライトポートA
  1539:             } catch (IOException ioe) {
  1540:               ioe.printStackTrace ();
  1541:               ppiUkunDisconnect ();
  1542:             }
  1543:           }  //if jSerialComm/!
  1544:           while (ppiUkunSending) {
  1545:           }
  1546:         } else if (ppiUkunCurrentMode == PPI_UKUN_NOTIFY_B) {  //Notify(B)モード
  1547:           while (ppiUkunSending) {
  1548:           }
  1549:           ppiUkunSending = true;
  1550:           if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1551:             ppiUkunSerialPort.writeBytes (new byte[] { (byte) (0b1000_0000 | (d & 0b0110_1111)) }, 1);  //ライトポートA
  1552:           } else {  //!jSerialComm
  1553:             try {
  1554:               ppiUkunOldOutputStream.write (0b1000_0000 | (d & 0b0110_1111));  //ライトポートA
  1555:             } catch (IOException ioe) {
  1556:               ioe.printStackTrace ();
  1557:               ppiUkunDisconnect ();
  1558:             }
  1559:           }  //if jSerialComm/!
  1560:         } else if (ppiUkunCurrentMode == PPI_UKUN_COMMAND) {  //Commandモード
  1561:           if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1562:             ppiUkunSerialPort.writeBytes (new byte[] { (byte) (0b1000_0000 | (d & 0b0110_1111)) }, 1);  //ライトポートA
  1563:           } else {  //!jSerialComm
  1564:             try {
  1565:               ppiUkunOldOutputStream.write (0b1000_0000 | (d & 0b0110_1111));  //ライトポートA
  1566:             } catch (IOException ioe) {
  1567:               ioe.printStackTrace ();
  1568:               ppiUkunDisconnect ();
  1569:             }
  1570:           }  //if jSerialComm/!
  1571:         }
  1572:       } else {  //接続していない
  1573:         ppiJoystick1.writeByte (d);
  1574:       }
  1575:       break;
  1576:       //
  1577:     case PPI_PORT_B & 7:
  1578:       if (PPI_UKUN_ON &&
  1579:           ppiUkunCurrentConnection) {  //接続している
  1580:         if (PPI_UKUN_INTERVAL && ppiUkunIntervalOn) {
  1581:           ppiUkunAdjustInterval ();
  1582:         } else {
  1583:           XEiJ.mpuClockTime += PPI_UKUN_WAIT;
  1584:         }
  1585:         if (ppiUkunCurrentMode == PPI_UKUN_NOTIFY_A) {  //Notify(A)モード
  1586:           ppiUkunSending = true;
  1587:           if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1588:             ppiUkunSerialPort.writeBytes (new byte[] { (byte) (0b1001_0000 | (d & 0b0110_1111)) }, 1);  //ライトポートB
  1589:           } else {  //!jSerialComm
  1590:             try {
  1591:               ppiUkunOldOutputStream.write (0b1001_0000 | (d & 0b0110_1111));  //ライトポートB
  1592:             } catch (IOException ioe) {
  1593:               ioe.printStackTrace ();
  1594:               ppiUkunDisconnect ();
  1595:             }
  1596:           }  //if jSerialComm/!
  1597:           while (ppiUkunSending) {
  1598:           }
  1599:         } else if (ppiUkunCurrentMode == PPI_UKUN_NOTIFY_B) {  //Notify(B)モード
  1600:           while (ppiUkunSending) {
  1601:           }
  1602:           ppiUkunSending = true;
  1603:           if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1604:             ppiUkunSerialPort.writeBytes (new byte[] { (byte) (0b1001_0000 | (d & 0b0110_1111)) }, 1);  //ライトポートB
  1605:           } else {  //!jSerialComm
  1606:             try {
  1607:               ppiUkunOldOutputStream.write (0b1001_0000 | (d & 0b0110_1111));  //ライトポートB
  1608:             } catch (IOException ioe) {
  1609:               ioe.printStackTrace ();
  1610:               ppiUkunDisconnect ();
  1611:             }
  1612:           }  //if jSerialComm/!
  1613:         } else if (ppiUkunCurrentMode == PPI_UKUN_COMMAND) {  //Commandモード
  1614:           if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1615:             ppiUkunSerialPort.writeBytes (new byte[] { (byte) (0b1001_0000 | (d & 0b0110_1111)) }, 1);  //ライトポートB
  1616:           } else {  //!jSerialComm
  1617:             try {
  1618:               ppiUkunOldOutputStream.write (0b1001_0000 | (d & 0b0110_1111));  //ライトポートB
  1619:             } catch (IOException ioe) {
  1620:               ioe.printStackTrace ();
  1621:               ppiUkunDisconnect ();
  1622:             }
  1623:           }  //if jSerialComm/!
  1624:         }
  1625:       } else {  //接続していない
  1626:         ppiJoystick2.writeByte (d);
  1627:       }
  1628:       break;
  1629:       //
  1630:     case PPI_PORT_C & 7:
  1631:       ppiPortCData = d;
  1632:       //下位4ビット
  1633:       ADPCM.pcmSetPan (d);  //パン
  1634:       ADPCM.pcmDivider = d >> 2 & 3;  //分周比。0=1/1024,1=1/768,2=1/512,3=inhibited
  1635:       ADPCM.pcmUpdateRepeatInterval ();
  1636:       //上位4ビット
  1637:       if (PPI_UKUN_ON &&
  1638:           ppiUkunCurrentConnection) {  //接続している
  1639:         if (PPI_UKUN_INTERVAL && ppiUkunIntervalOn) {
  1640:           ppiUkunAdjustInterval ();
  1641:         } else {
  1642:           XEiJ.mpuClockTime += PPI_UKUN_WAIT;
  1643:         }
  1644:         if (ppiUkunCurrentMode == PPI_UKUN_NOTIFY_A) {  //Notify(A)モード
  1645:           ppiUkunSending = true;
  1646:           if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1647:             ppiUkunSerialPort.writeBytes (new byte[] { (byte) (d >> 4) }, 1);  //ライトポートC
  1648:           } else {  //!jSerialComm
  1649:             try {
  1650:               ppiUkunOldOutputStream.write (d >> 4);  //ライトポートC
  1651:             } catch (IOException ioe) {
  1652:               ioe.printStackTrace ();
  1653:               ppiUkunDisconnect ();
  1654:             }
  1655:           }  //if jSerialComm/!
  1656:           while (ppiUkunSending) {
  1657:           }
  1658:         } else if (ppiUkunCurrentMode == PPI_UKUN_NOTIFY_B) {  //Notify(B)モード
  1659:           while (ppiUkunSending) {
  1660:           }
  1661:           ppiUkunSending = true;
  1662:           if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1663:             ppiUkunSerialPort.writeBytes (new byte[] { (byte) (d >> 4) }, 1);  //ライトポートC
  1664:           } else {  //!jSerialComm
  1665:             try {
  1666:               ppiUkunOldOutputStream.write (d >> 4);  //ライトポートC
  1667:             } catch (IOException ioe) {
  1668:               ioe.printStackTrace ();
  1669:               ppiUkunDisconnect ();
  1670:             }
  1671:           }  //if jSerialComm/!
  1672:         } else if (ppiUkunCurrentMode == PPI_UKUN_COMMAND) {  //Commandモード
  1673:           if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1674:             ppiUkunSerialPort.writeBytes (new byte[] { (byte) (d >> 4) }, 1);  //ライトポートC
  1675:           } else {  //!jSerialComm
  1676:             try {
  1677:               ppiUkunOldOutputStream.write (d >> 4);  //ライトポートC
  1678:             } catch (IOException ioe) {
  1679:               ioe.printStackTrace ();
  1680:               ppiUkunDisconnect ();
  1681:             }
  1682:           }  //if jSerialComm/!
  1683:         }
  1684:       } else {  //接続していない
  1685:         ppiJoystick1.setPin8 (d >> 4 & 1);
  1686:         ppiJoystick2.setPin8 (d >> 5 & 1);
  1687:         ppiJoystick1.setPin6 ((d >> 6 & 1) ^ 1);
  1688:         ppiJoystick1.setPin7 ((d >> 7 & 1) ^ 1);
  1689:       }
  1690:       break;
  1691:       //
  1692:     case PPI_CONTROL & 7:
  1693:       if ((d & 0b1000_0000) == 0b0000_0000) {  //0b0..._nnnx
  1694:         int n = (d >> 1) & 7;  //ビット番号
  1695:         int x = d & 1;  //データ
  1696:         ppiPortCData = ppiPortCData & ~(1 << n) | x << n;
  1697:         if (n < 4) {  //下位4ビット
  1698:           switch (n) {
  1699:           case 0:
  1700:           case 1:
  1701:             ADPCM.pcmSetPan (ppiPortCData & 3);  //パン
  1702:             break;
  1703:           case 2:
  1704:           case 3:
  1705:             ADPCM.pcmDivider = ppiPortCData >> 2 & 3;  //分周比。0=1/1024,1=1/768,2=1/512,3=inhibited
  1706:             ADPCM.pcmUpdateRepeatInterval ();
  1707:             break;
  1708:           }
  1709:         } else {  //上位4ビット
  1710:           if (PPI_UKUN_ON &&
  1711:               ppiUkunCurrentConnection) {  //接続している
  1712:             if (PPI_UKUN_INTERVAL && ppiUkunIntervalOn) {
  1713:               ppiUkunAdjustInterval ();
  1714:             } else {
  1715:               XEiJ.mpuClockTime += PPI_UKUN_WAIT;
  1716:             }
  1717:             if (ppiUkunCurrentMode == PPI_UKUN_NOTIFY_A) {  //Notify(A)モード
  1718:               ppiUkunSending = true;
  1719:               if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1720:                 ppiUkunSerialPort.writeBytes (new byte[] { (byte) (0b0001_0000 | (d & 0b0000_1111)) }, 1);  //ライトコントロールワード
  1721:               } else {  //!jSerialComm
  1722:                 try {
  1723:                   ppiUkunOldOutputStream.write (0b0001_0000 | (d & 0b0000_1111));  //ライトコントロールワード
  1724:                 } catch (IOException ioe) {
  1725:                   ioe.printStackTrace ();
  1726:                   ppiUkunDisconnect ();
  1727:                 }
  1728:               }  //if jSerialComm/!
  1729:               while (ppiUkunSending) {
  1730:               }
  1731:             } else if (ppiUkunCurrentMode == PPI_UKUN_NOTIFY_B) {  //Notify(B)モード
  1732:               while (ppiUkunSending) {
  1733:               }
  1734:               ppiUkunSending = true;
  1735:               if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1736:                 ppiUkunSerialPort.writeBytes (new byte[] { (byte) (0b0001_0000 | (d & 0b0000_1111)) }, 1);  //ライトコントロールワード
  1737:               } else {  //!jSerialComm
  1738:                 try {
  1739:                   ppiUkunOldOutputStream.write (0b0001_0000 | (d & 0b0000_1111));  //ライトコントロールワード
  1740:                 } catch (IOException ioe) {
  1741:                   ioe.printStackTrace ();
  1742:                   ppiUkunDisconnect ();
  1743:                 }
  1744:               }  //if jSerialComm/!
  1745:             } else if (ppiUkunCurrentMode == PPI_UKUN_COMMAND) {  //Commandモード
  1746:               if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1747:                 ppiUkunSerialPort.writeBytes (new byte[] { (byte) (0b0001_0000 | (d & 0b0000_1111)) }, 1);  //ライトコントロールワード
  1748:               } else {  //!jSerialComm
  1749:                 try {
  1750:                   ppiUkunOldOutputStream.write (0b0001_0000 | (d & 0b0000_1111));  //ライトコントロールワード
  1751:                 } catch (IOException ioe) {
  1752:                   ioe.printStackTrace ();
  1753:                   ppiUkunDisconnect ();
  1754:                 }
  1755:               }  //if jSerialComm/!
  1756:             }
  1757:           } else {  //接続していない
  1758:             switch (n) {
  1759:             case 4:
  1760:               ppiJoystick1.setPin8 (x);
  1761:               break;
  1762:             case 5:
  1763:               ppiJoystick2.setPin8 (x);
  1764:               break;
  1765:             case 6:
  1766:               ppiJoystick1.setPin6 (x ^ 1);
  1767:               break;
  1768:             case 7:
  1769:               ppiJoystick1.setPin7 (x ^ 1);
  1770:               break;
  1771:             }
  1772:           }
  1773:         }  //if 下位/上位
  1774:       } else if ((d & 0b1000_0100) == 0b1000_0000){  //0b1..._.0..
  1775:         if (PPI_UKUN_ON &&
  1776:             ppiUkunCurrentConnection) {  //接続している
  1777:           if (PPI_UKUN_INTERVAL && ppiUkunIntervalOn) {
  1778:             ppiUkunAdjustInterval ();
  1779:           } else {
  1780:             XEiJ.mpuClockTime += PPI_UKUN_WAIT;
  1781:           }
  1782:           if (ppiUkunCurrentMode == PPI_UKUN_NOTIFY_A) {  //Notify(A)モード
  1783:             ppiUkunSending = true;
  1784:             if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1785:               ppiUkunSerialPort.writeBytes (new byte[] { (byte) (0b0100_0000 |
  1786:                                                                  (d & 0b0111_1000) >> 1 |
  1787:                                                                  (d & 0b0000_0011)) }, 1);  //ライトコントロールワード
  1788:             } else {  //!jSerialComm
  1789:               try {
  1790:                 ppiUkunOldOutputStream.write (0b0100_0000 |
  1791:                                               (d & 0b0111_1000) >> 1 |
  1792:                                               (d & 0b0000_0011));  //ライトコントロールワード
  1793:               } catch (IOException ioe) {
  1794:                 ioe.printStackTrace ();
  1795:                 ppiUkunDisconnect ();
  1796:               }
  1797:             }  //if jSerialComm/!
  1798:             while (ppiUkunSending) {
  1799:             }
  1800:           } else if (ppiUkunCurrentMode == PPI_UKUN_NOTIFY_B) {  //Notify(B)モード
  1801:             while (ppiUkunSending) {
  1802:             }
  1803:             ppiUkunSending = true;
  1804:             if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1805:               ppiUkunSerialPort.writeBytes (new byte[] { (byte) (0b0100_0000 |
  1806:                                                                  (d & 0b0111_1000) >> 1 |
  1807:                                                                  (d & 0b0000_0011)) }, 1);  //ライトコントロールワード
  1808:             } else {  //!jSerialComm
  1809:               try {
  1810:                 ppiUkunOldOutputStream.write (0b0100_0000 |
  1811:                                               (d & 0b0111_1000) >> 1 |
  1812:                                               (d & 0b0000_0011));  //ライトコントロールワード
  1813:               } catch (IOException ioe) {
  1814:                 ioe.printStackTrace ();
  1815:                 ppiUkunDisconnect ();
  1816:               }
  1817:             }  //if jSerialComm/!
  1818:           } else if (ppiUkunCurrentMode == PPI_UKUN_COMMAND) {  //Commandモード
  1819:             if (PPI_UKUN_JSERIALCOMM && ppiUkunJSerialCommOn) {  //jSerialComm
  1820:               ppiUkunSerialPort.writeBytes (new byte[] { (byte) (0b0100_0000 |
  1821:                                                                  (d & 0b0111_1000) >> 1 |
  1822:                                                                  (d & 0b0000_0011)) }, 1);  //ライトコントロールワード
  1823:             } else {  //!jSerialComm
  1824:               try {
  1825:                 ppiUkunOldOutputStream.write (0b0100_0000 |
  1826:                                               (d & 0b0111_1000) >> 1 |
  1827:                                               (d & 0b0000_0011));  //ライトコントロールワード
  1828:               } catch (IOException ioe) {
  1829:                 ioe.printStackTrace ();
  1830:                 ppiUkunDisconnect ();
  1831:               }
  1832:             }  //if jSerialComm/!
  1833:           }
  1834:         } else {  //接続していない
  1835:           //!!! 未対応
  1836:         }
  1837:       } else {  //0b1..._.1..
  1838:         //!!! 非対応
  1839:       }
  1840:     }  //switch a&7
  1841:     //
  1842:     if (PPI_UKUN_NANO) {
  1843:       t = System.nanoTime () - t;
  1844:       int i = (a & 6) | 1;  //1,3,5,7
  1845:       if (t < ppiUkunNanoBestArray[i]) {
  1846:         ppiUkunNanoBestArray[i] = t;
  1847:       }
  1848:       if (ppiUkunNanoWorstArray[i] < t) {
  1849:         ppiUkunNanoWorstArray[i] = t;
  1850:       }
  1851:       ppiUkunNanoTotalArray[i] += t;
  1852:       ppiUkunNanoCountArray[i]++;
  1853:     }
  1854:     //
  1855:   }  //ppiWriteByte
  1856: 
  1857: }  //class PPI