Example #1
0
static void UpdateCallback(u64 userdata, int cycles_late) {
    SharedMem* mem = reinterpret_cast<SharedMem*>(shared_memory->GetPointer());

    if (is_device_reload_pending.exchange(false))
        LoadInputDevices();

    PadState state;
    state.zl.Assign(zl_button->GetStatus());
    state.zr.Assign(zr_button->GetStatus());

    // Get current c-stick position and update c-stick direction
    float c_stick_x_f, c_stick_y_f;
    std::tie(c_stick_x_f, c_stick_y_f) = c_stick->GetStatus();
    constexpr int MAX_CSTICK_RADIUS = 0x9C; // Max value for a c-stick radius
    const s16 c_stick_x = static_cast<s16>(c_stick_x_f * MAX_CSTICK_RADIUS);
    const s16 c_stick_y = static_cast<s16>(c_stick_y_f * MAX_CSTICK_RADIUS);

    if (!raw_c_stick) {
        const HID::DirectionState direction = HID::GetStickDirectionState(c_stick_x, c_stick_y);
        state.c_stick_up.Assign(direction.up);
        state.c_stick_down.Assign(direction.down);
        state.c_stick_left.Assign(direction.left);
        state.c_stick_right.Assign(direction.right);
    }

    // TODO (wwylele): implement raw C-stick data for raw_c_stick = true

    const u32 last_entry_index = mem->index;
    mem->index = next_pad_index;
    next_pad_index = (next_pad_index + 1) % mem->entries.size();

    // Get the previous Pad state
    PadState old_state{mem->entries[last_entry_index].current_state};

    // Compute bitmask with 1s for bits different from the old state
    PadState changed = {state.hex ^ old_state.hex};

    // Get the current Pad entry
    PadDataEntry& pad_entry = mem->entries[mem->index];

    // Update entry properties
    pad_entry.current_state.hex = state.hex;
    pad_entry.delta_additions.hex = changed.hex & state.hex;
    pad_entry.delta_removals.hex = changed.hex & old_state.hex;
    pad_entry.c_stick_x = c_stick_x;
    pad_entry.c_stick_y = c_stick_y;

    // If we just updated index 0, provide a new timestamp
    if (mem->index == 0) {
        mem->index_reset_ticks_previous = mem->index_reset_ticks;
        mem->index_reset_ticks = CoreTiming::GetTicks();
    }

    update_event->Signal();

    // Reschedule recurrent event
    CoreTiming::ScheduleEvent(msToCycles(update_period) - cycles_late, update_callback_id);
}
Example #2
0
static void UpdateGyroscopeCallback(u64 userdata, int cycles_late) {
    SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());

    mem->gyroscope.index = next_gyroscope_index;
    next_gyroscope_index = (next_gyroscope_index + 1) % mem->gyroscope.entries.size();

    GyroscopeDataEntry& gyroscope_entry = mem->gyroscope.entries[mem->gyroscope.index];

    Math::Vec3<float> gyro;
    std::tie(std::ignore, gyro) = motion_device->GetStatus();
    double stretch = Core::System::GetInstance().perf_stats.GetLastFrameTimeScale();
    gyro *= gyroscope_coef * static_cast<float>(stretch);
    gyroscope_entry.x = static_cast<s16>(gyro.x);
    gyroscope_entry.y = static_cast<s16>(gyro.y);
    gyroscope_entry.z = static_cast<s16>(gyro.z);

    // Make up "raw" entry
    mem->gyroscope.raw_entry.x = gyroscope_entry.x;
    mem->gyroscope.raw_entry.z = -gyroscope_entry.y;
    mem->gyroscope.raw_entry.y = gyroscope_entry.z;

    // If we just updated index 0, provide a new timestamp
    if (mem->gyroscope.index == 0) {
        mem->gyroscope.index_reset_ticks_previous = mem->gyroscope.index_reset_ticks;
        mem->gyroscope.index_reset_ticks = (s64)CoreTiming::GetTicks();
    }

    event_gyroscope->Signal();

    // Reschedule recurrent event
    CoreTiming::ScheduleEvent(gyroscope_update_ticks - cycles_late, gyroscope_update_event);
}
Example #3
0
static void UpdateAccelerometerCallback(u64 userdata, int cycles_late) {
    SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());

    mem->accelerometer.index = next_accelerometer_index;
    next_accelerometer_index = (next_accelerometer_index + 1) % mem->accelerometer.entries.size();

    Math::Vec3<float> accel;
    std::tie(accel, std::ignore) = motion_device->GetStatus();
    accel *= accelerometer_coef;
    // TODO(wwylele): do a time stretch like the one in UpdateGyroscopeCallback
    // The time stretch formula should be like
    // stretched_vector = (raw_vector - gravity) * stretch_ratio + gravity

    AccelerometerDataEntry& accelerometer_entry =
        mem->accelerometer.entries[mem->accelerometer.index];

    accelerometer_entry.x = static_cast<s16>(accel.x);
    accelerometer_entry.y = static_cast<s16>(accel.y);
    accelerometer_entry.z = static_cast<s16>(accel.z);

    // Make up "raw" entry
    // TODO(wwylele):
    // From hardware testing, the raw_entry values are approximately, but not exactly, as twice as
    // corresponding entries (or with a minus sign). It may caused by system calibration to the
    // accelerometer. Figure out how it works, or, if no game reads raw_entry, the following three
    // lines can be removed and leave raw_entry unimplemented.
    mem->accelerometer.raw_entry.x = -2 * accelerometer_entry.x;
    mem->accelerometer.raw_entry.z = 2 * accelerometer_entry.y;
    mem->accelerometer.raw_entry.y = -2 * accelerometer_entry.z;

    // If we just updated index 0, provide a new timestamp
    if (mem->accelerometer.index == 0) {
        mem->accelerometer.index_reset_ticks_previous = mem->accelerometer.index_reset_ticks;
        mem->accelerometer.index_reset_ticks = (s64)CoreTiming::GetTicks();
    }

    event_accelerometer->Signal();

    // Reschedule recurrent event
    CoreTiming::ScheduleEvent(accelerometer_update_ticks - cycles_late, accelerometer_update_event);
}
Example #4
0
static void UpdatePadCallback(u64 userdata, int cycles_late) {
    SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());

    if (is_device_reload_pending.exchange(false))
        LoadInputDevices();

    PadState state;
    using namespace Settings::NativeButton;
    state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
    state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
    state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
    state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
    state.right.Assign(buttons[Right - BUTTON_HID_BEGIN]->GetStatus());
    state.left.Assign(buttons[Left - BUTTON_HID_BEGIN]->GetStatus());
    state.up.Assign(buttons[Up - BUTTON_HID_BEGIN]->GetStatus());
    state.down.Assign(buttons[Down - BUTTON_HID_BEGIN]->GetStatus());
    state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
    state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
    state.start.Assign(buttons[Start - BUTTON_HID_BEGIN]->GetStatus());
    state.select.Assign(buttons[Select - BUTTON_HID_BEGIN]->GetStatus());

    // Get current circle pad position and update circle pad direction
    float circle_pad_x_f, circle_pad_y_f;
    std::tie(circle_pad_x_f, circle_pad_y_f) = circle_pad->GetStatus();
    constexpr int MAX_CIRCLEPAD_POS = 0x9C; // Max value for a circle pad position
    s16 circle_pad_x = static_cast<s16>(circle_pad_x_f * MAX_CIRCLEPAD_POS);
    s16 circle_pad_y = static_cast<s16>(circle_pad_y_f * MAX_CIRCLEPAD_POS);
    const DirectionState direction = GetStickDirectionState(circle_pad_x, circle_pad_y);
    state.circle_up.Assign(direction.up);
    state.circle_down.Assign(direction.down);
    state.circle_left.Assign(direction.left);
    state.circle_right.Assign(direction.right);

    mem->pad.current_state.hex = state.hex;
    mem->pad.index = next_pad_index;
    next_pad_index = (next_pad_index + 1) % mem->pad.entries.size();

    // Get the previous Pad state
    u32 last_entry_index = (mem->pad.index - 1) % mem->pad.entries.size();
    PadState old_state = mem->pad.entries[last_entry_index].current_state;

    // Compute bitmask with 1s for bits different from the old state
    PadState changed = {{(state.hex ^ old_state.hex)}};

    // Get the current Pad entry
    PadDataEntry& pad_entry = mem->pad.entries[mem->pad.index];

    // Update entry properties
    pad_entry.current_state.hex = state.hex;
    pad_entry.delta_additions.hex = changed.hex & state.hex;
    pad_entry.delta_removals.hex = changed.hex & old_state.hex;
    pad_entry.circle_pad_x = circle_pad_x;
    pad_entry.circle_pad_y = circle_pad_y;

    // If we just updated index 0, provide a new timestamp
    if (mem->pad.index == 0) {
        mem->pad.index_reset_ticks_previous = mem->pad.index_reset_ticks;
        mem->pad.index_reset_ticks = (s64)CoreTiming::GetTicks();
    }

    mem->touch.index = next_touch_index;
    next_touch_index = (next_touch_index + 1) % mem->touch.entries.size();

    // Get the current touch entry
    TouchDataEntry& touch_entry = mem->touch.entries[mem->touch.index];
    bool pressed = false;
    float x, y;
    std::tie(x, y, pressed) = touch_device->GetStatus();
    touch_entry.x = static_cast<u16>(x * Core::kScreenBottomWidth);
    touch_entry.y = static_cast<u16>(y * Core::kScreenBottomHeight);
    touch_entry.valid.Assign(pressed ? 1 : 0);

    // TODO(bunnei): We're not doing anything with offset 0xA8 + 0x18 of HID SharedMemory, which
    // supposedly is "Touch-screen entry, which contains the raw coordinate data prior to being
    // converted to pixel coordinates." (http://3dbrew.org/wiki/HID_Shared_Memory#Offset_0xA8).

    // If we just updated index 0, provide a new timestamp
    if (mem->touch.index == 0) {
        mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks;
        mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks();
    }

    // Signal both handles when there's an update to Pad or touch
    event_pad_or_touch_1->Signal();
    event_pad_or_touch_2->Signal();

    // Reschedule recurrent event
    CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
}