2011年2月19日土曜日

xfpsをアプリによってコントロールする

以前こちらでラフなコードを書きましたが、ちゃんとxfpsとパイプで通信できるように修正しました。

この関数で、xfpsのパイプのハンドルを取得します。


HANDLE xfpsInitialize()
{
  HANDLE hPipe=INVALID_HANDLE_VALUE;

  GUID hidGuid;
  HDEVINFO hardwareDeviceInfo;

  HidD_GetHidGuid(&hidGuid);
  hardwareDeviceInfo=SetupDiGetClassDevs(&hidGuid, NULL, NULL, 0x12);

  SP_DEVICE_INTERFACE_DATA sp_devinterfacedata;
  sp_devinterfacedata.cbSize=sizeof(SP_DEVICE_INTERFACE_DATA);

  for(DWORD MemberIndex=0; ; MemberIndex++){
    int ret=SetupDiEnumDeviceInterfaces(hardwareDeviceInfo,
                                        NULL,
                                        &hidGuid,
                                        MemberIndex,
                                        &sp_devinterfacedata);
    if(ret==0) break;
  
    DWORD requiredLength, predictedLength;
    SetupDiGetDeviceInterfaceDetail(hardwareDeviceInfo,
                                    &sp_devinterfacedata,
                                    NULL,
                                    0,
                                    &requiredLength,
                                    NULL);
  
    predictedLength=requiredLength;
    PSP_DEVICE_INTERFACE_DETAIL_DATA psp_devinterfacedetail=
      (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(predictedLength);
    psp_devinterfacedetail->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

    SetupDiGetDeviceInterfaceDetail(hardwareDeviceInfo,
                                    &sp_devinterfacedata,
                                    psp_devinterfacedetail,
                                    predictedLength,
                                    &requiredLength,
                                    NULL);
  

    HANDLE hHIDDevice=CreateFile(psp_devinterfacedetail->DevicePath,
                                 0x40000000, // GENERIC_WRITE
                                 2,
                                 NULL, // no SECURITY_ATTRIBUTES
                                 3, // OPEN_EXISTING
                                 0x40000000, // FILE_FLAG_OVERLAPPED
                                 NULL);
  
    if(hHIDDevice!=INVALID_HANDLE_VALUE){
    
      HIDD_ATTRIBUTES HIDAttributes;
      HIDAttributes.Size=sizeof(ULONG);
      HidD_GetAttributes(hHIDDevice, &HIDAttributes);

      PHIDP_PREPARSED_DATA HIDPreparsedData;
      ret=HidD_GetPreparsedData(hHIDDevice, &HIDPreparsedData);
      if(ret){
        HIDP_CAPS HIDCaps;
        HidP_GetCaps(HIDPreparsedData, &HIDCaps);
        //    ...
        HidD_FreePreparsedData(HIDPreparsedData);
      }
      CloseHandle(hHIDDevice);

      char pipeFileName[MAX_PATH];
      if((HIDAttributes.VendorID==0x04b4)&&(HIDAttributes.ProductID==0x0811)){
        wsprintf(pipeFileName, "%s\\PIPE1", psp_devinterfacedetail->DevicePath);
        hPipe=CreateFile(pipeFileName,
                         0xc0000000, // GENERIC_WRITE|GENERIC_READ
                         3, // FILE_SHARE_READ|FILE_SHARE_WRITE
                         NULL,
                         3, // OPEN_EXISTING
                         0,
                         NULL);
      }
    }
    free(psp_devinterfacedetail);
  }
  SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
  return hPipe;
}

このパイプに書き込むデータですが、リバースエンジニアリングとこちらの情報から、以下の50(0x32)バイトを書きこめばよいことがわかります。

#pragma pack(push, 1)
typedef struct
{
  unsigned char Reserved0;
  unsigned char ReportType;
  unsigned char Reserved1;
  unsigned char ButtonState1;
  unsigned char ButtonState2;
  unsigned char PSButtonState;
  unsigned char Reserved2;
  unsigned char LeftStickX;
  unsigned char LeftStickY;
  unsigned char RightStickX;
  unsigned char RightStickY;
  unsigned char Reserved3[4];
  unsigned char PressureUp;
  unsigned char PressureRight;
  unsigned char PressureDown;
  unsigned char PressureLeft;
  unsigned char PressureL2;
  unsigned char PressureR2;
  unsigned char PressureL1;
  unsigned char PressureR1;
  unsigned char PressureTriangle;
  unsigned char PressureCircule;
  unsigned char PressureCross;
  unsigned char PressureSquare;
  unsigned char Reserved4[3];
  unsigned char Charge;
  unsigned char Power;
  unsigned char Connection;
  unsigned char Reserved5[9];
  unsigned short AccelerometerX; // big endian
  unsigned short Accelerometer;  // big endian
  unsigned short AccelerometerZ; // big endian
  unsigned short GyrometerX;     // big endian
}PS3ControllerData;
#pragma pack(pop)


Reserved5の9バイトは、xfpsが書き込んでる内容をそのまま使いましょう。
  rawdata->Reserved5[0]  =0x00;
  rawdata->Reserved5[1]  =0x00;
  rawdata->Reserved5[2]  =0x00;
  rawdata->Reserved5[3]  =0x00;
  rawdata->Reserved5[4]  =0x33;
  rawdata->Reserved5[5]  =0xfe;
  rawdata->Reserved5[6]  =0x77;
  rawdata->Reserved5[7]  =0x01;
  rawdata->Reserved5[8]  =0xc0;

ということで、自作アプリからPSボタンをプッシュ/リリースできることを確認しました。

さて、次はアナログインターフェースの作成ですね。
世の中のアナログ操作系は大抵はポテンショメータの抵抗値変化によって値を出しているので、AD変換して1チップマイコンに取り込むだけですぐできそうです。

さて、ケーブルを買いに行ってきます♪

0 件のコメント:

コメントを投稿