Beispiel #1
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);
}
Beispiel #2
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);
}
void RequireConnection(Interface* self) {
    u32* cmd_buff = Kernel::GetCommandBuffer();

    conn_status_event->Signal();

    cmd_buff[1] = RESULT_SUCCESS.raw;

    LOG_WARNING(Service_IR, "(STUBBED) called");
}
Beispiel #4
0
void NotifyToWait(Service::Interface* self) {
    u32* cmd_buff = Kernel::GetCommandBuffer();
    u32 app_id = cmd_buff[1];
    // TODO(Subv): Verify this, it seems to get SWKBD and Home Menu further.
    start_event->Signal();

    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
    LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id);
}
Beispiel #5
0
void DisableGyroscopeLow(Service::Interface* self) {
    u32* cmd_buff = Kernel::GetCommandBuffer();

    event_gyroscope->Signal();

    cmd_buff[1] = RESULT_SUCCESS.raw;

    LOG_WARNING(Service_HID, "(STUBBED) called");
}
Beispiel #6
0
void EnableAccelerometer(Service::Interface* self) {
    u32* cmd_buff = Kernel::GetCommandBuffer();

    event_accelerometer->Signal();

    cmd_buff[1] = RESULT_SUCCESS.raw;

    LOG_WARNING(Service_HID, "(STUBBED) called");
}
Beispiel #7
0
void SignalInterrupt() {
    // TODO(bunnei): This is just a stub, it does not do anything other than signal to the emulated
    // application that a DSP interrupt occurred, without specifying which one. Since we do not
    // emulate the DSP yet (and how it works is largely unknown), this is a work around to get games
    // that check the DSP interrupt signal event to run. We should figure out the different types of
    // DSP interrupts, and trigger them at the appropriate times.

    if (interrupt_event != 0)
        interrupt_event->Signal();
}
Beispiel #8
0
static void StartConversion(Service::Interface* self) {
    u32* cmd_buff = Kernel::GetCommandBuffer();

    // dst_image_size would seem to be perfect for this, but it doesn't include the gap :(
    u32 total_output_size = conversion.input_lines * (conversion.dst.transfer_unit + conversion.dst.gap);
    Memory::RasterizerFlushAndInvalidateRegion(Memory::VirtualToPhysicalAddress(conversion.dst.address), total_output_size);

    HW::Y2R::PerformConversion(conversion);

    completion_event->Signal();

    cmd_buff[0] = IPC::MakeHeader(0x26, 1, 0);
    cmd_buff[1] = RESULT_SUCCESS.raw;

    LOG_DEBUG(Service_Y2R, "called");
}
Beispiel #9
0
static void StartConversion(Service::Interface* self) {
    u32* cmd_buff = Kernel::GetCommandBuffer();

    HW::Y2R::PerformConversion(conversion);

    // dst_image_size would seem to be perfect for this, but it doesn't include the gap :(
    u32 total_output_size = conversion.input_lines *
        (conversion.dst.transfer_unit + conversion.dst.gap);
    VideoCore::g_renderer->hw_rasterizer->NotifyFlush(
        Memory::VirtualToPhysicalAddress(conversion.dst.address), total_output_size);

    LOG_DEBUG(Service_Y2R, "called");
    completion_event->Signal();

    cmd_buff[1] = RESULT_SUCCESS.raw;
}
Beispiel #10
0
void Initialize(Service::Interface* self) {
    u32* cmd_buff = Kernel::GetCommandBuffer();

    // TODO(bunnei): Check if these are created in Initialize or on APT process startup.
    notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification");
    pause_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Pause");

    cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom();
    cmd_buff[4] = Kernel::g_handle_table.Create(pause_event).MoveFrom();

    // TODO(bunnei): Check if these events are cleared/signaled every time Initialize is called.
    notification_event->Clear();
    pause_event->Signal(); // Fire start event

    ASSERT_MSG((nullptr != lock), "Cannot initialize without lock");
    lock->Release();

    cmd_buff[1] = RESULT_SUCCESS.raw; // No error
}
Beispiel #11
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);
}
Beispiel #12
0
void Update() {
    SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());
    const PadState state = VideoCore::g_emu_window->GetPadState();

    if (mem == nullptr) {
        LOG_DEBUG(Service_HID, "Cannot update HID prior to mapping shared memory!");
        return;
    }

    mem->pad.current_state.hex = state.hex;
    mem->pad.index = next_pad_index;
    next_touch_index = (next_touch_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;;

    // Set circle Pad
    pad_entry->circle_pad_x = state.circle_left  ? -MAX_CIRCLEPAD_POS :
                              state.circle_right ?  MAX_CIRCLEPAD_POS : 0x0;
    pad_entry->circle_pad_y = state.circle_down  ? -MAX_CIRCLEPAD_POS :
                              state.circle_up    ?  MAX_CIRCLEPAD_POS : 0x0;

    // 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;

    std::tie(touch_entry->x, touch_entry->y, pressed) = VideoCore::g_emu_window->GetTouchState();
    touch_entry->valid = 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();
}
Beispiel #13
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);
}