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); }
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"); }
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); }
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"); }
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"); }
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(); }
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"); }
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; }
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 }
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); }
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(); }
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); }