early-access version 2859
This commit is contained in:
@@ -536,6 +536,8 @@ void SoftwareKeyboard::InitializeFrontendNormalKeyboard() {
|
||||
.sub_text{std::move(sub_text)},
|
||||
.guide_text{std::move(guide_text)},
|
||||
.initial_text{initial_text},
|
||||
.left_optional_symbol_key{swkbd_config_common.left_optional_symbol_key},
|
||||
.right_optional_symbol_key{swkbd_config_common.right_optional_symbol_key},
|
||||
.max_text_length{max_text_length},
|
||||
.min_text_length{min_text_length},
|
||||
.initial_cursor_position{initial_cursor_position},
|
||||
@@ -591,6 +593,8 @@ void SoftwareKeyboard::InitializeFrontendInlineKeyboardOld() {
|
||||
.sub_text{},
|
||||
.guide_text{},
|
||||
.initial_text{current_text},
|
||||
.left_optional_symbol_key{appear_arg.left_optional_symbol_key},
|
||||
.right_optional_symbol_key{appear_arg.right_optional_symbol_key},
|
||||
.max_text_length{max_text_length},
|
||||
.min_text_length{min_text_length},
|
||||
.initial_cursor_position{initial_cursor_position},
|
||||
@@ -632,6 +636,8 @@ void SoftwareKeyboard::InitializeFrontendInlineKeyboardNew() {
|
||||
.sub_text{},
|
||||
.guide_text{},
|
||||
.initial_text{current_text},
|
||||
.left_optional_symbol_key{appear_arg.left_optional_symbol_key},
|
||||
.right_optional_symbol_key{appear_arg.right_optional_symbol_key},
|
||||
.max_text_length{max_text_length},
|
||||
.min_text_length{min_text_length},
|
||||
.initial_cursor_position{initial_cursor_position},
|
||||
|
@@ -19,3 +19,10 @@ constexpr Result InvalidNpadId{ErrorModule::HID, 709};
|
||||
constexpr Result NpadNotConnected{ErrorModule::HID, 710};
|
||||
|
||||
} // namespace Service::HID
|
||||
|
||||
namespace Service::IRS {
|
||||
|
||||
constexpr Result InvalidProcessorState{ErrorModule::Irsensor, 78};
|
||||
constexpr Result InvalidIrCameraHandle{ErrorModule::Irsensor, 204};
|
||||
|
||||
} // namespace Service::IRS
|
||||
|
@@ -2345,8 +2345,8 @@ void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system
|
||||
std::make_shared<HidSys>(system)->InstallAsService(service_manager);
|
||||
std::make_shared<HidTmp>(system)->InstallAsService(service_manager);
|
||||
|
||||
std::make_shared<IRS>(system)->InstallAsService(service_manager);
|
||||
std::make_shared<IRS_SYS>(system)->InstallAsService(service_manager);
|
||||
std::make_shared<Service::IRS::IRS>(system)->InstallAsService(service_manager);
|
||||
std::make_shared<Service::IRS::IRS_SYS>(system)->InstallAsService(service_manager);
|
||||
|
||||
std::make_shared<XCD_SYS>(system)->InstallAsService(service_manager);
|
||||
}
|
||||
|
@@ -1,16 +1,28 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
#include "core/hle/service/hid/irs.h"
|
||||
#include "core/hle/service/hid/irsensor/clustering_processor.h"
|
||||
#include "core/hle/service/hid/irsensor/image_transfer_processor.h"
|
||||
#include "core/hle/service/hid/irsensor/ir_led_processor.h"
|
||||
#include "core/hle/service/hid/irsensor/moment_processor.h"
|
||||
#include "core/hle/service/hid/irsensor/pointing_processor.h"
|
||||
#include "core/hle/service/hid/irsensor/tera_plugin_processor.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Service::HID {
|
||||
namespace Service::IRS {
|
||||
|
||||
IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} {
|
||||
// clang-format off
|
||||
@@ -36,14 +48,19 @@ IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} {
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
u8* raw_shared_memory = system.Kernel().GetIrsSharedMem().GetPointer();
|
||||
RegisterHandlers(functions);
|
||||
shared_memory = std::construct_at(reinterpret_cast<StatusManager*>(raw_shared_memory));
|
||||
|
||||
npad_device = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||
}
|
||||
IRS::~IRS() = default;
|
||||
|
||||
void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}",
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -54,7 +71,7 @@ void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}",
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -75,7 +92,7 @@ void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
|
||||
void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
@@ -88,17 +105,23 @@ void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
if (result.IsSuccess()) {
|
||||
// TODO: Stop Image processor
|
||||
result = ResultSuccess;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
PackedMomentProcessorConfig processor_config;
|
||||
Core::IrSensor::PackedMomentProcessorConfig processor_config;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size.");
|
||||
|
||||
@@ -109,19 +132,28 @@ void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) {
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
const auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
||||
MakeProcessor<MomentProcessor>(parameters.camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<MomentProcessor>(parameters.camera_handle);
|
||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
PackedClusteringProcessorConfig processor_config;
|
||||
Core::IrSensor::PackedClusteringProcessorConfig processor_config;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x40, "Parameters has incorrect size.");
|
||||
static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
@@ -130,17 +162,27 @@ void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) {
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
||||
MakeProcessorWithCoreContext<ClusteringProcessor>(parameters.camera_handle, device);
|
||||
auto& image_transfer_processor =
|
||||
GetProcessor<ClusteringProcessor>(parameters.camera_handle);
|
||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
PackedImageTransferProcessorConfig processor_config;
|
||||
Core::IrSensor::PackedImageTransferProcessorConfig processor_config;
|
||||
u32 transfer_memory_size;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size.");
|
||||
@@ -151,20 +193,42 @@ void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
|
||||
auto t_mem =
|
||||
system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle);
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, transfer_memory_size={}, "
|
||||
"applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.transfer_memory_size, parameters.applet_resource_user_id);
|
||||
if (t_mem.IsNull()) {
|
||||
LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT_MSG(t_mem->GetSize() == parameters.transfer_memory_size, "t_mem has incorrect size");
|
||||
|
||||
u8* transfer_memory = system.Memory().GetPointer(t_mem->GetSourceAddress());
|
||||
|
||||
LOG_INFO(Service_IRS,
|
||||
"called, npad_type={}, npad_id={}, transfer_memory_size={}, transfer_memory_size={}, "
|
||||
"applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.transfer_memory_size, t_mem->GetSize(), parameters.applet_resource_user_id);
|
||||
|
||||
const auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
||||
MakeProcessorWithCoreContext<ImageTransferProcessor>(parameters.camera_handle, device);
|
||||
auto& image_transfer_processor =
|
||||
GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
|
||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
||||
image_transfer_processor.SetTransferMemoryPointer(transfer_memory);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
@@ -172,32 +236,68 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
LOG_DEBUG(Service_IRS, "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
const auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
if (result.IsError()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
||||
|
||||
if (device.mode != Core::IrSensor::IrSensorMode::ImageTransferProcessor) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(InvalidProcessorState);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<u8> data{};
|
||||
const auto& image_transfer_processor =
|
||||
GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
|
||||
const auto& state = image_transfer_processor.GetState(data);
|
||||
|
||||
ctx.WriteBuffer(data);
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw<u64>(system.CoreTiming().GetCPUTicks());
|
||||
rb.PushRaw<u32>(0);
|
||||
rb.PushRaw(state);
|
||||
}
|
||||
|
||||
void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto camera_handle{rp.PopRaw<IrCameraHandle>()};
|
||||
const auto processor_config{rp.PopRaw<PackedTeraPluginProcessorConfig>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
struct Parameters {
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
Core::IrSensor::PackedTeraPluginProcessorConfig processor_config;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, "
|
||||
"applet_resource_user_id={}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, processor_config.mode,
|
||||
processor_config.required_mcu_version.major,
|
||||
processor_config.required_mcu_version.minor, applet_resource_user_id);
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(
|
||||
Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, "
|
||||
"applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.processor_config.mode, parameters.processor_config.required_mcu_version.major,
|
||||
parameters.processor_config.required_mcu_version.minor, parameters.applet_resource_user_id);
|
||||
|
||||
const auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
||||
MakeProcessor<TeraPluginProcessor>(parameters.camera_handle, device);
|
||||
auto& image_transfer_processor =
|
||||
GetProcessor<TeraPluginProcessor>(parameters.camera_handle);
|
||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
|
||||
@@ -207,17 +307,17 @@ void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
|
||||
if (npad_id > Core::HID::NpadIdType::Player8 && npad_id != Core::HID::NpadIdType::Invalid &&
|
||||
npad_id != Core::HID::NpadIdType::Handheld) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(InvalidNpadId);
|
||||
rb.Push(Service::HID::InvalidNpadId);
|
||||
return;
|
||||
}
|
||||
|
||||
IrCameraHandle camera_handle{
|
||||
Core::IrSensor::IrCameraHandle camera_handle{
|
||||
.npad_id = static_cast<u8>(NpadIdTypeToIndex(npad_id)),
|
||||
.npad_type = Core::HID::NpadStyleIndex::None,
|
||||
};
|
||||
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called, npad_id={}, camera_npad_id={}, camera_npad_type={}",
|
||||
npad_id, camera_handle.npad_id, camera_handle.npad_type);
|
||||
LOG_INFO(Service_IRS, "called, npad_id={}, camera_npad_id={}, camera_npad_type={}", npad_id,
|
||||
camera_handle.npad_id, camera_handle.npad_type);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
@@ -226,8 +326,8 @@ void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto camera_handle{rp.PopRaw<IrCameraHandle>()};
|
||||
const auto processor_config{rp.PopRaw<PackedPointingProcessorConfig>()};
|
||||
const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
|
||||
const auto processor_config{rp.PopRaw<Core::IrSensor::PackedPointingProcessorConfig>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(
|
||||
@@ -236,14 +336,23 @@ void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) {
|
||||
camera_handle.npad_type, camera_handle.npad_id, processor_config.required_mcu_version.major,
|
||||
processor_config.required_mcu_version.minor, applet_resource_user_id);
|
||||
|
||||
auto result = IsIrCameraHandleValid(camera_handle);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessor<PointingProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<PointingProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
@@ -256,14 +365,20 @@ void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) {
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
if (result.IsSuccess()) {
|
||||
// TODO: Suspend image processor
|
||||
result = ResultSuccess;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto camera_handle{rp.PopRaw<IrCameraHandle>()};
|
||||
const auto mcu_version{rp.PopRaw<PackedMcuVersion>()};
|
||||
const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
|
||||
const auto mcu_version{rp.PopRaw<Core::IrSensor::PackedMcuVersion>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(
|
||||
@@ -272,37 +387,45 @@ void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) {
|
||||
camera_handle.npad_type, camera_handle.npad_id, applet_resource_user_id, mcu_version.major,
|
||||
mcu_version.minor);
|
||||
|
||||
auto result = IsIrCameraHandleValid(camera_handle);
|
||||
if (result.IsSuccess()) {
|
||||
// TODO: Check firmware version
|
||||
result = ResultSuccess;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
PackedFunctionLevel function_level;
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
|
||||
const auto function_level{rp.PopRaw<Core::IrSensor::PackedFunctionLevel>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
LOG_WARNING(
|
||||
Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, function_level={}, applet_resource_user_id={}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, function_level.function_level,
|
||||
applet_resource_user_id);
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
auto result = IsIrCameraHandleValid(camera_handle);
|
||||
if (result.IsSuccess()) {
|
||||
// TODO: Set Function level
|
||||
result = ResultSuccess;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
PackedImageTransferProcessorExConfig processor_config;
|
||||
Core::IrSensor::PackedImageTransferProcessorExConfig processor_config;
|
||||
u64 transfer_memory_size;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size.");
|
||||
@@ -313,20 +436,33 @@ void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) {
|
||||
auto t_mem =
|
||||
system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle);
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, transfer_memory_size={}, "
|
||||
"applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.transfer_memory_size, parameters.applet_resource_user_id);
|
||||
u8* transfer_memory = system.Memory().GetPointer(t_mem->GetSourceAddress());
|
||||
|
||||
LOG_INFO(Service_IRS,
|
||||
"called, npad_type={}, npad_id={}, transfer_memory_size={}, "
|
||||
"applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.transfer_memory_size, parameters.applet_resource_user_id);
|
||||
|
||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
||||
MakeProcessorWithCoreContext<ImageTransferProcessor>(parameters.camera_handle, device);
|
||||
auto& image_transfer_processor =
|
||||
GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
|
||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
||||
image_transfer_processor.SetTransferMemoryPointer(transfer_memory);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto camera_handle{rp.PopRaw<IrCameraHandle>()};
|
||||
const auto processor_config{rp.PopRaw<PackedIrLedProcessorConfig>()};
|
||||
const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
|
||||
const auto processor_config{rp.PopRaw<Core::IrSensor::PackedIrLedProcessorConfig>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
@@ -336,14 +472,23 @@ void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) {
|
||||
processor_config.required_mcu_version.major,
|
||||
processor_config.required_mcu_version.minor, applet_resource_user_id);
|
||||
|
||||
auto result = IsIrCameraHandleValid(camera_handle);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessor<IrLedProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<IrLedProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
@@ -356,14 +501,20 @@ void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) {
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
if (result.IsSuccess()) {
|
||||
// TODO: Stop image processor async
|
||||
result = ResultSuccess;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(result);
|
||||
}
|
||||
|
||||
void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
PackedFunctionLevel function_level;
|
||||
Core::IrSensor::PackedFunctionLevel function_level;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
@@ -378,7 +529,22 @@ void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
IRS::~IRS() = default;
|
||||
Result IRS::IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const {
|
||||
if (camera_handle.npad_id >
|
||||
static_cast<u8>(NpadIdTypeToIndex(Core::HID::NpadIdType::Handheld))) {
|
||||
return InvalidIrCameraHandle;
|
||||
}
|
||||
if (camera_handle.npad_type != Core::HID::NpadStyleIndex::None) {
|
||||
return InvalidIrCameraHandle;
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Core::IrSensor::DeviceFormat& IRS::GetIrCameraSharedMemoryDeviceEntry(
|
||||
const Core::IrSensor::IrCameraHandle& camera_handle) {
|
||||
ASSERT_MSG(sizeof(StatusManager::device) > camera_handle.npad_id, "invalid npad_id");
|
||||
return shared_memory->device[camera_handle.npad_id];
|
||||
}
|
||||
|
||||
IRS_SYS::IRS_SYS(Core::System& system_) : ServiceFramework{system_, "irs:sys"} {
|
||||
// clang-format off
|
||||
@@ -395,4 +561,4 @@ IRS_SYS::IRS_SYS(Core::System& system_) : ServiceFramework{system_, "irs:sys"} {
|
||||
|
||||
IRS_SYS::~IRS_SYS() = default;
|
||||
|
||||
} // namespace Service::HID
|
||||
} // namespace Service::IRS
|
||||
|
@@ -4,13 +4,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hid/irs_types.h"
|
||||
#include "core/hle/service/hid/irsensor/processor_base.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::HID {
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::IRS {
|
||||
|
||||
class IRS final : public ServiceFramework<IRS> {
|
||||
public:
|
||||
@@ -18,234 +24,19 @@ public:
|
||||
~IRS() override;
|
||||
|
||||
private:
|
||||
// This is nn::irsensor::IrCameraStatus
|
||||
enum IrCameraStatus : u32 {
|
||||
Available,
|
||||
Unsupported,
|
||||
Unconnected,
|
||||
// This is nn::irsensor::detail::AruidFormat
|
||||
struct AruidFormat {
|
||||
u64 sensor_aruid;
|
||||
u64 sensor_aruid_status;
|
||||
};
|
||||
static_assert(sizeof(AruidFormat) == 0x10, "AruidFormat is an invalid size");
|
||||
|
||||
// This is nn::irsensor::IrCameraInternalStatus
|
||||
enum IrCameraInternalStatus : u32 {
|
||||
Stopped,
|
||||
FirmwareUpdateNeeded,
|
||||
Unkown2,
|
||||
Unkown3,
|
||||
Unkown4,
|
||||
FirmwareVersionRequested,
|
||||
FirmwareVersionIsInvalid,
|
||||
Ready,
|
||||
Setting,
|
||||
// This is nn::irsensor::detail::StatusManager
|
||||
struct StatusManager {
|
||||
std::array<Core::IrSensor::DeviceFormat, 9> device;
|
||||
std::array<AruidFormat, 5> aruid;
|
||||
};
|
||||
|
||||
// This is nn::irsensor::detail::StatusManager::IrSensorMode
|
||||
enum IrSensorMode : u64 {
|
||||
None,
|
||||
MomentProcessor,
|
||||
ClusteringProcessor,
|
||||
ImageTransferProcessor,
|
||||
PointingProcessorMarker,
|
||||
TeraPluginProcessor,
|
||||
IrLedProcessor,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::ImageProcessorStatus
|
||||
enum ImageProcessorStatus : u8 {
|
||||
stopped,
|
||||
running,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::ImageTransferProcessorFormat
|
||||
enum ImageTransferProcessorFormat : u8 {
|
||||
Size320x240,
|
||||
Size160x120,
|
||||
Size80x60,
|
||||
Size40x30,
|
||||
Size20x15,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::AdaptiveClusteringMode
|
||||
enum AdaptiveClusteringMode : u8 {
|
||||
StaticFov,
|
||||
DynamicFov,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::AdaptiveClusteringTargetDistance
|
||||
enum AdaptiveClusteringTargetDistance : u8 {
|
||||
Near,
|
||||
Middle,
|
||||
Far,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::IrsHandAnalysisMode
|
||||
enum IrsHandAnalysisMode : u8 {
|
||||
Silhouette,
|
||||
Image,
|
||||
SilhoueteAndImage,
|
||||
SilhuetteOnly,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::IrSensorFunctionLevel
|
||||
enum IrSensorFunctionLevel : u8 {
|
||||
unknown0,
|
||||
unknown1,
|
||||
unknown2,
|
||||
unknown3,
|
||||
unknown4,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::IrCameraHandle
|
||||
struct IrCameraHandle {
|
||||
u8 npad_id{};
|
||||
Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None};
|
||||
INSERT_PADDING_BYTES(2);
|
||||
};
|
||||
static_assert(sizeof(IrCameraHandle) == 4, "IrCameraHandle is an invalid size");
|
||||
|
||||
struct IrsRect {
|
||||
s16 x;
|
||||
s16 y;
|
||||
s16 width;
|
||||
s16 height;
|
||||
};
|
||||
|
||||
// This is nn::irsensor::PackedMcuVersion
|
||||
struct PackedMcuVersion {
|
||||
u16 major;
|
||||
u16 minor;
|
||||
};
|
||||
static_assert(sizeof(PackedMcuVersion) == 4, "PackedMcuVersion is an invalid size");
|
||||
|
||||
// This is nn::irsensor::MomentProcessorConfig
|
||||
struct MomentProcessorConfig {
|
||||
u64 exposire_time;
|
||||
u8 light_target;
|
||||
u8 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(7);
|
||||
IrsRect window_of_interest;
|
||||
u8 preprocess;
|
||||
u8 preprocess_intensity_threshold;
|
||||
INSERT_PADDING_BYTES(5);
|
||||
};
|
||||
static_assert(sizeof(MomentProcessorConfig) == 0x28,
|
||||
"MomentProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedMomentProcessorConfig
|
||||
struct PackedMomentProcessorConfig {
|
||||
u64 exposire_time;
|
||||
u8 light_target;
|
||||
u8 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(5);
|
||||
IrsRect window_of_interest;
|
||||
PackedMcuVersion required_mcu_version;
|
||||
u8 preprocess;
|
||||
u8 preprocess_intensity_threshold;
|
||||
INSERT_PADDING_BYTES(2);
|
||||
};
|
||||
static_assert(sizeof(PackedMomentProcessorConfig) == 0x20,
|
||||
"PackedMomentProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::ClusteringProcessorConfig
|
||||
struct ClusteringProcessorConfig {
|
||||
u64 exposire_time;
|
||||
u32 light_target;
|
||||
u32 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(7);
|
||||
IrsRect window_of_interest;
|
||||
u32 pixel_count_min;
|
||||
u32 pixel_count_max;
|
||||
u32 object_intensity_min;
|
||||
u8 is_external_light_filter_enabled;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(ClusteringProcessorConfig) == 0x30,
|
||||
"ClusteringProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedClusteringProcessorConfig
|
||||
struct PackedClusteringProcessorConfig {
|
||||
u64 exposire_time;
|
||||
u8 light_target;
|
||||
u8 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(5);
|
||||
IrsRect window_of_interest;
|
||||
PackedMcuVersion required_mcu_version;
|
||||
u32 pixel_count_min;
|
||||
u32 pixel_count_max;
|
||||
u32 object_intensity_min;
|
||||
u8 is_external_light_filter_enabled;
|
||||
INSERT_PADDING_BYTES(2);
|
||||
};
|
||||
static_assert(sizeof(PackedClusteringProcessorConfig) == 0x30,
|
||||
"PackedClusteringProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedImageTransferProcessorConfig
|
||||
struct PackedImageTransferProcessorConfig {
|
||||
u64 exposire_time;
|
||||
u8 light_target;
|
||||
u8 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(5);
|
||||
PackedMcuVersion required_mcu_version;
|
||||
u8 format;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(PackedImageTransferProcessorConfig) == 0x18,
|
||||
"PackedImageTransferProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedTeraPluginProcessorConfig
|
||||
struct PackedTeraPluginProcessorConfig {
|
||||
PackedMcuVersion required_mcu_version;
|
||||
u8 mode;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(PackedTeraPluginProcessorConfig) == 0x8,
|
||||
"PackedTeraPluginProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedPointingProcessorConfig
|
||||
struct PackedPointingProcessorConfig {
|
||||
IrsRect window_of_interest;
|
||||
PackedMcuVersion required_mcu_version;
|
||||
};
|
||||
static_assert(sizeof(PackedPointingProcessorConfig) == 0xC,
|
||||
"PackedPointingProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedFunctionLevel
|
||||
struct PackedFunctionLevel {
|
||||
IrSensorFunctionLevel function_level;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(PackedFunctionLevel) == 0x4, "PackedFunctionLevel is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedImageTransferProcessorExConfig
|
||||
struct PackedImageTransferProcessorExConfig {
|
||||
u64 exposire_time;
|
||||
u8 light_target;
|
||||
u8 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(5);
|
||||
PackedMcuVersion required_mcu_version;
|
||||
ImageTransferProcessorFormat origin_format;
|
||||
ImageTransferProcessorFormat trimming_format;
|
||||
u16 trimming_start_x;
|
||||
u16 trimming_start_y;
|
||||
u8 is_external_light_filter_enabled;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(PackedImageTransferProcessorExConfig) == 0x20,
|
||||
"PackedImageTransferProcessorExConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedIrLedProcessorConfig
|
||||
struct PackedIrLedProcessorConfig {
|
||||
PackedMcuVersion required_mcu_version;
|
||||
u8 light_target;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(PackedIrLedProcessorConfig) == 0x8,
|
||||
"PackedIrLedProcessorConfig is an invalid size");
|
||||
static_assert(sizeof(StatusManager) == 0x8000, "StatusManager is an invalid size");
|
||||
|
||||
void ActivateIrsensor(Kernel::HLERequestContext& ctx);
|
||||
void DeactivateIrsensor(Kernel::HLERequestContext& ctx);
|
||||
@@ -265,6 +56,56 @@ private:
|
||||
void RunIrLedProcessor(Kernel::HLERequestContext& ctx);
|
||||
void StopImageProcessorAsync(Kernel::HLERequestContext& ctx);
|
||||
void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx);
|
||||
|
||||
Result IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const;
|
||||
Core::IrSensor::DeviceFormat& GetIrCameraSharedMemoryDeviceEntry(
|
||||
const Core::IrSensor::IrCameraHandle& camera_handle);
|
||||
|
||||
template <typename T>
|
||||
void MakeProcessor(const Core::IrSensor::IrCameraHandle& handle,
|
||||
Core::IrSensor::DeviceFormat& device_state) {
|
||||
const auto index = static_cast<std::size_t>(handle.npad_id);
|
||||
if (index > sizeof(processors)) {
|
||||
LOG_CRITICAL(Service_IRS, "Invalid index {}", index);
|
||||
return;
|
||||
}
|
||||
processors[index] = std::make_unique<T>(device_state);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MakeProcessorWithCoreContext(const Core::IrSensor::IrCameraHandle& handle,
|
||||
Core::IrSensor::DeviceFormat& device_state) {
|
||||
const auto index = static_cast<std::size_t>(handle.npad_id);
|
||||
if (index > sizeof(processors)) {
|
||||
LOG_CRITICAL(Service_IRS, "Invalid index {}", index);
|
||||
return;
|
||||
}
|
||||
processors[index] = std::make_unique<T>(system.HIDCore(), device_state, index);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& GetProcessor(const Core::IrSensor::IrCameraHandle& handle) {
|
||||
const auto index = static_cast<std::size_t>(handle.npad_id);
|
||||
if (index > sizeof(processors)) {
|
||||
LOG_CRITICAL(Service_IRS, "Invalid index {}", index);
|
||||
return static_cast<T&>(*processors[0]);
|
||||
}
|
||||
return static_cast<T&>(*processors[index]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& GetProcessor(const Core::IrSensor::IrCameraHandle& handle) const {
|
||||
const auto index = static_cast<std::size_t>(handle.npad_id);
|
||||
if (index > sizeof(processors)) {
|
||||
LOG_CRITICAL(Service_IRS, "Invalid index {}", index);
|
||||
return static_cast<T&>(*processors[0]);
|
||||
}
|
||||
return static_cast<T&>(*processors[index]);
|
||||
}
|
||||
|
||||
Core::HID::EmulatedController* npad_device = nullptr;
|
||||
StatusManager* shared_memory = nullptr;
|
||||
std::array<std::unique_ptr<ProcessorBase>, 9> processors{};
|
||||
};
|
||||
|
||||
class IRS_SYS final : public ServiceFramework<IRS_SYS> {
|
||||
@@ -273,4 +114,4 @@ public:
|
||||
~IRS_SYS() override;
|
||||
};
|
||||
|
||||
} // namespace Service::HID
|
||||
} // namespace Service::IRS
|
||||
|
47
src/core/hle/service/hid/irs_ring_lifo.h
Executable file
47
src/core/hle/service/hid/irs_ring_lifo.h
Executable file
@@ -0,0 +1,47 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::IRS {
|
||||
|
||||
template <typename State, std::size_t max_buffer_size>
|
||||
struct Lifo {
|
||||
s64 sampling_number{};
|
||||
s64 buffer_count{};
|
||||
std::array<State, max_buffer_size> entries{};
|
||||
|
||||
const State& ReadCurrentEntry() const {
|
||||
return entries[GetBufferTail()];
|
||||
}
|
||||
|
||||
const State& ReadPreviousEntry() const {
|
||||
return entries[GetPreviousEntryIndex()];
|
||||
}
|
||||
|
||||
s64 GetBufferTail() const {
|
||||
return sampling_number % max_buffer_size;
|
||||
}
|
||||
|
||||
std::size_t GetPreviousEntryIndex() const {
|
||||
return static_cast<size_t>((GetBufferTail() + max_buffer_size - 1) % max_buffer_size);
|
||||
}
|
||||
|
||||
std::size_t GetNextEntryIndex() const {
|
||||
return static_cast<size_t>((GetBufferTail() + 1) % max_buffer_size);
|
||||
}
|
||||
|
||||
void WriteNextEntry(const State& new_state) {
|
||||
if (buffer_count < static_cast<s64>(max_buffer_size)) {
|
||||
buffer_count++;
|
||||
}
|
||||
sampling_number++;
|
||||
entries[GetBufferTail()] = new_state;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Service::IRS
|
@@ -1,34 +1,264 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hle/service/hid/irsensor/clustering_processor.h"
|
||||
|
||||
namespace Service::IRS {
|
||||
ClusteringProcessor::ClusteringProcessor(Core::IrSensor::DeviceFormat& device_format)
|
||||
: device(device_format) {
|
||||
ClusteringProcessor::ClusteringProcessor(Core::HID::HIDCore& hid_core_,
|
||||
Core::IrSensor::DeviceFormat& device_format,
|
||||
std::size_t npad_index)
|
||||
: device{device_format} {
|
||||
npad_device = hid_core_.GetEmulatedControllerByIndex(npad_index);
|
||||
|
||||
device.mode = Core::IrSensor::IrSensorMode::ClusteringProcessor;
|
||||
device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
|
||||
device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
|
||||
SetDefaultConfig();
|
||||
|
||||
shared_memory = std::construct_at(
|
||||
reinterpret_cast<ClusteringSharedMemory*>(&device_format.state.processor_raw_data));
|
||||
|
||||
Core::HID::ControllerUpdateCallback engine_callback{
|
||||
.on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); },
|
||||
.is_npad_service = true,
|
||||
};
|
||||
callback_key = npad_device->SetCallback(engine_callback);
|
||||
}
|
||||
|
||||
ClusteringProcessor::~ClusteringProcessor() = default;
|
||||
ClusteringProcessor::~ClusteringProcessor() {
|
||||
npad_device->DeleteCallback(callback_key);
|
||||
};
|
||||
|
||||
void ClusteringProcessor::StartProcessor() {}
|
||||
void ClusteringProcessor::StartProcessor() {
|
||||
device.camera_status = Core::IrSensor::IrCameraStatus::Available;
|
||||
device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Ready;
|
||||
}
|
||||
|
||||
void ClusteringProcessor::SuspendProcessor() {}
|
||||
|
||||
void ClusteringProcessor::StopProcessor() {}
|
||||
|
||||
void ClusteringProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType type) {
|
||||
if (type != Core::HID::ControllerTriggerType::IrSensor) {
|
||||
return;
|
||||
}
|
||||
|
||||
next_state = {};
|
||||
const auto camera_data = npad_device->GetCamera();
|
||||
auto filtered_image = camera_data.data;
|
||||
|
||||
RemoveLowIntensityData(filtered_image);
|
||||
|
||||
const auto window_start_x = static_cast<std::size_t>(current_config.window_of_interest.x);
|
||||
const auto window_start_y = static_cast<std::size_t>(current_config.window_of_interest.y);
|
||||
const auto window_end_x =
|
||||
window_start_x + static_cast<std::size_t>(current_config.window_of_interest.width);
|
||||
const auto window_end_y =
|
||||
window_start_y + static_cast<std::size_t>(current_config.window_of_interest.height);
|
||||
|
||||
for (std::size_t y = window_start_y; y < window_end_y; y++) {
|
||||
for (std::size_t x = window_start_x; x < window_end_x; x++) {
|
||||
u8 pixel = GetPixel(filtered_image, x, y);
|
||||
if (pixel == 0) {
|
||||
continue;
|
||||
}
|
||||
const auto cluster = GetClusterProperties(filtered_image, x, y);
|
||||
if (cluster.pixel_count > current_config.pixel_count_max) {
|
||||
continue;
|
||||
}
|
||||
if (cluster.pixel_count < current_config.pixel_count_min) {
|
||||
continue;
|
||||
}
|
||||
// Cluster object limit reached
|
||||
if (next_state.object_count >= next_state.data.size()) {
|
||||
continue;
|
||||
}
|
||||
next_state.data[next_state.object_count] = cluster;
|
||||
next_state.object_count++;
|
||||
}
|
||||
}
|
||||
|
||||
next_state.sampling_number = camera_data.sample;
|
||||
next_state.timestamp = next_state.timestamp + 131;
|
||||
next_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low;
|
||||
shared_memory->clustering_lifo.WriteNextEntry(next_state);
|
||||
|
||||
if (!IsProcessorActive()) {
|
||||
StartProcessor();
|
||||
}
|
||||
}
|
||||
|
||||
void ClusteringProcessor::RemoveLowIntensityData(std::vector<u8>& data) {
|
||||
for (u8& pixel : data) {
|
||||
if (pixel < current_config.pixel_count_min) {
|
||||
pixel = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClusteringProcessor::ClusteringData ClusteringProcessor::GetClusterProperties(std::vector<u8>& data,
|
||||
std::size_t x,
|
||||
std::size_t y) {
|
||||
std::queue<Common::Point<std::size_t>> search_points{};
|
||||
ClusteringData current_cluster = GetPixelProperties(data, x, y);
|
||||
SetPixel(data, x, y, 0);
|
||||
search_points.emplace(x, y);
|
||||
|
||||
while (!search_points.empty()) {
|
||||
const auto point = search_points.front();
|
||||
search_points.pop();
|
||||
|
||||
// Avoid negative numbers
|
||||
if (point.x == 0 || point.y == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::array<Common::Point<std::size_t>, 4> new_points{
|
||||
Common::Point<std::size_t>{point.x - 1, point.y},
|
||||
{point.x, point.y - 1},
|
||||
{point.x + 1, point.y},
|
||||
{point.x, point.y + 1},
|
||||
};
|
||||
|
||||
for (const auto new_point : new_points) {
|
||||
if (new_point.x >= width) {
|
||||
continue;
|
||||
}
|
||||
if (new_point.y >= height) {
|
||||
continue;
|
||||
}
|
||||
if (GetPixel(data, new_point.x, new_point.y) < current_config.object_intensity_min) {
|
||||
continue;
|
||||
}
|
||||
const ClusteringData cluster = GetPixelProperties(data, new_point.x, new_point.y);
|
||||
current_cluster = MergeCluster(current_cluster, cluster);
|
||||
SetPixel(data, new_point.x, new_point.y, 0);
|
||||
search_points.emplace(new_point.x, new_point.y);
|
||||
}
|
||||
}
|
||||
|
||||
return current_cluster;
|
||||
}
|
||||
|
||||
ClusteringProcessor::ClusteringData ClusteringProcessor::GetPixelProperties(
|
||||
const std::vector<u8>& data, std::size_t x, std::size_t y) const {
|
||||
return {
|
||||
.average_intensity = GetPixel(data, x, y) / 255.0f,
|
||||
.centroid =
|
||||
{
|
||||
.x = static_cast<f32>(x),
|
||||
.y = static_cast<f32>(y),
|
||||
|
||||
},
|
||||
.pixel_count = 1,
|
||||
.bound =
|
||||
{
|
||||
.x = static_cast<s16>(x),
|
||||
.y = static_cast<s16>(y),
|
||||
.width = 1,
|
||||
.height = 1,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
ClusteringProcessor::ClusteringData ClusteringProcessor::MergeCluster(
|
||||
const ClusteringData a, const ClusteringData b) const {
|
||||
const f32 a_pixel_count = static_cast<f32>(a.pixel_count);
|
||||
const f32 b_pixel_count = static_cast<f32>(b.pixel_count);
|
||||
const f32 pixel_count = a_pixel_count + b_pixel_count;
|
||||
const f32 average_intensity =
|
||||
(a.average_intensity * a_pixel_count + b.average_intensity * b_pixel_count) / pixel_count;
|
||||
const Core::IrSensor::IrsCentroid centroid = {
|
||||
.x = (a.centroid.x * a_pixel_count + b.centroid.x * b_pixel_count) / pixel_count,
|
||||
.y = (a.centroid.y * a_pixel_count + b.centroid.y * b_pixel_count) / pixel_count,
|
||||
};
|
||||
s16 bound_start_x = a.bound.x < b.bound.x ? a.bound.x : b.bound.x;
|
||||
s16 bound_start_y = a.bound.y < b.bound.y ? a.bound.y : b.bound.y;
|
||||
s16 a_bound_end_x = a.bound.x + a.bound.width;
|
||||
s16 a_bound_end_y = a.bound.y + a.bound.height;
|
||||
s16 b_bound_end_x = b.bound.x + b.bound.width;
|
||||
s16 b_bound_end_y = b.bound.y + b.bound.height;
|
||||
|
||||
const Core::IrSensor::IrsRect bound = {
|
||||
.x = bound_start_x,
|
||||
.y = bound_start_y,
|
||||
.width = a_bound_end_x > b_bound_end_x ? static_cast<s16>(a_bound_end_x - bound_start_x)
|
||||
: static_cast<s16>(b_bound_end_x - bound_start_x),
|
||||
.height = a_bound_end_y > b_bound_end_y ? static_cast<s16>(a_bound_end_y - bound_start_y)
|
||||
: static_cast<s16>(b_bound_end_y - bound_start_y),
|
||||
};
|
||||
|
||||
return {
|
||||
.average_intensity = average_intensity,
|
||||
.centroid = centroid,
|
||||
.pixel_count = static_cast<u32>(pixel_count),
|
||||
.bound = bound,
|
||||
};
|
||||
}
|
||||
|
||||
u8 ClusteringProcessor::GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const {
|
||||
if ((y * width) + x > data.size()) {
|
||||
return 0;
|
||||
}
|
||||
return data[(y * width) + x];
|
||||
}
|
||||
|
||||
void ClusteringProcessor::SetPixel(std::vector<u8>& data, std::size_t x, std::size_t y, u8 value) {
|
||||
if ((y * width) + x > data.size()) {
|
||||
return;
|
||||
}
|
||||
data[(y * width) + x] = value;
|
||||
}
|
||||
|
||||
void ClusteringProcessor::SetDefaultConfig() {
|
||||
using namespace std::literals::chrono_literals;
|
||||
current_config.camera_config.exposure_time = std::chrono::microseconds(200ms).count();
|
||||
current_config.camera_config.gain = 2;
|
||||
current_config.camera_config.is_negative_used = false;
|
||||
current_config.camera_config.light_target = Core::IrSensor::CameraLightTarget::BrightLeds;
|
||||
current_config.window_of_interest = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
current_config.pixel_count_min = 3;
|
||||
current_config.pixel_count_max = static_cast<u32>(GetDataSize(format));
|
||||
current_config.is_external_light_filter_enabled = true;
|
||||
current_config.object_intensity_min = 150;
|
||||
|
||||
npad_device->SetCameraFormat(format);
|
||||
}
|
||||
|
||||
void ClusteringProcessor::SetConfig(Core::IrSensor::PackedClusteringProcessorConfig config) {
|
||||
current_config.camera_config.exposure_time = config.camera_config.exposure_time;
|
||||
current_config.camera_config.gain = config.camera_config.gain;
|
||||
current_config.camera_config.is_negative_used = config.camera_config.is_negative_used;
|
||||
current_config.camera_config.light_target =
|
||||
static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target);
|
||||
current_config.window_of_interest = config.window_of_interest;
|
||||
current_config.pixel_count_min = config.pixel_count_min;
|
||||
current_config.pixel_count_max = config.pixel_count_max;
|
||||
current_config.is_external_light_filter_enabled = config.is_external_light_filter_enabled;
|
||||
current_config.object_intensity_min = config.object_intensity_min;
|
||||
|
||||
LOG_INFO(Service_IRS,
|
||||
"Processor config, exposure_time={}, gain={}, is_negative_used={}, "
|
||||
"light_target={}, window_of_interest=({}, {}, {}, {}), pixel_count_min={}, "
|
||||
"pixel_count_max={}, is_external_light_filter_enabled={}, object_intensity_min={}",
|
||||
current_config.camera_config.exposure_time, current_config.camera_config.gain,
|
||||
current_config.camera_config.is_negative_used,
|
||||
current_config.camera_config.light_target, current_config.window_of_interest.x,
|
||||
current_config.window_of_interest.y, current_config.window_of_interest.width,
|
||||
current_config.window_of_interest.height, current_config.pixel_count_min,
|
||||
current_config.pixel_count_max, current_config.is_external_light_filter_enabled,
|
||||
current_config.object_intensity_min);
|
||||
|
||||
npad_device->SetCameraFormat(format);
|
||||
}
|
||||
|
||||
} // namespace Service::IRS
|
||||
|
@@ -5,12 +5,19 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hid/irs_types.h"
|
||||
#include "core/hle/service/hid/irs_ring_lifo.h"
|
||||
#include "core/hle/service/hid/irsensor/processor_base.h"
|
||||
|
||||
namespace Core::HID {
|
||||
class EmulatedController;
|
||||
} // namespace Core::HID
|
||||
|
||||
namespace Service::IRS {
|
||||
class ClusteringProcessor final : public ProcessorBase {
|
||||
public:
|
||||
explicit ClusteringProcessor(Core::IrSensor::DeviceFormat& device_format);
|
||||
explicit ClusteringProcessor(Core::HID::HIDCore& hid_core_,
|
||||
Core::IrSensor::DeviceFormat& device_format,
|
||||
std::size_t npad_index);
|
||||
~ClusteringProcessor() override;
|
||||
|
||||
// Called when the processor is initialized
|
||||
@@ -26,6 +33,10 @@ public:
|
||||
void SetConfig(Core::IrSensor::PackedClusteringProcessorConfig config);
|
||||
|
||||
private:
|
||||
static constexpr auto format = Core::IrSensor::ImageTransferProcessorFormat::Size320x240;
|
||||
static constexpr std::size_t width = 320;
|
||||
static constexpr std::size_t height = 240;
|
||||
|
||||
// This is nn::irsensor::ClusteringProcessorConfig
|
||||
struct ClusteringProcessorConfig {
|
||||
Core::IrSensor::CameraConfig camera_config;
|
||||
@@ -68,7 +79,32 @@ private:
|
||||
static_assert(sizeof(ClusteringProcessorState) == 0x198,
|
||||
"ClusteringProcessorState is an invalid size");
|
||||
|
||||
struct ClusteringSharedMemory {
|
||||
Service::IRS::Lifo<ClusteringProcessorState, 6> clustering_lifo;
|
||||
static_assert(sizeof(clustering_lifo) == 0x9A0, "clustering_lifo is an invalid size");
|
||||
INSERT_PADDING_WORDS(0x11F);
|
||||
};
|
||||
static_assert(sizeof(ClusteringSharedMemory) == 0xE20,
|
||||
"ClusteringSharedMemory is an invalid size");
|
||||
|
||||
void OnControllerUpdate(Core::HID::ControllerTriggerType type);
|
||||
void RemoveLowIntensityData(std::vector<u8>& data);
|
||||
ClusteringData GetClusterProperties(std::vector<u8>& data, std::size_t x, std::size_t y);
|
||||
ClusteringData GetPixelProperties(const std::vector<u8>& data, std::size_t x,
|
||||
std::size_t y) const;
|
||||
ClusteringData MergeCluster(const ClusteringData a, const ClusteringData b) const;
|
||||
u8 GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const;
|
||||
void SetPixel(std::vector<u8>& data, std::size_t x, std::size_t y, u8 value);
|
||||
|
||||
// Sets config parameters of the camera
|
||||
void SetDefaultConfig();
|
||||
|
||||
ClusteringSharedMemory* shared_memory = nullptr;
|
||||
ClusteringProcessorState next_state{};
|
||||
|
||||
ClusteringProcessorConfig current_config{};
|
||||
Core::IrSensor::DeviceFormat& device;
|
||||
Core::HID::EmulatedController* npad_device;
|
||||
int callback_key{};
|
||||
};
|
||||
} // namespace Service::IRS
|
||||
|
Reference in New Issue
Block a user