summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgerman77 <juangerman-13@hotmail.com>2022-06-19 06:45:06 +0200
committergerman77 <juangerman-13@hotmail.com>2022-07-24 02:40:25 +0200
commit453970059528d564d9ef88f7f9096c05946fbefe (patch)
tree3b1a43e8dd51e5c03204108ac72c4cd33d5361c0
parentcore: hid: Add cammera support (diff)
downloadyuzu-453970059528d564d9ef88f7f9096c05946fbefe.tar
yuzu-453970059528d564d9ef88f7f9096c05946fbefe.tar.gz
yuzu-453970059528d564d9ef88f7f9096c05946fbefe.tar.bz2
yuzu-453970059528d564d9ef88f7f9096c05946fbefe.tar.lz
yuzu-453970059528d564d9ef88f7f9096c05946fbefe.tar.xz
yuzu-453970059528d564d9ef88f7f9096c05946fbefe.tar.zst
yuzu-453970059528d564d9ef88f7f9096c05946fbefe.zip
-rw-r--r--src/core/CMakeLists.txt14
-rw-r--r--src/core/hle/service/hid/errors.h3
-rw-r--r--src/core/hle/service/hid/irs.cpp290
-rw-r--r--src/core/hle/service/hid/irs.h291
-rw-r--r--src/core/hle/service/hid/irsensor/clustering_processor.cpp36
-rw-r--r--src/core/hle/service/hid/irsensor/clustering_processor.h74
-rw-r--r--src/core/hle/service/hid/irsensor/image_transfer_processor.cpp154
-rw-r--r--src/core/hle/service/hid/irsensor/image_transfer_processor.h73
-rw-r--r--src/core/hle/service/hid/irsensor/ir_led_processor.cpp29
-rw-r--r--src/core/hle/service/hid/irsensor/ir_led_processor.h47
-rw-r--r--src/core/hle/service/hid/irsensor/moment_processor.cpp36
-rw-r--r--src/core/hle/service/hid/irsensor/moment_processor.h61
-rw-r--r--src/core/hle/service/hid/irsensor/pointing_processor.cpp28
-rw-r--r--src/core/hle/service/hid/irsensor/pointing_processor.h62
-rw-r--r--src/core/hle/service/hid/irsensor/processor_base.cpp67
-rw-r--r--src/core/hle/service/hid/irsensor/processor_base.h33
-rw-r--r--src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp31
-rw-r--r--src/core/hle/service/hid/irsensor/tera_plugin_processor.h53
18 files changed, 1091 insertions, 291 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 1f8439f91..32cc2f392 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -478,6 +478,20 @@ add_library(core STATIC
hle/service/hid/hidbus/starlink.h
hle/service/hid/hidbus/stubbed.cpp
hle/service/hid/hidbus/stubbed.h
+ hle/service/hid/irsensor/clustering_processor.cpp
+ hle/service/hid/irsensor/clustering_processor.h
+ hle/service/hid/irsensor/image_transfer_processor.cpp
+ hle/service/hid/irsensor/image_transfer_processor.h
+ hle/service/hid/irsensor/ir_led_processor.cpp
+ hle/service/hid/irsensor/ir_led_processor.h
+ hle/service/hid/irsensor/moment_processor.cpp
+ hle/service/hid/irsensor/moment_processor.h
+ hle/service/hid/irsensor/pointing_processor.cpp
+ hle/service/hid/irsensor/pointing_processor.h
+ hle/service/hid/irsensor/processor_base.cpp
+ hle/service/hid/irsensor/processor_base.h
+ hle/service/hid/irsensor/tera_plugin_processor.cpp
+ hle/service/hid/irsensor/tera_plugin_processor.h
hle/service/jit/jit_context.cpp
hle/service/jit/jit_context.h
hle/service/jit/jit.cpp
diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h
index 46282f42e..1bd62461c 100644
--- a/src/core/hle/service/hid/errors.h
+++ b/src/core/hle/service/hid/errors.h
@@ -18,4 +18,7 @@ constexpr Result NpadIsSameType{ErrorModule::HID, 602};
constexpr Result InvalidNpadId{ErrorModule::HID, 709};
constexpr Result NpadNotConnected{ErrorModule::HID, 710};
+constexpr ResultCode InvalidProcessorState{ErrorModule::Irsensor, 78};
+constexpr ResultCode InvalidIrCameraHandle{ErrorModule::Irsensor, 204};
+
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index d2a91d913..53a31df79 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -1,14 +1,26 @@
// 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 {
@@ -36,8 +48,13 @@ 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};
@@ -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,17 +132,26 @@ 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.");
@@ -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);
+ MakeProcessor<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_HID, "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,21 +236,40 @@ 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);
+
+ const auto result = IsIrCameraHandleValid(parameters.camera_handle);
+ if (result.IsError()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
+ }
- IPC::ResponseBuilder rb{ctx, 5};
+ 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 camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
+ const auto processor_config{rp.PopRaw<Core::IrSensor::PackedTeraPluginProcessorConfig>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_IRS,
@@ -196,8 +279,17 @@ void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) {
processor_config.required_mcu_version.major,
processor_config.required_mcu_version.minor, applet_resource_user_id);
+ const auto result = IsIrCameraHandleValid(camera_handle);
+
+ if (result.IsSuccess()) {
+ auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
+ MakeProcessor<TeraPluginProcessor>(camera_handle, device);
+ auto& image_transfer_processor = GetProcessor<TeraPluginProcessor>(camera_handle);
+ image_transfer_processor.SetConfig(processor_config);
+ }
+
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ rb.Push(result);
}
void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
@@ -211,13 +303,13 @@ void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
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 +318,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 +328,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 +357,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 +379,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 parameters{rp.PopRaw<Parameters>()};
+ 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>()};
- 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_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);
+
+ 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 +428,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 +464,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 +493,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 +521,22 @@ void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-IRS::~IRS() = default;
+ResultCode 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
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h
index 361dc2213..ae7f7719b 100644
--- a/src/core/hle/service/hid/irs.h
+++ b/src/core/hle/service/hid/irs.h
@@ -4,12 +4,18 @@
#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 Core::HID {
+class EmulatedController;
+} // namespace Core::HID
+
namespace Service::HID {
class IRS final : public ServiceFramework<IRS> {
@@ -18,234 +24,19 @@ public:
~IRS() override;
private:
- // This is nn::irsensor::IrCameraStatus
- enum IrCameraStatus : u32 {
- Available,
- Unsupported,
- Unconnected,
- };
-
- // This is nn::irsensor::IrCameraInternalStatus
- enum IrCameraInternalStatus : u32 {
- Stopped,
- FirmwareUpdateNeeded,
- Unkown2,
- Unkown3,
- Unkown4,
- FirmwareVersionRequested,
- FirmwareVersionIsInvalid,
- Ready,
- Setting,
- };
-
- // 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::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::PackedMcuVersion
- struct PackedMcuVersion {
- u16 major;
- u16 minor;
+ // This is nn::irsensor::detail::StatusManager
+ struct StatusManager {
+ std::array<Core::IrSensor::DeviceFormat, 9> device;
+ std::array<AruidFormat, 5> aruid;
};
- 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);
+
+ ResultCode 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> {
diff --git a/src/core/hle/service/hid/irsensor/clustering_processor.cpp b/src/core/hle/service/hid/irsensor/clustering_processor.cpp
new file mode 100644
index 000000000..aac3e4fec
--- /dev/null
+++ b/src/core/hle/service/hid/irsensor/clustering_processor.cpp
@@ -0,0 +1,36 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "core/hle/service/hid/irsensor/clustering_processor.h"
+
+namespace Service::HID {
+ClusteringProcessor::ClusteringProcessor(Core::IrSensor::DeviceFormat& device_format)
+ : device(device_format) {
+ device.mode = Core::IrSensor::IrSensorMode::ClusteringProcessor;
+ device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
+ device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
+ device.state.start = 0;
+ device.state.count = 0;
+}
+
+ClusteringProcessor::~ClusteringProcessor() = default;
+
+void ClusteringProcessor::StartProcessor() {}
+
+void ClusteringProcessor::SuspendProcessor() {}
+
+void ClusteringProcessor::StopProcessor() {}
+
+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.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;
+}
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irsensor/clustering_processor.h b/src/core/hle/service/hid/irsensor/clustering_processor.h
new file mode 100644
index 000000000..58b2acf1c
--- /dev/null
+++ b/src/core/hle/service/hid/irsensor/clustering_processor.h
@@ -0,0 +1,74 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/hid/irs_types.h"
+#include "core/hle/service/hid/irsensor/processor_base.h"
+
+namespace Service::HID {
+class ClusteringProcessor final : public ProcessorBase {
+public:
+ explicit ClusteringProcessor(Core::IrSensor::DeviceFormat& device_format);
+ ~ClusteringProcessor() override;
+
+ // Called when the processor is initialized
+ void StartProcessor() override;
+
+ // Called when the processor is suspended
+ void SuspendProcessor() override;
+
+ // Called when the processor is stopped
+ void StopProcessor() override;
+
+ // Sets config parameters of the camera
+ void SetConfig(Core::IrSensor::PackedClusteringProcessorConfig config);
+
+private:
+ // This is nn::irsensor::ClusteringProcessorConfig
+ struct ClusteringProcessorConfig {
+ Core::IrSensor::CameraConfig camera_config;
+ Core::IrSensor::IrsRect window_of_interest;
+ u32 pixel_count_min;
+ u32 pixel_count_max;
+ u32 object_intensity_min;
+ bool is_external_light_filter_enabled;
+ INSERT_PADDING_BYTES(3);
+ };
+ static_assert(sizeof(ClusteringProcessorConfig) == 0x30,
+ "ClusteringProcessorConfig is an invalid size");
+
+ // This is nn::irsensor::AdaptiveClusteringProcessorConfig
+ struct AdaptiveClusteringProcessorConfig {
+ Core::IrSensor::AdaptiveClusteringMode mode;
+ Core::IrSensor::AdaptiveClusteringTargetDistance target_distance;
+ };
+ static_assert(sizeof(AdaptiveClusteringProcessorConfig) == 0x8,
+ "AdaptiveClusteringProcessorConfig is an invalid size");
+
+ // This is nn::irsensor::ClusteringData
+ struct ClusteringData {
+ f32 average_intensity;
+ Core::IrSensor::IrsCentroid centroid;
+ u32 pixel_count;
+ Core::IrSensor::IrsRect bound;
+ };
+ static_assert(sizeof(ClusteringData) == 0x18, "ClusteringData is an invalid size");
+
+ // This is nn::irsensor::ClusteringProcessorState
+ struct ClusteringProcessorState {
+ s64 sampling_number;
+ u64 timestamp;
+ u8 object_count;
+ INSERT_PADDING_BYTES(3);
+ Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level;
+ std::array<ClusteringData, 0x10> data;
+ };
+ static_assert(sizeof(ClusteringProcessorState) == 0x198,
+ "ClusteringProcessorState is an invalid size");
+
+ ClusteringProcessorConfig current_config{};
+ Core::IrSensor::DeviceFormat& device;
+};
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp b/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp
new file mode 100644
index 000000000..703e825e6
--- /dev/null
+++ b/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp
@@ -0,0 +1,154 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "core/hid/emulated_controller.h"
+#include "core/hid/hid_core.h"
+#include "core/hle/service/hid/irsensor/image_transfer_processor.h"
+
+namespace Service::HID {
+ImageTransferProcessor::ImageTransferProcessor(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);
+
+ 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);
+
+ device.mode = Core::IrSensor::IrSensorMode::ImageTransferProcessor;
+ device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
+ device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
+ device.state.start = 0;
+ device.state.count = 0;
+}
+
+ImageTransferProcessor::~ImageTransferProcessor() {
+ npad_device->DeleteCallback(callback_key);
+};
+
+void ImageTransferProcessor::StartProcessor() {
+ is_active = true;
+ device.camera_status = Core::IrSensor::IrCameraStatus::Available;
+ device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Ready;
+ device.state.start = 0;
+ device.state.count = 1;
+ processor_state.sampling_number = 0;
+ processor_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low;
+}
+
+void ImageTransferProcessor::SuspendProcessor() {}
+
+void ImageTransferProcessor::StopProcessor() {}
+
+void ImageTransferProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType type) {
+ if (type != Core::HID::ControllerTriggerType::IrSensor) {
+ return;
+ }
+ if (!is_transfer_memory_set) {
+ return;
+ }
+
+ const auto camera_data = npad_device->GetCamera();
+
+ // This indicates how much ambient light is precent
+ processor_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low;
+ processor_state.sampling_number = camera_data.sample;
+
+ if (camera_data.format != current_config.origin_format) {
+ LOG_WARNING(Service_IRS, "Wrong Input format {} expected {}", camera_data.format,
+ current_config.origin_format);
+ memset(transfer_memory, 0, GetDataSize(current_config.trimming_format));
+ return;
+ }
+
+ if (current_config.origin_format > current_config.trimming_format) {
+ LOG_WARNING(Service_IRS, "Origin format {} is smaller than trimming format {}",
+ current_config.origin_format, current_config.trimming_format);
+ memset(transfer_memory, 0, GetDataSize(current_config.trimming_format));
+ return;
+ }
+
+ std::vector<u8> window_data{};
+ const auto origin_width = GetDataWidth(current_config.origin_format);
+ const auto origin_height = GetDataHeight(current_config.origin_format);
+ const auto trimming_width = GetDataWidth(current_config.trimming_format);
+ const auto trimming_height = GetDataHeight(current_config.trimming_format);
+ window_data.resize(GetDataSize(current_config.trimming_format));
+
+ if (trimming_width + current_config.trimming_start_x > origin_width ||
+ trimming_height + current_config.trimming_start_y > origin_height) {
+ LOG_WARNING(Service_IRS,
+ "Trimming area ({}, {}, {}, {}) is outside of origin area ({}, {})",
+ current_config.trimming_start_x, current_config.trimming_start_y,
+ trimming_width, trimming_height, origin_width, origin_height);
+ memset(transfer_memory, 0, GetDataSize(current_config.trimming_format));
+ return;
+ }
+
+ for (std::size_t y = 0; y < trimming_height; y++) {
+ for (std::size_t x = 0; x < trimming_width; x++) {
+ const std::size_t window_index = (y * trimming_width) + x;
+ const std::size_t origin_index =
+ ((y + current_config.trimming_start_y) * origin_width) + x +
+ current_config.trimming_start_x;
+ window_data[window_index] = camera_data.data[origin_index];
+ }
+ }
+
+ memcpy(transfer_memory, window_data.data(), GetDataSize(current_config.trimming_format));
+
+ if (!IsProcessorActive()) {
+ StartProcessor();
+ }
+}
+
+void ImageTransferProcessor::SetConfig(Core::IrSensor::PackedImageTransferProcessorConfig 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.origin_format =
+ static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.format);
+ current_config.trimming_format =
+ static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.format);
+ current_config.trimming_start_x = 0;
+ current_config.trimming_start_y = 0;
+
+ npad_device->SetCameraFormat(current_config.origin_format);
+}
+
+void ImageTransferProcessor::SetConfig(
+ Core::IrSensor::PackedImageTransferProcessorExConfig 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.origin_format =
+ static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.origin_format);
+ current_config.trimming_format =
+ static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.trimming_format);
+ current_config.trimming_start_x = config.trimming_start_x;
+ current_config.trimming_start_y = config.trimming_start_y;
+
+ npad_device->SetCameraFormat(current_config.origin_format);
+}
+
+void ImageTransferProcessor::SetTransferMemoryPointer(u8* t_mem) {
+ is_transfer_memory_set = true;
+ transfer_memory = t_mem;
+}
+
+Core::IrSensor::ImageTransferProcessorState ImageTransferProcessor::GetState(
+ std::vector<u8>& data) const {
+ const auto size = GetDataSize(current_config.trimming_format);
+ data.resize(size);
+ memcpy(data.data(), transfer_memory, size);
+ return processor_state;
+}
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irsensor/image_transfer_processor.h b/src/core/hle/service/hid/irsensor/image_transfer_processor.h
new file mode 100644
index 000000000..b557eaf20
--- /dev/null
+++ b/src/core/hle/service/hid/irsensor/image_transfer_processor.h
@@ -0,0 +1,73 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/hid/irs_types.h"
+#include "core/hle/service/hid/irsensor/processor_base.h"
+
+namespace Core::HID {
+class EmulatedController;
+} // namespace Core::HID
+
+namespace Service::HID {
+class ImageTransferProcessor final : public ProcessorBase {
+public:
+ explicit ImageTransferProcessor(Core::HID::HIDCore& hid_core_,
+ Core::IrSensor::DeviceFormat& device_format,
+ std::size_t npad_index);
+ ~ImageTransferProcessor() override;
+
+ // Called when the processor is initialized
+ void StartProcessor() override;
+
+ // Called when the processor is suspended
+ void SuspendProcessor() override;
+
+ // Called when the processor is stopped
+ void StopProcessor() override;
+
+ // Sets config parameters of the camera
+ void SetConfig(Core::IrSensor::PackedImageTransferProcessorConfig config);
+ void SetConfig(Core::IrSensor::PackedImageTransferProcessorExConfig config);
+
+ // Transfer memory where the image data will be stored
+ void SetTransferMemoryPointer(u8* t_mem);
+
+ Core::IrSensor::ImageTransferProcessorState GetState(std::vector<u8>& data) const;
+
+private:
+ // This is nn::irsensor::ImageTransferProcessorConfig
+ struct ImageTransferProcessorConfig {
+ Core::IrSensor::CameraConfig camera_config;
+ Core::IrSensor::ImageTransferProcessorFormat format;
+ };
+ static_assert(sizeof(ImageTransferProcessorConfig) == 0x20,
+ "ImageTransferProcessorConfig is an invalid size");
+
+ // This is nn::irsensor::ImageTransferProcessorExConfig
+ struct ImageTransferProcessorExConfig {
+ Core::IrSensor::CameraConfig camera_config;
+ Core::IrSensor::ImageTransferProcessorFormat origin_format;
+ Core::IrSensor::ImageTransferProcessorFormat trimming_format;
+ u16 trimming_start_x;
+ u16 trimming_start_y;
+ bool is_external_light_filter_enabled;
+ INSERT_PADDING_BYTES(3);
+ };
+ static_assert(sizeof(ImageTransferProcessorExConfig) == 0x28,
+ "ImageTransferProcessorExConfig is an invalid size");
+
+ void OnControllerUpdate(Core::HID::ControllerTriggerType type);
+
+ ImageTransferProcessorExConfig current_config{};
+ Core::IrSensor::ImageTransferProcessorState processor_state{};
+ Core::IrSensor::DeviceFormat& device;
+ Core::HID::EmulatedController* npad_device;
+ int callback_key{};
+
+ u8* transfer_memory = nullptr;
+ bool is_transfer_memory_set = false;
+};
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irsensor/ir_led_processor.cpp b/src/core/hle/service/hid/irsensor/ir_led_processor.cpp
new file mode 100644
index 000000000..656e17c95
--- /dev/null
+++ b/src/core/hle/service/hid/irsensor/ir_led_processor.cpp
@@ -0,0 +1,29 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "core/hle/service/hid/irsensor/ir_led_processor.h"
+
+namespace Service::HID {
+IrLedProcessor::IrLedProcessor(Core::IrSensor::DeviceFormat& device_format)
+ : device(device_format) {
+ device.mode = Core::IrSensor::IrSensorMode::IrLedProcessor;
+ device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
+ device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
+ device.state.start = 0;
+ device.state.count = 0;
+}
+
+IrLedProcessor::~IrLedProcessor() = default;
+
+void IrLedProcessor::StartProcessor() {}
+
+void IrLedProcessor::SuspendProcessor() {}
+
+void IrLedProcessor::StopProcessor() {}
+
+void IrLedProcessor::SetConfig(Core::IrSensor::PackedIrLedProcessorConfig config) {
+ current_config.light_target =
+ static_cast<Core::IrSensor::CameraLightTarget>(config.light_target);
+}
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irsensor/ir_led_processor.h b/src/core/hle/service/hid/irsensor/ir_led_processor.h
new file mode 100644
index 000000000..cb04d0b94
--- /dev/null
+++ b/src/core/hle/service/hid/irsensor/ir_led_processor.h
@@ -0,0 +1,47 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "core/hid/irs_types.h"
+#include "core/hle/service/hid/irsensor/processor_base.h"
+
+namespace Service::HID {
+class IrLedProcessor final : public ProcessorBase {
+public:
+ explicit IrLedProcessor(Core::IrSensor::DeviceFormat& device_format);
+ ~IrLedProcessor() override;
+
+ // Called when the processor is initialized
+ void StartProcessor() override;
+
+ // Called when the processor is suspended
+ void SuspendProcessor() override;
+
+ // Called when the processor is stopped
+ void StopProcessor() override;
+
+ // Sets config parameters of the camera
+ void SetConfig(Core::IrSensor::PackedIrLedProcessorConfig config);
+
+private:
+ // This is nn::irsensor::IrLedProcessorConfig
+ struct IrLedProcessorConfig {
+ Core::IrSensor::CameraLightTarget light_target;
+ };
+ static_assert(sizeof(IrLedProcessorConfig) == 0x4, "IrLedProcessorConfig is an invalid size");
+
+ struct IrLedProcessorState {
+ s64 sampling_number;
+ u64 timestamp;
+ std::array<u8, 0x8> data;
+ };
+ static_assert(sizeof(IrLedProcessorState) == 0x18, "IrLedProcessorState is an invalid size");
+
+ IrLedProcessorConfig current_config{};
+ Core::IrSensor::DeviceFormat& device;
+};
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irsensor/moment_processor.cpp b/src/core/hle/service/hid/irsensor/moment_processor.cpp
new file mode 100644
index 000000000..fb36be577
--- /dev/null
+++ b/src/core/hle/service/hid/irsensor/moment_processor.cpp
@@ -0,0 +1,36 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "core/hle/service/hid/irsensor/moment_processor.h"
+
+namespace Service::HID {
+MomentProcessor::MomentProcessor(Core::IrSensor::DeviceFormat& device_format)
+ : device(device_format) {
+ device.mode = Core::IrSensor::IrSensorMode::MomentProcessor;
+ device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
+ device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
+ device.state.start = 0;
+ device.state.count = 0;
+}
+
+MomentProcessor::~MomentProcessor() = default;
+
+void MomentProcessor::StartProcessor() {}
+
+void MomentProcessor::SuspendProcessor() {}
+
+void MomentProcessor::StopProcessor() {}
+
+void MomentProcessor::SetConfig(Core::IrSensor::PackedMomentProcessorConfig 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.preprocess =
+ static_cast<Core::IrSensor::MomentProcessorPreprocess>(config.preprocess);
+ current_config.preprocess_intensity_threshold = config.preprocess_intensity_threshold;
+}
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irsensor/moment_processor.h b/src/core/hle/service/hid/irsensor/moment_processor.h
new file mode 100644
index 000000000..63cdadfda
--- /dev/null
+++ b/src/core/hle/service/hid/irsensor/moment_processor.h
@@ -0,0 +1,61 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "core/hid/irs_types.h"
+#include "core/hle/service/hid/irsensor/processor_base.h"
+
+namespace Service::HID {
+class MomentProcessor final : public ProcessorBase {
+public:
+ explicit MomentProcessor(Core::IrSensor::DeviceFormat& device_format);
+ ~MomentProcessor() override;
+
+ // Called when the processor is initialized
+ void StartProcessor() override;
+
+ // Called when the processor is suspended
+ void SuspendProcessor() override;
+
+ // Called when the processor is stopped
+ void StopProcessor() override;
+
+ // Sets config parameters of the camera
+ void SetConfig(Core::IrSensor::PackedMomentProcessorConfig config);
+
+private:
+ // This is nn::irsensor::MomentProcessorConfig
+ struct MomentProcessorConfig {
+ Core::IrSensor::CameraConfig camera_config;
+ Core::IrSensor::IrsRect window_of_interest;
+ Core::IrSensor::MomentProcessorPreprocess preprocess;
+ u32 preprocess_intensity_threshold;
+ };
+ static_assert(sizeof(MomentProcessorConfig) == 0x28,
+ "MomentProcessorConfig is an invalid size");
+
+ // This is nn::irsensor::MomentStatistic
+ struct MomentStatistic {
+ f32 average_intensity;
+ Core::IrSensor::IrsCentroid centroid;
+ };
+ static_assert(sizeof(MomentStatistic) == 0xC, "MomentStatistic is an invalid size");
+
+ // This is nn::irsensor::MomentProcessorState
+ struct MomentProcessorState {
+ s64 sampling_number;
+ u64 timestamp;
+ Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level;
+ INSERT_PADDING_BYTES(4);
+ std::array<MomentStatistic, 0x30> stadistic;
+ };
+ static_assert(sizeof(MomentProcessorState) == 0x258, "MomentProcessorState is an invalid size");
+
+ MomentProcessorConfig current_config{};
+ Core::IrSensor::DeviceFormat& device;
+};
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irsensor/pointing_processor.cpp b/src/core/hle/service/hid/irsensor/pointing_processor.cpp
new file mode 100644
index 000000000..7eb123636
--- /dev/null
+++ b/src/core/hle/service/hid/irsensor/pointing_processor.cpp
@@ -0,0 +1,28 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "core/hle/service/hid/irsensor/pointing_processor.h"
+
+namespace Service::HID {
+PointingProcessor::PointingProcessor(Core::IrSensor::DeviceFormat& device_format)
+ : device(device_format) {
+ device.mode = Core::IrSensor::IrSensorMode::PointingProcessorMarker;
+ device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
+ device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
+ device.state.start = 0;
+ device.state.count = 0;
+}
+
+PointingProcessor::~PointingProcessor() = default;
+
+void PointingProcessor::StartProcessor() {}
+
+void PointingProcessor::SuspendProcessor() {}
+
+void PointingProcessor::StopProcessor() {}
+
+void PointingProcessor::SetConfig(Core::IrSensor::PackedPointingProcessorConfig config) {
+ current_config.window_of_interest = config.window_of_interest;
+}
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irsensor/pointing_processor.h b/src/core/hle/service/hid/irsensor/pointing_processor.h
new file mode 100644
index 000000000..2f67eff91
--- /dev/null
+++ b/src/core/hle/service/hid/irsensor/pointing_processor.h
@@ -0,0 +1,62 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "core/hid/irs_types.h"
+#include "core/hle/service/hid/irsensor/processor_base.h"
+
+namespace Service::HID {
+class PointingProcessor final : public ProcessorBase {
+public:
+ explicit PointingProcessor(Core::IrSensor::DeviceFormat& device_format);
+ ~PointingProcessor() override;
+
+ // Called when the processor is initialized
+ void StartProcessor() override;
+
+ // Called when the processor is suspended
+ void SuspendProcessor() override;
+
+ // Called when the processor is stopped
+ void StopProcessor() override;
+
+ // Sets config parameters of the camera
+ void SetConfig(Core::IrSensor::PackedPointingProcessorConfig config);
+
+private:
+ // This is nn::irsensor::PointingProcessorConfig
+ struct PointingProcessorConfig {
+ Core::IrSensor::IrsRect window_of_interest;
+ };
+ static_assert(sizeof(PointingProcessorConfig) == 0x8,
+ "PointingProcessorConfig is an invalid size");
+
+ struct PointingProcessorMarkerData {
+ u8 pointing_status;
+ INSERT_PADDING_BYTES(3);
+ u32 unknown;
+ float unkown_float1;
+ float position_x;
+ float position_y;
+ float unkown_float2;
+ Core::IrSensor::IrsRect window_of_interest;
+ };
+ static_assert(sizeof(PointingProcessorMarkerData) == 0x20,
+ "PointingProcessorMarkerData is an invalid size");
+
+ struct PointingProcessorMarkerState {
+ s64 sampling_number;
+ u64 timestamp;
+ std::array<PointingProcessorMarkerData, 0x3> data;
+ };
+ static_assert(sizeof(PointingProcessorMarkerState) == 0x70,
+ "PointingProcessorMarkerState is an invalid size");
+
+ PointingProcessorConfig current_config{};
+ Core::IrSensor::DeviceFormat& device;
+};
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irsensor/processor_base.cpp b/src/core/hle/service/hid/irsensor/processor_base.cpp
new file mode 100644
index 000000000..bc8025375
--- /dev/null
+++ b/src/core/hle/service/hid/irsensor/processor_base.cpp
@@ -0,0 +1,67 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "core/hle/service/hid/irsensor/processor_base.h"
+
+namespace Service::HID {
+
+ProcessorBase::ProcessorBase() {}
+ProcessorBase::~ProcessorBase() = default;
+
+bool ProcessorBase::IsProcessorActive() const {
+ return is_active;
+}
+
+std::size_t ProcessorBase::GetDataSize(Core::IrSensor::ImageTransferProcessorFormat format) const {
+ switch (format) {
+ case Core::IrSensor::ImageTransferProcessorFormat::Size320x240:
+ return 320 * 240;
+ case Core::IrSensor::ImageTransferProcessorFormat::Size160x120:
+ return 160 * 120;
+ case Core::IrSensor::ImageTransferProcessorFormat::Size80x60:
+ return 80 * 60;
+ case Core::IrSensor::ImageTransferProcessorFormat::Size40x30:
+ return 40 * 30;
+ case Core::IrSensor::ImageTransferProcessorFormat::Size20x15:
+ return 20 * 15;
+ default:
+ return 0;
+ }
+}
+
+std::size_t ProcessorBase::GetDataWidth(Core::IrSensor::ImageTransferProcessorFormat format) const {
+ switch (format) {
+ case Core::IrSensor::ImageTransferProcessorFormat::Size320x240:
+ return 320;
+ case Core::IrSensor::ImageTransferProcessorFormat::Size160x120:
+ return 160;
+ case Core::IrSensor::ImageTransferProcessorFormat::Size80x60:
+ return 80;
+ case Core::IrSensor::ImageTransferProcessorFormat::Size40x30:
+ return 40;
+ case Core::IrSensor::ImageTransferProcessorFormat::Size20x15:
+ return 20;
+ default:
+ return 0;
+ }
+}
+
+std::size_t ProcessorBase::GetDataHeight(
+ Core::IrSensor::ImageTransferProcessorFormat format) const {
+ switch (format) {
+ case Core::IrSensor::ImageTransferProcessorFormat::Size320x240:
+ return 240;
+ case Core::IrSensor::ImageTransferProcessorFormat::Size160x120:
+ return 120;
+ case Core::IrSensor::ImageTransferProcessorFormat::Size80x60:
+ return 60;
+ case Core::IrSensor::ImageTransferProcessorFormat::Size40x30:
+ return 30;
+ case Core::IrSensor::ImageTransferProcessorFormat::Size20x15:
+ return 15;
+ default:
+ return 0;
+ }
+}
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irsensor/processor_base.h b/src/core/hle/service/hid/irsensor/processor_base.h
new file mode 100644
index 000000000..49831aab6
--- /dev/null
+++ b/src/core/hle/service/hid/irsensor/processor_base.h
@@ -0,0 +1,33 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/hid/irs_types.h"
+
+namespace Service::HID {
+class ProcessorBase {
+public:
+ explicit ProcessorBase();
+ virtual ~ProcessorBase();
+
+ virtual void StartProcessor() = 0;
+ virtual void SuspendProcessor() = 0;
+ virtual void StopProcessor() = 0;
+
+ bool IsProcessorActive() const;
+
+protected:
+ /// Returns the number of bytes the image uses
+ std::size_t GetDataSize(Core::IrSensor::ImageTransferProcessorFormat format) const;
+
+ /// Returns the width of the image
+ std::size_t GetDataWidth(Core::IrSensor::ImageTransferProcessorFormat format) const;
+
+ /// Returns the height of the image
+ std::size_t GetDataHeight(Core::IrSensor::ImageTransferProcessorFormat format) const;
+
+ bool is_active{false};
+};
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp b/src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp
new file mode 100644
index 000000000..deec22072
--- /dev/null
+++ b/src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp
@@ -0,0 +1,31 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "core/hle/service/hid/irsensor/tera_plugin_processor.h"
+
+namespace Service::HID {
+TeraPluginProcessor::TeraPluginProcessor(Core::IrSensor::DeviceFormat& device_format)
+ : device(device_format) {
+ device.mode = Core::IrSensor::IrSensorMode::TeraPluginProcessor;
+ device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected;
+ device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped;
+ device.state.start = 0;
+ device.state.count = 0;
+}
+
+TeraPluginProcessor::~TeraPluginProcessor() = default;
+
+void TeraPluginProcessor::StartProcessor() {}
+
+void TeraPluginProcessor::SuspendProcessor() {}
+
+void TeraPluginProcessor::StopProcessor() {}
+
+void TeraPluginProcessor::SetConfig(Core::IrSensor::PackedTeraPluginProcessorConfig config) {
+ current_config.mode = config.mode;
+ current_config.unknown_1 = config.unknown_1;
+ current_config.unknown_2 = config.unknown_2;
+ current_config.unknown_3 = config.unknown_3;
+}
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irsensor/tera_plugin_processor.h b/src/core/hle/service/hid/irsensor/tera_plugin_processor.h
new file mode 100644
index 000000000..60f8057a5
--- /dev/null
+++ b/src/core/hle/service/hid/irsensor/tera_plugin_processor.h
@@ -0,0 +1,53 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "core/hid/irs_types.h"
+#include "core/hle/service/hid/irsensor/processor_base.h"
+
+namespace Service::HID {
+class TeraPluginProcessor final : public ProcessorBase {
+public:
+ explicit TeraPluginProcessor(Core::IrSensor::DeviceFormat& device_format);
+ ~TeraPluginProcessor() override;
+
+ // Called when the processor is initialized
+ void StartProcessor() override;
+
+ // Called when the processor is suspended
+ void SuspendProcessor() override;
+
+ // Called when the processor is stopped
+ void StopProcessor() override;
+
+ // Sets config parameters of the camera
+ void SetConfig(Core::IrSensor::PackedTeraPluginProcessorConfig config);
+
+private:
+ // This is nn::irsensor::TeraPluginProcessorConfig
+ struct TeraPluginProcessorConfig {
+ u8 mode;
+ u8 unknown_1;
+ u8 unknown_2;
+ u8 unknown_3;
+ };
+ static_assert(sizeof(TeraPluginProcessorConfig) == 0x4,
+ "TeraPluginProcessorConfig is an invalid size");
+
+ struct TeraPluginProcessorState {
+ s64 sampling_number;
+ u64 timestamp;
+ Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level;
+ std::array<u8, 0x12c> data;
+ };
+ static_assert(sizeof(TeraPluginProcessorState) == 0x140,
+ "TeraPluginProcessorState is an invalid size");
+
+ TeraPluginProcessorConfig current_config{};
+ Core::IrSensor::DeviceFormat& device;
+};
+
+} // namespace Service::HID