bool PSDualShock4Controller::getTrackingColorID(eCommonTrackingColorID &out_tracking_color_id) const { bool bSuccess = false; if (getIsOpen() && getIsBluetooth()) { out_tracking_color_id = cfg.tracking_color_id; bSuccess = true; } return bSuccess; }
bool PSDualShock4Controller::setTrackingColorID(const eCommonTrackingColorID tracking_color_id) { bool bSuccess = false; if (getIsOpen() && getIsBluetooth()) { cfg.tracking_color_id = tracking_color_id; cfg.save(); bSuccess = true; } return bSuccess; }
IControllerInterface::ePollResult PSDualShock4Controller::poll() { IControllerInterface::ePollResult result = IControllerInterface::_PollResultFailure; if (!getIsBluetooth()) { // Don't bother polling when connected via usb result = IControllerInterface::_PollResultSuccessNoData; } else if (getIsOpen()) { static const int k_max_iterations = 32; for (int iteration = 0; iteration < k_max_iterations; ++iteration) { // Attempt to read the next update packet from the controller int res = hid_read(HIDDetails.Handle, (unsigned char*)InData, sizeof(PSDualShock4DataInput)); if (res == 0) { //SERVER_LOG_WARNING("PSDualShock4Controller::readDataIn") << "Read Bytes: " << res; // Device still in valid state result = (iteration == 0) ? IControllerInterface::_PollResultSuccessNoData : IControllerInterface::_PollResultSuccessNewData; // No more data available. Stop iterating. break; } else if (res < 0) { char hidapi_err_mbs[256]; bool valid_error_mesg = hid_error_mbs(HIDDetails.Handle, hidapi_err_mbs, sizeof(hidapi_err_mbs)); // Device no longer in valid state. if (valid_error_mesg) { SERVER_LOG_ERROR("PSDualShock4Controller::readDataIn") << "HID ERROR: " << hidapi_err_mbs; } result = IControllerInterface::_PollResultFailure; // No more data available. Stop iterating. break; } else { //SERVER_LOG_WARNING("PSDualShock4Controller::readDataIn") << "Read Bytes: " << res; // New data available. Keep iterating. result = IControllerInterface::_PollResultSuccessNewData; } // https://github.com/nitsch/moveonpc/wiki/Input-report PSDualShock4ControllerState newState; // Increment the sequence for every new polling packet newState.PollSequenceNumber = NextPollSequenceNumber; ++NextPollSequenceNumber; // Smush the button state into one unsigned 32-bit variable newState.AllButtons = (((unsigned int)InData->buttons3.raw & 0x3) << 16) | // Get the 1st two bits of buttons: [0|0|0|0|0|0|PS|TPad] (unsigned int)(InData->buttons2.raw << 8) | // [R3|L3|Option|Share|R2|L2|R1|L1] ((unsigned int)InData->buttons1.raw & 0xF0); // Mask out the dpad enum (1st four bits): [tri|cir|x|sq|0|0|0|0] // Converts the dpad enum to independent bit flags { ePSDualShock4_DPad dpad_enum = static_cast<ePSDualShock4_DPad>(InData->buttons1.raw & 0xF); unsigned int dpad_bits= 0; switch (dpad_enum) { case ePSDualShock4_DPad::PSDualShock4DPad_N: dpad_bits |= ePSDS4_Button::Btn_DPAD_UP; break; case ePSDualShock4_DPad::PSDualShock4DPad_NE: dpad_bits |= ePSDS4_Button::Btn_DPAD_UP; dpad_bits |= ePSDS4_Button::Btn_DPAD_RIGHT; break; case ePSDualShock4_DPad::PSDualShock4DPad_E: dpad_bits |= ePSDS4_Button::Btn_DPAD_RIGHT; break; case ePSDualShock4_DPad::PSDualShock4DPad_SE: dpad_bits |= ePSDS4_Button::Btn_DPAD_DOWN; dpad_bits |= ePSDS4_Button::Btn_DPAD_RIGHT; break; case ePSDualShock4_DPad::PSDualShock4DPad_S: dpad_bits |= ePSDS4_Button::Btn_DPAD_DOWN; break; case ePSDualShock4_DPad::PSDualShock4DPad_SW: dpad_bits |= ePSDS4_Button::Btn_DPAD_DOWN; dpad_bits |= ePSDS4_Button::Btn_DPAD_LEFT; break; case ePSDualShock4_DPad::PSDualShock4DPad_W: dpad_bits |= ePSDS4_Button::Btn_DPAD_LEFT; break; case ePSDualShock4_DPad::PSDualShock4DPad_NW: dpad_bits |= ePSDS4_Button::Btn_DPAD_UP; dpad_bits |= ePSDS4_Button::Btn_DPAD_LEFT; break; } // Append in the DPad bits newState.AllButtons |= (dpad_bits & 0xf); } // Update the button state enum { unsigned int lastButtons = ControllerStates.empty() ? 0 : ControllerStates.back().AllButtons; newState.DPad_Up = getButtonState(newState.AllButtons, lastButtons, Btn_DPAD_UP); newState.DPad_Down = getButtonState(newState.AllButtons, lastButtons, Btn_DPAD_DOWN); newState.DPad_Left = getButtonState(newState.AllButtons, lastButtons, Btn_DPAD_LEFT); newState.DPad_Right = getButtonState(newState.AllButtons, lastButtons, Btn_DPAD_RIGHT); newState.Square = getButtonState(newState.AllButtons, lastButtons, Btn_SQUARE); newState.Cross = getButtonState(newState.AllButtons, lastButtons, Btn_CROSS); newState.Circle = getButtonState(newState.AllButtons, lastButtons, Btn_CIRCLE); newState.Triangle = getButtonState(newState.AllButtons, lastButtons, Btn_TRIANGLE); newState.L1 = getButtonState(newState.AllButtons, lastButtons, Btn_L1); newState.R1 = getButtonState(newState.AllButtons, lastButtons, Btn_R1); newState.L2 = getButtonState(newState.AllButtons, lastButtons, Btn_L2); newState.R2 = getButtonState(newState.AllButtons, lastButtons, Btn_R2); newState.Share = getButtonState(newState.AllButtons, lastButtons, Btn_SHARE); newState.Options = getButtonState(newState.AllButtons, lastButtons, Btn_OPTION); newState.L3 = getButtonState(newState.AllButtons, lastButtons, Btn_L3); newState.R3 = getButtonState(newState.AllButtons, lastButtons, Btn_R3); newState.PS = getButtonState(newState.AllButtons, lastButtons, Btn_PS); newState.TrackPadButton = getButtonState(newState.AllButtons, lastButtons, Btn_TPAD); } // Remap the analog sticks from [0,255] -> [-1.f,1.f] newState.LeftAnalogX= ((static_cast<float>(InData->left_stick_x) / 255.f) - 0.5f) * 2.f; newState.LeftAnalogY = ((static_cast<float>(InData->left_stick_y) / 255.f) - 0.5f) * 2.f; newState.RightAnalogX = ((static_cast<float>(InData->right_stick_x) / 255.f) - 0.5f) * 2.f; newState.RightAnalogY = ((static_cast<float>(InData->right_stick_y) / 255.f) - 0.5f) * 2.f; // Remap the analog triggers from [0,255] -> [0.f,1.f] newState.LeftTrigger = static_cast<float>(InData->left_trigger) / 255.f; newState.RightTrigger = static_cast<float>(InData->right_trigger) / 255.f; // Processes the IMU data { // Piece together the 12-bit accelerometer data short raw_accelX = static_cast<short>((InData->accel_x[1] << 8) | InData->accel_x[0]) >> 4; short raw_accelY = static_cast<short>((InData->accel_y[1] << 8) | InData->accel_y[0]) >> 4; short raw_accelZ = static_cast<short>((InData->accel_z[1] << 8) | InData->accel_z[0]) >> 4; // Piece together the 16-bit gyroscope data short raw_gyroX = static_cast<short>((InData->gyro_x[1] << 8) | InData->gyro_x[0]); short raw_gyroY = static_cast<short>((InData->gyro_y[1] << 8) | InData->gyro_y[0]); short raw_gyroZ = static_cast<short>((InData->gyro_z[1] << 8) | InData->gyro_z[0]); // Save the raw accelerometer values newState.RawAccelerometer[0] = static_cast<int>(raw_accelX); newState.RawAccelerometer[1] = static_cast<int>(raw_accelY); newState.RawAccelerometer[2] = static_cast<int>(raw_accelZ); // Save the raw gyro values newState.RawGyro[0] = static_cast<int>(raw_gyroX); newState.RawGyro[1] = static_cast<int>(raw_gyroY); newState.RawGyro[2] = static_cast<int>(raw_gyroZ); // calibrated_acc= raw_acc*acc_gain + acc_bias newState.CalibratedAccelerometer.i = static_cast<float>(newState.RawAccelerometer[0]) * cfg.accelerometer_gain.i + cfg.accelerometer_bias.i; newState.CalibratedAccelerometer.j = static_cast<float>(newState.RawAccelerometer[1]) * cfg.accelerometer_gain.j + cfg.accelerometer_bias.j; newState.CalibratedAccelerometer.k = static_cast<float>(newState.RawAccelerometer[2]) * cfg.accelerometer_gain.k + cfg.accelerometer_bias.k; // calibrated_gyro= raw_gyro*gyro_gain + gyro_bias newState.CalibratedGyro.i = static_cast<float>(newState.RawGyro[0]) * cfg.gyro_gain; newState.CalibratedGyro.j = static_cast<float>(newState.RawGyro[1]) * cfg.gyro_gain; newState.CalibratedGyro.k = static_cast<float>(newState.RawGyro[2]) * cfg.gyro_gain; } // Sequence and timestamp newState.RawSequence = InData->buttons3.state.counter; newState.RawTimeStamp = InData->timestamp; // Convert the 0-10 battery level into the batter level switch (InData->batteryLevel) { case 0: newState.Battery = CommonControllerState::BatteryLevel::Batt_CHARGING; break; case 1: newState.Battery = CommonControllerState::BatteryLevel::Batt_MIN; break; case 2: case 3: newState.Battery = CommonControllerState::BatteryLevel::Batt_20Percent; break; case 4: case 5: newState.Battery = CommonControllerState::BatteryLevel::Batt_40Percent; break; case 6: case 7: newState.Battery = CommonControllerState::BatteryLevel::Batt_60Percent; break; case 8: case 9: newState.Battery = CommonControllerState::BatteryLevel::Batt_80Percent; break; case 10: default: newState.Battery = CommonControllerState::BatteryLevel::Batt_MAX; break; } // Make room for new entry if at the max queue size if (ControllerStates.size() >= PSDS4_STATE_BUFFER_MAX) { ControllerStates.erase(ControllerStates.begin(), ControllerStates.begin() + ControllerStates.size() - PSDS4_STATE_BUFFER_MAX); } ControllerStates.push_back(newState); } // Update recurrent writes on a regular interval { std::chrono::time_point<std::chrono::high_resolution_clock> now = std::chrono::high_resolution_clock::now(); // See if it's time to update the LED/rumble state std::chrono::duration<double, std::milli> led_update_diff = now - lastWriteStateTime; if (led_update_diff.count() >= PSDS4_WRITE_DATA_INTERVAL_MS) { writeDataOut(); lastWriteStateTime = now; } } } return result; }
bool PSDualShock4Controller::getIsReadyToPoll() const { return (getIsOpen() && getIsBluetooth()); }
IControllerInterface::ePollResult PSNaviController::poll() { IControllerInterface::ePollResult result= IControllerInterface::_PollResultFailure; if (!getIsBluetooth()) { // Don't bother polling when connected via usb result = IControllerInterface::_PollResultSuccessNoData; } else if (getIsOpen()) { static const int k_max_iterations= 32; for (int iteration= 0; iteration < k_max_iterations; ++iteration) { // Attempt to read the next update packet from the controller int res = hid_read(HIDDetails.Handle, (unsigned char*)InData, sizeof(PSNaviDataInput)); if (res == 0) { // Device still in valid state result= (iteration == 0) ? IControllerInterface::_PollResultSuccessNoData : IControllerInterface::_PollResultSuccessNewData; // No more data available. Stop iterating. break; } else if (res < 0) { char hidapi_err_mbs[256]; bool valid_error_mesg = hid_error_mbs(HIDDetails.Handle, hidapi_err_mbs, sizeof(hidapi_err_mbs)); // Device no longer in valid state. if (valid_error_mesg) { SERVER_LOG_ERROR("PSMoveController::readDataIn") << "HID ERROR: " << hidapi_err_mbs; } result= IControllerInterface::_PollResultFailure; // No more data available. Stop iterating. break; } else { // New data available. Keep iterating. result= IControllerInterface::_PollResultFailure; } // https://github.com/nitsch/moveonpc/wiki/Input-report PSNaviControllerState newState; // Increment the sequence for every new polling packet newState.PollSequenceNumber= NextPollSequenceNumber; ++NextPollSequenceNumber; // Buttons newState.AllButtons = (InData->buttons2) | // |-|L2|L1|-|-|Circle|-|Cross (InData->buttons1 << 8) | // |Left|Down|Right|Up|-|-|L3|- ((InData->buttons3 & 0x01) << 16); // |-|-|-|-|-|-|-|PS unsigned int lastButtons = ControllerStates.empty() ? 0 : ControllerStates.back().AllButtons; newState.Circle = getButtonState(newState.AllButtons, lastButtons, Btn_CIRCLE); newState.Cross = getButtonState(newState.AllButtons, lastButtons, Btn_CROSS); newState.PS = getButtonState(newState.AllButtons, lastButtons, Btn_PS); newState.Trigger = InData->analog_l2; newState.Stick_XAxis= InData->stick_xaxis; newState.Stick_YAxis= InData->stick_yaxis; // Other newState.Battery = static_cast<CommonControllerState::BatteryLevel>(InData->battery); // Make room for new entry if at the max queue size if (ControllerStates.size() >= PSNAVI_STATE_BUFFER_MAX) { ControllerStates.erase(ControllerStates.begin(), ControllerStates.begin()+ControllerStates.size()-PSNAVI_STATE_BUFFER_MAX); } ControllerStates.push_back(newState); } } return result; }
bool PSNaviController::getIsReadyToPoll() const { return (getIsOpen() && getIsBluetooth()); }