|
|
@ -35,6 +35,15 @@ static u32 next_gyroscope_index; |
|
|
static int enable_accelerometer_count = 0; // positive means enabled
|
|
|
static int enable_accelerometer_count = 0; // positive means enabled
|
|
|
static int enable_gyroscope_count = 0; // positive means enabled
|
|
|
static int enable_gyroscope_count = 0; // positive means enabled
|
|
|
|
|
|
|
|
|
|
|
|
static int pad_update_event; |
|
|
|
|
|
static int accelerometer_update_event; |
|
|
|
|
|
static int gyroscope_update_event; |
|
|
|
|
|
|
|
|
|
|
|
// Updating period for each HID device. These empirical values are measured from a 11.2 3DS.
|
|
|
|
|
|
constexpr u64 pad_update_ticks = BASE_CLOCK_RATE_ARM11 / 234; |
|
|
|
|
|
constexpr u64 accelerometer_update_ticks = BASE_CLOCK_RATE_ARM11 / 104; |
|
|
|
|
|
constexpr u64 gyroscope_update_ticks = BASE_CLOCK_RATE_ARM11 / 101; |
|
|
|
|
|
|
|
|
static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) { |
|
|
static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) { |
|
|
// 30 degree and 60 degree are angular thresholds for directions
|
|
|
// 30 degree and 60 degree are angular thresholds for directions
|
|
|
constexpr float TAN30 = 0.577350269f; |
|
|
constexpr float TAN30 = 0.577350269f; |
|
|
@ -65,14 +74,9 @@ static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) { |
|
|
return state; |
|
|
return state; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void Update() { |
|
|
|
|
|
|
|
|
static void UpdatePadCallback(u64 userdata, int cycles_late) { |
|
|
SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer()); |
|
|
SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer()); |
|
|
|
|
|
|
|
|
if (mem == nullptr) { |
|
|
|
|
|
LOG_DEBUG(Service_HID, "Cannot update HID prior to mapping shared memory!"); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
PadState state = VideoCore::g_emu_window->GetPadState(); |
|
|
PadState state = VideoCore::g_emu_window->GetPadState(); |
|
|
|
|
|
|
|
|
// Get current circle pad position and update circle pad direction
|
|
|
// Get current circle pad position and update circle pad direction
|
|
|
@ -131,11 +135,15 @@ void Update() { |
|
|
event_pad_or_touch_1->Signal(); |
|
|
event_pad_or_touch_1->Signal(); |
|
|
event_pad_or_touch_2->Signal(); |
|
|
event_pad_or_touch_2->Signal(); |
|
|
|
|
|
|
|
|
// Update accelerometer
|
|
|
|
|
|
if (enable_accelerometer_count > 0) { |
|
|
|
|
|
|
|
|
// Reschedule recurrent event
|
|
|
|
|
|
CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void UpdateAccelerometerCallback(u64 userdata, int cycles_late) { |
|
|
|
|
|
SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer()); |
|
|
|
|
|
|
|
|
mem->accelerometer.index = next_accelerometer_index; |
|
|
mem->accelerometer.index = next_accelerometer_index; |
|
|
next_accelerometer_index = |
|
|
|
|
|
(next_accelerometer_index + 1) % mem->accelerometer.entries.size(); |
|
|
|
|
|
|
|
|
next_accelerometer_index = (next_accelerometer_index + 1) % mem->accelerometer.entries.size(); |
|
|
|
|
|
|
|
|
AccelerometerDataEntry& accelerometer_entry = |
|
|
AccelerometerDataEntry& accelerometer_entry = |
|
|
mem->accelerometer.entries[mem->accelerometer.index]; |
|
|
mem->accelerometer.entries[mem->accelerometer.index]; |
|
|
@ -144,11 +152,10 @@ void Update() { |
|
|
|
|
|
|
|
|
// Make up "raw" entry
|
|
|
// Make up "raw" entry
|
|
|
// TODO(wwylele):
|
|
|
// 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.
|
|
|
|
|
|
|
|
|
// 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.x = -2 * accelerometer_entry.x; |
|
|
mem->accelerometer.raw_entry.z = 2 * accelerometer_entry.y; |
|
|
mem->accelerometer.raw_entry.z = 2 * accelerometer_entry.y; |
|
|
mem->accelerometer.raw_entry.y = -2 * accelerometer_entry.z; |
|
|
mem->accelerometer.raw_entry.y = -2 * accelerometer_entry.z; |
|
|
@ -160,10 +167,14 @@ void Update() { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
event_accelerometer->Signal(); |
|
|
event_accelerometer->Signal(); |
|
|
|
|
|
|
|
|
|
|
|
// Reschedule recurrent event
|
|
|
|
|
|
CoreTiming::ScheduleEvent(accelerometer_update_ticks - cycles_late, accelerometer_update_event); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Update gyroscope
|
|
|
|
|
|
if (enable_gyroscope_count > 0) { |
|
|
|
|
|
|
|
|
static void UpdateGyroscopeCallback(u64 userdata, int cycles_late) { |
|
|
|
|
|
SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer()); |
|
|
|
|
|
|
|
|
mem->gyroscope.index = next_gyroscope_index; |
|
|
mem->gyroscope.index = next_gyroscope_index; |
|
|
next_gyroscope_index = (next_gyroscope_index + 1) % mem->gyroscope.entries.size(); |
|
|
next_gyroscope_index = (next_gyroscope_index + 1) % mem->gyroscope.entries.size(); |
|
|
|
|
|
|
|
|
@ -183,7 +194,9 @@ void Update() { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
event_gyroscope->Signal(); |
|
|
event_gyroscope->Signal(); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Reschedule recurrent event
|
|
|
|
|
|
CoreTiming::ScheduleEvent(gyroscope_update_ticks - cycles_late, gyroscope_update_event); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void GetIPCHandles(Service::Interface* self) { |
|
|
void GetIPCHandles(Service::Interface* self) { |
|
|
@ -204,7 +217,11 @@ void EnableAccelerometer(Service::Interface* self) { |
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
|
++enable_accelerometer_count; |
|
|
++enable_accelerometer_count; |
|
|
event_accelerometer->Signal(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Schedules the accelerometer update event if the accelerometer was just enabled
|
|
|
|
|
|
if (enable_accelerometer_count == 1) { |
|
|
|
|
|
CoreTiming::ScheduleEvent(accelerometer_update_ticks, accelerometer_update_event); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
|
|
|
|
|
@ -215,7 +232,11 @@ void DisableAccelerometer(Service::Interface* self) { |
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
|
--enable_accelerometer_count; |
|
|
--enable_accelerometer_count; |
|
|
event_accelerometer->Signal(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Unschedules the accelerometer update event if the accelerometer was just disabled
|
|
|
|
|
|
if (enable_accelerometer_count == 0) { |
|
|
|
|
|
CoreTiming::UnscheduleEvent(accelerometer_update_event, 0); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
|
|
|
|
|
@ -226,7 +247,11 @@ void EnableGyroscopeLow(Service::Interface* self) { |
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
|
++enable_gyroscope_count; |
|
|
++enable_gyroscope_count; |
|
|
event_gyroscope->Signal(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Schedules the gyroscope update event if the gyroscope was just enabled
|
|
|
|
|
|
if (enable_gyroscope_count == 1) { |
|
|
|
|
|
CoreTiming::ScheduleEvent(gyroscope_update_ticks, gyroscope_update_event); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
|
|
|
|
|
@ -237,7 +262,11 @@ void DisableGyroscopeLow(Service::Interface* self) { |
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
|
|
|
|
|
|
--enable_gyroscope_count; |
|
|
--enable_gyroscope_count; |
|
|
event_gyroscope->Signal(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Unschedules the gyroscope update event if the gyroscope was just disabled
|
|
|
|
|
|
if (enable_gyroscope_count == 0) { |
|
|
|
|
|
CoreTiming::UnscheduleEvent(gyroscope_update_event, 0); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
cmd_buff[1] = RESULT_SUCCESS.raw; |
|
|
|
|
|
|
|
|
@ -298,6 +327,15 @@ void Init() { |
|
|
event_accelerometer = Event::Create(ResetType::OneShot, "HID:EventAccelerometer"); |
|
|
event_accelerometer = Event::Create(ResetType::OneShot, "HID:EventAccelerometer"); |
|
|
event_gyroscope = Event::Create(ResetType::OneShot, "HID:EventGyroscope"); |
|
|
event_gyroscope = Event::Create(ResetType::OneShot, "HID:EventGyroscope"); |
|
|
event_debug_pad = Event::Create(ResetType::OneShot, "HID:EventDebugPad"); |
|
|
event_debug_pad = Event::Create(ResetType::OneShot, "HID:EventDebugPad"); |
|
|
|
|
|
|
|
|
|
|
|
// Register update callbacks
|
|
|
|
|
|
pad_update_event = CoreTiming::RegisterEvent("HID::UpdatePadCallback", UpdatePadCallback); |
|
|
|
|
|
accelerometer_update_event = |
|
|
|
|
|
CoreTiming::RegisterEvent("HID::UpdateAccelerometerCallback", UpdateAccelerometerCallback); |
|
|
|
|
|
gyroscope_update_event = |
|
|
|
|
|
CoreTiming::RegisterEvent("HID::UpdateGyroscopeCallback", UpdateGyroscopeCallback); |
|
|
|
|
|
|
|
|
|
|
|
CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void Shutdown() { |
|
|
void Shutdown() { |
|
|
|