summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hid/emulated_controller.cpp21
-rw-r--r--src/core/hid/emulated_controller.h5
-rw-r--r--src/core/hle/service/hid/irs.cpp11
-rw-r--r--src/input_common/CMakeLists.txt2
-rw-r--r--src/input_common/drivers/joycon.cpp29
-rw-r--r--src/input_common/drivers/joycon.h5
-rw-r--r--src/input_common/helpers/joycon_driver.cpp55
-rw-r--r--src/input_common/helpers/joycon_driver.h4
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.cpp13
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.h7
-rw-r--r--src/input_common/helpers/joycon_protocol/irs.cpp300
-rw-r--r--src/input_common/helpers/joycon_protocol/irs.h63
-rw-r--r--src/input_common/helpers/joycon_protocol/joycon_types.h107
-rw-r--r--src/input_common/helpers/joycon_protocol/poller.cpp6
-rw-r--r--src/input_common/helpers/joycon_protocol/poller.h3
15 files changed, 608 insertions, 23 deletions
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 915ffa490..faf9e7c4e 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -145,7 +145,9 @@ void EmulatedController::LoadDevices() {
145 battery_params[LeftIndex].Set("battery", true); 145 battery_params[LeftIndex].Set("battery", true);
146 battery_params[RightIndex].Set("battery", true); 146 battery_params[RightIndex].Set("battery", true);
147 147
148 camera_params = Common::ParamPackage{"engine:camera,camera:1"}; 148 camera_params[0] = right_joycon;
149 camera_params[0].Set("camera", true);
150 camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"};
149 ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"}; 151 ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"};
150 nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"}; 152 nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"};
151 nfc_params[1] = right_joycon; 153 nfc_params[1] = right_joycon;
@@ -153,7 +155,7 @@ void EmulatedController::LoadDevices() {
153 155
154 output_params[LeftIndex] = left_joycon; 156 output_params[LeftIndex] = left_joycon;
155 output_params[RightIndex] = right_joycon; 157 output_params[RightIndex] = right_joycon;
156 output_params[2] = camera_params; 158 output_params[2] = camera_params[1];
157 output_params[3] = nfc_params[0]; 159 output_params[3] = nfc_params[0];
158 output_params[LeftIndex].Set("output", true); 160 output_params[LeftIndex].Set("output", true);
159 output_params[RightIndex].Set("output", true); 161 output_params[RightIndex].Set("output", true);
@@ -171,7 +173,7 @@ void EmulatedController::LoadDevices() {
171 std::ranges::transform(battery_params, battery_devices.begin(), 173 std::ranges::transform(battery_params, battery_devices.begin(),
172 Common::Input::CreateInputDevice); 174 Common::Input::CreateInputDevice);
173 std::ranges::transform(color_params, color_devices.begin(), Common::Input::CreateInputDevice); 175 std::ranges::transform(color_params, color_devices.begin(), Common::Input::CreateInputDevice);
174 camera_devices = Common::Input::CreateInputDevice(camera_params); 176 std::ranges::transform(camera_params, camera_devices.begin(), Common::Input::CreateInputDevice);
175 std::ranges::transform(ring_params, ring_analog_devices.begin(), 177 std::ranges::transform(ring_params, ring_analog_devices.begin(),
176 Common::Input::CreateInputDevice); 178 Common::Input::CreateInputDevice);
177 std::ranges::transform(nfc_params, nfc_devices.begin(), Common::Input::CreateInputDevice); 179 std::ranges::transform(nfc_params, nfc_devices.begin(), Common::Input::CreateInputDevice);
@@ -362,12 +364,15 @@ void EmulatedController::ReloadInput() {
362 motion_devices[index]->ForceUpdate(); 364 motion_devices[index]->ForceUpdate();
363 } 365 }
364 366
365 if (camera_devices) { 367 for (std::size_t index = 0; index < camera_devices.size(); ++index) {
366 camera_devices->SetCallback({ 368 if (!camera_devices[index]) {
369 continue;
370 }
371 camera_devices[index]->SetCallback({
367 .on_change = 372 .on_change =
368 [this](const Common::Input::CallbackStatus& callback) { SetCamera(callback); }, 373 [this](const Common::Input::CallbackStatus& callback) { SetCamera(callback); },
369 }); 374 });
370 camera_devices->ForceUpdate(); 375 camera_devices[index]->ForceUpdate();
371 } 376 }
372 377
373 for (std::size_t index = 0; index < ring_analog_devices.size(); ++index) { 378 for (std::size_t index = 0; index < ring_analog_devices.size(); ++index) {
@@ -477,7 +482,9 @@ void EmulatedController::UnloadInput() {
477 for (auto& stick : virtual_stick_devices) { 482 for (auto& stick : virtual_stick_devices) {
478 stick.reset(); 483 stick.reset();
479 } 484 }
480 camera_devices.reset(); 485 for (auto& camera : camera_devices) {
486 camera.reset();
487 }
481 for (auto& ring : ring_analog_devices) { 488 for (auto& ring : ring_analog_devices) {
482 ring.reset(); 489 ring.reset();
483 } 490 }
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index fb931fc0a..edebfc15c 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -39,7 +39,8 @@ using ColorDevices =
39 std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>; 39 std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
40using BatteryDevices = 40using BatteryDevices =
41 std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>; 41 std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
42using CameraDevices = std::unique_ptr<Common::Input::InputDevice>; 42using CameraDevices =
43 std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
43using RingAnalogDevices = 44using RingAnalogDevices =
44 std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>; 45 std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
45using NfcDevices = 46using NfcDevices =
@@ -52,7 +53,7 @@ using ControllerMotionParams = std::array<Common::ParamPackage, Settings::Native
52using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>; 53using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>;
53using ColorParams = std::array<Common::ParamPackage, max_emulated_controllers>; 54using ColorParams = std::array<Common::ParamPackage, max_emulated_controllers>;
54using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>; 55using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>;
55using CameraParams = Common::ParamPackage; 56using CameraParams = std::array<Common::ParamPackage, max_emulated_controllers>;
56using RingAnalogParams = std::array<Common::ParamPackage, max_emulated_controllers>; 57using RingAnalogParams = std::array<Common::ParamPackage, max_emulated_controllers>;
57using NfcParams = std::array<Common::ParamPackage, max_emulated_controllers>; 58using NfcParams = std::array<Common::ParamPackage, max_emulated_controllers>;
58using OutputParams = std::array<Common::ParamPackage, output_devices_size>; 59using OutputParams = std::array<Common::ParamPackage, output_devices_size>;
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index 6a3453457..3c1fa2274 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -74,6 +74,8 @@ void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) {
74 LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}", 74 LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}",
75 applet_resource_user_id); 75 applet_resource_user_id);
76 76
77 npad_device->SetPollingMode(Common::Input::PollingMode::Active);
78
77 IPC::ResponseBuilder rb{ctx, 2}; 79 IPC::ResponseBuilder rb{ctx, 2};
78 rb.Push(ResultSuccess); 80 rb.Push(ResultSuccess);
79} 81}
@@ -108,6 +110,7 @@ void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
108 auto result = IsIrCameraHandleValid(parameters.camera_handle); 110 auto result = IsIrCameraHandleValid(parameters.camera_handle);
109 if (result.IsSuccess()) { 111 if (result.IsSuccess()) {
110 // TODO: Stop Image processor 112 // TODO: Stop Image processor
113 npad_device->SetPollingMode(Common::Input::PollingMode::Active);
111 result = ResultSuccess; 114 result = ResultSuccess;
112 } 115 }
113 116
@@ -139,6 +142,7 @@ void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) {
139 MakeProcessor<MomentProcessor>(parameters.camera_handle, device); 142 MakeProcessor<MomentProcessor>(parameters.camera_handle, device);
140 auto& image_transfer_processor = GetProcessor<MomentProcessor>(parameters.camera_handle); 143 auto& image_transfer_processor = GetProcessor<MomentProcessor>(parameters.camera_handle);
141 image_transfer_processor.SetConfig(parameters.processor_config); 144 image_transfer_processor.SetConfig(parameters.processor_config);
145 npad_device->SetPollingMode(Common::Input::PollingMode::IR);
142 } 146 }
143 147
144 IPC::ResponseBuilder rb{ctx, 2}; 148 IPC::ResponseBuilder rb{ctx, 2};
@@ -170,6 +174,7 @@ void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) {
170 auto& image_transfer_processor = 174 auto& image_transfer_processor =
171 GetProcessor<ClusteringProcessor>(parameters.camera_handle); 175 GetProcessor<ClusteringProcessor>(parameters.camera_handle);
172 image_transfer_processor.SetConfig(parameters.processor_config); 176 image_transfer_processor.SetConfig(parameters.processor_config);
177 npad_device->SetPollingMode(Common::Input::PollingMode::IR);
173 } 178 }
174 179
175 IPC::ResponseBuilder rb{ctx, 2}; 180 IPC::ResponseBuilder rb{ctx, 2};
@@ -219,6 +224,7 @@ void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
219 GetProcessor<ImageTransferProcessor>(parameters.camera_handle); 224 GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
220 image_transfer_processor.SetConfig(parameters.processor_config); 225 image_transfer_processor.SetConfig(parameters.processor_config);
221 image_transfer_processor.SetTransferMemoryPointer(transfer_memory); 226 image_transfer_processor.SetTransferMemoryPointer(transfer_memory);
227 npad_device->SetPollingMode(Common::Input::PollingMode::IR);
222 } 228 }
223 229
224 IPC::ResponseBuilder rb{ctx, 2}; 230 IPC::ResponseBuilder rb{ctx, 2};
@@ -294,6 +300,7 @@ void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) {
294 auto& image_transfer_processor = 300 auto& image_transfer_processor =
295 GetProcessor<TeraPluginProcessor>(parameters.camera_handle); 301 GetProcessor<TeraPluginProcessor>(parameters.camera_handle);
296 image_transfer_processor.SetConfig(parameters.processor_config); 302 image_transfer_processor.SetConfig(parameters.processor_config);
303 npad_device->SetPollingMode(Common::Input::PollingMode::IR);
297 } 304 }
298 305
299 IPC::ResponseBuilder rb{ctx, 2}; 306 IPC::ResponseBuilder rb{ctx, 2};
@@ -343,6 +350,7 @@ void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) {
343 MakeProcessor<PointingProcessor>(camera_handle, device); 350 MakeProcessor<PointingProcessor>(camera_handle, device);
344 auto& image_transfer_processor = GetProcessor<PointingProcessor>(camera_handle); 351 auto& image_transfer_processor = GetProcessor<PointingProcessor>(camera_handle);
345 image_transfer_processor.SetConfig(processor_config); 352 image_transfer_processor.SetConfig(processor_config);
353 npad_device->SetPollingMode(Common::Input::PollingMode::IR);
346 } 354 }
347 355
348 IPC::ResponseBuilder rb{ctx, 2}; 356 IPC::ResponseBuilder rb{ctx, 2};
@@ -453,6 +461,7 @@ void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) {
453 GetProcessor<ImageTransferProcessor>(parameters.camera_handle); 461 GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
454 image_transfer_processor.SetConfig(parameters.processor_config); 462 image_transfer_processor.SetConfig(parameters.processor_config);
455 image_transfer_processor.SetTransferMemoryPointer(transfer_memory); 463 image_transfer_processor.SetTransferMemoryPointer(transfer_memory);
464 npad_device->SetPollingMode(Common::Input::PollingMode::IR);
456 } 465 }
457 466
458 IPC::ResponseBuilder rb{ctx, 2}; 467 IPC::ResponseBuilder rb{ctx, 2};
@@ -479,6 +488,7 @@ void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) {
479 MakeProcessor<IrLedProcessor>(camera_handle, device); 488 MakeProcessor<IrLedProcessor>(camera_handle, device);
480 auto& image_transfer_processor = GetProcessor<IrLedProcessor>(camera_handle); 489 auto& image_transfer_processor = GetProcessor<IrLedProcessor>(camera_handle);
481 image_transfer_processor.SetConfig(processor_config); 490 image_transfer_processor.SetConfig(processor_config);
491 npad_device->SetPollingMode(Common::Input::PollingMode::IR);
482 } 492 }
483 493
484 IPC::ResponseBuilder rb{ctx, 2}; 494 IPC::ResponseBuilder rb{ctx, 2};
@@ -504,6 +514,7 @@ void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) {
504 auto result = IsIrCameraHandleValid(parameters.camera_handle); 514 auto result = IsIrCameraHandleValid(parameters.camera_handle);
505 if (result.IsSuccess()) { 515 if (result.IsSuccess()) {
506 // TODO: Stop image processor async 516 // TODO: Stop image processor async
517 npad_device->SetPollingMode(Common::Input::PollingMode::IR);
507 result = ResultSuccess; 518 result = ResultSuccess;
508 } 519 }
509 520
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt
index 9c901af2a..e3b627e4f 100644
--- a/src/input_common/CMakeLists.txt
+++ b/src/input_common/CMakeLists.txt
@@ -64,6 +64,8 @@ if (ENABLE_SDL2)
64 helpers/joycon_protocol/generic_functions.cpp 64 helpers/joycon_protocol/generic_functions.cpp
65 helpers/joycon_protocol/generic_functions.h 65 helpers/joycon_protocol/generic_functions.h
66 helpers/joycon_protocol/joycon_types.h 66 helpers/joycon_protocol/joycon_types.h
67 helpers/joycon_protocol/irs.cpp
68 helpers/joycon_protocol/irs.h
67 helpers/joycon_protocol/nfc.cpp 69 helpers/joycon_protocol/nfc.cpp
68 helpers/joycon_protocol/nfc.h 70 helpers/joycon_protocol/nfc.h
69 helpers/joycon_protocol/poller.cpp 71 helpers/joycon_protocol/poller.cpp
diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp
index cf54f1b53..6c03e0953 100644
--- a/src/input_common/drivers/joycon.cpp
+++ b/src/input_common/drivers/joycon.cpp
@@ -191,6 +191,10 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) {
191 .on_amiibo_data = {[this, port](const std::vector<u8>& amiibo_data) { 191 .on_amiibo_data = {[this, port](const std::vector<u8>& amiibo_data) {
192 OnAmiiboUpdate(port, amiibo_data); 192 OnAmiiboUpdate(port, amiibo_data);
193 }}, 193 }},
194 .on_camera_data = {[this, port](const std::vector<u8>& camera_data,
195 Joycon::IrsResolution format) {
196 OnCameraUpdate(port, camera_data, format);
197 }},
194 }; 198 };
195 199
196 handle->InitializeDevice(); 200 handle->InitializeDevice();
@@ -265,9 +269,14 @@ Common::Input::DriverResult Joycons::SetLeds(const PadIdentifier& identifier,
265 handle->SetLedConfig(static_cast<u8>(led_config))); 269 handle->SetLedConfig(static_cast<u8>(led_config)));
266} 270}
267 271
268Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier_, 272Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier,
269 Common::Input::CameraFormat camera_format) { 273 Common::Input::CameraFormat camera_format) {
270 return Common::Input::DriverResult::NotSupported; 274 auto handle = GetHandle(identifier);
275 if (handle == nullptr) {
276 return Common::Input::DriverResult::InvalidHandle;
277 }
278 return static_cast<Common::Input::DriverResult>(handle->SetIrsConfig(
279 Joycon::IrsMode::ImageTransfer, static_cast<Joycon::IrsResolution>(camera_format)));
271}; 280};
272 281
273Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) const { 282Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) const {
@@ -288,18 +297,16 @@ Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identif
288 } 297 }
289 298
290 switch (polling_mode) { 299 switch (polling_mode) {
291 case Common::Input::PollingMode::NFC:
292 return static_cast<Common::Input::DriverResult>(handle->SetNfcMode());
293 break;
294 case Common::Input::PollingMode::Active: 300 case Common::Input::PollingMode::Active:
295 return static_cast<Common::Input::DriverResult>(handle->SetActiveMode()); 301 return static_cast<Common::Input::DriverResult>(handle->SetActiveMode());
296 break;
297 case Common::Input::PollingMode::Pasive: 302 case Common::Input::PollingMode::Pasive:
298 return static_cast<Common::Input::DriverResult>(handle->SetPasiveMode()); 303 return static_cast<Common::Input::DriverResult>(handle->SetPasiveMode());
299 break; 304 case Common::Input::PollingMode::IR:
305 return static_cast<Common::Input::DriverResult>(handle->SetIrMode());
306 case Common::Input::PollingMode::NFC:
307 return static_cast<Common::Input::DriverResult>(handle->SetNfcMode());
300 case Common::Input::PollingMode::Ring: 308 case Common::Input::PollingMode::Ring:
301 return static_cast<Common::Input::DriverResult>(handle->SetRingConMode()); 309 return static_cast<Common::Input::DriverResult>(handle->SetRingConMode());
302 break;
303 default: 310 default:
304 return Common::Input::DriverResult::NotSupported; 311 return Common::Input::DriverResult::NotSupported;
305 } 312 }
@@ -390,6 +397,12 @@ void Joycons::OnAmiiboUpdate(std::size_t port, const std::vector<u8>& amiibo_dat
390 SetNfc(identifier, {nfc_state, amiibo_data}); 397 SetNfc(identifier, {nfc_state, amiibo_data});
391} 398}
392 399
400void Joycons::OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data,
401 Joycon::IrsResolution format) {
402 const auto identifier = GetIdentifier(port, Joycon::ControllerType::Right);
403 SetCamera(identifier, {static_cast<Common::Input::CameraFormat>(format), camera_data});
404}
405
393std::shared_ptr<Joycon::JoyconDriver> Joycons::GetHandle(PadIdentifier identifier) const { 406std::shared_ptr<Joycon::JoyconDriver> Joycons::GetHandle(PadIdentifier identifier) const {
394 auto is_handle_active = [&](std::shared_ptr<Joycon::JoyconDriver> device) { 407 auto is_handle_active = [&](std::shared_ptr<Joycon::JoyconDriver> device) {
395 if (!device) { 408 if (!device) {
diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h
index 1a04c19fd..f180b7478 100644
--- a/src/input_common/drivers/joycon.h
+++ b/src/input_common/drivers/joycon.h
@@ -17,6 +17,7 @@ struct Color;
17struct MotionData; 17struct MotionData;
18enum class ControllerType; 18enum class ControllerType;
19enum class DriverResult; 19enum class DriverResult;
20enum class IrsResolution;
20class JoyconDriver; 21class JoyconDriver;
21} // namespace InputCommon::Joycon 22} // namespace InputCommon::Joycon
22 23
@@ -35,7 +36,7 @@ public:
35 Common::Input::DriverResult SetLeds(const PadIdentifier& identifier, 36 Common::Input::DriverResult SetLeds(const PadIdentifier& identifier,
36 const Common::Input::LedStatus& led_status) override; 37 const Common::Input::LedStatus& led_status) override;
37 38
38 Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier_, 39 Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier,
39 Common::Input::CameraFormat camera_format) override; 40 Common::Input::CameraFormat camera_format) override;
40 41
41 Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; 42 Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override;
@@ -81,6 +82,8 @@ private:
81 const Joycon::MotionData& value); 82 const Joycon::MotionData& value);
82 void OnRingConUpdate(f32 ring_data); 83 void OnRingConUpdate(f32 ring_data);
83 void OnAmiiboUpdate(std::size_t port, const std::vector<u8>& amiibo_data); 84 void OnAmiiboUpdate(std::size_t port, const std::vector<u8>& amiibo_data);
85 void OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data,
86 Joycon::IrsResolution format);
84 87
85 /// Returns a JoyconHandle corresponding to a PadIdentifier 88 /// Returns a JoyconHandle corresponding to a PadIdentifier
86 std::shared_ptr<Joycon::JoyconDriver> GetHandle(PadIdentifier identifier) const; 89 std::shared_ptr<Joycon::JoyconDriver> GetHandle(PadIdentifier identifier) const;
diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp
index 8217ba7f6..040832a4b 100644
--- a/src/input_common/helpers/joycon_driver.cpp
+++ b/src/input_common/helpers/joycon_driver.cpp
@@ -7,6 +7,7 @@
7#include "input_common/helpers/joycon_driver.h" 7#include "input_common/helpers/joycon_driver.h"
8#include "input_common/helpers/joycon_protocol/calibration.h" 8#include "input_common/helpers/joycon_protocol/calibration.h"
9#include "input_common/helpers/joycon_protocol/generic_functions.h" 9#include "input_common/helpers/joycon_protocol/generic_functions.h"
10#include "input_common/helpers/joycon_protocol/irs.h"
10#include "input_common/helpers/joycon_protocol/nfc.h" 11#include "input_common/helpers/joycon_protocol/nfc.h"
11#include "input_common/helpers/joycon_protocol/poller.h" 12#include "input_common/helpers/joycon_protocol/poller.h"
12#include "input_common/helpers/joycon_protocol/ringcon.h" 13#include "input_common/helpers/joycon_protocol/ringcon.h"
@@ -78,6 +79,7 @@ DriverResult JoyconDriver::InitializeDevice() {
78 // Initialize HW Protocols 79 // Initialize HW Protocols
79 calibration_protocol = std::make_unique<CalibrationProtocol>(hidapi_handle); 80 calibration_protocol = std::make_unique<CalibrationProtocol>(hidapi_handle);
80 generic_protocol = std::make_unique<GenericProtocol>(hidapi_handle); 81 generic_protocol = std::make_unique<GenericProtocol>(hidapi_handle);
82 irs_protocol = std::make_unique<IrsProtocol>(hidapi_handle);
81 nfc_protocol = std::make_unique<NfcProtocol>(hidapi_handle); 83 nfc_protocol = std::make_unique<NfcProtocol>(hidapi_handle);
82 ring_protocol = std::make_unique<RingConProtocol>(hidapi_handle); 84 ring_protocol = std::make_unique<RingConProtocol>(hidapi_handle);
83 rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle); 85 rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle);
@@ -200,10 +202,15 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
200 .min_value = ring_calibration.min_value, 202 .min_value = ring_calibration.min_value,
201 }; 203 };
202 204
205 if (irs_protocol->IsEnabled()) {
206 irs_protocol->RequestImage(buffer);
207 joycon_poller->UpdateCamera(irs_protocol->GetImage(), irs_protocol->GetIrsFormat());
208 }
209
203 if (nfc_protocol->IsEnabled()) { 210 if (nfc_protocol->IsEnabled()) {
204 if (amiibo_detected) { 211 if (amiibo_detected) {
205 if (!nfc_protocol->HasAmiibo()) { 212 if (!nfc_protocol->HasAmiibo()) {
206 joycon_poller->updateAmiibo({}); 213 joycon_poller->UpdateAmiibo({});
207 amiibo_detected = false; 214 amiibo_detected = false;
208 return; 215 return;
209 } 216 }
@@ -213,7 +220,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
213 std::vector<u8> data(0x21C); 220 std::vector<u8> data(0x21C);
214 const auto result = nfc_protocol->ScanAmiibo(data); 221 const auto result = nfc_protocol->ScanAmiibo(data);
215 if (result == DriverResult::Success) { 222 if (result == DriverResult::Success) {
216 joycon_poller->updateAmiibo(data); 223 joycon_poller->UpdateAmiibo(data);
217 amiibo_detected = true; 224 amiibo_detected = true;
218 } 225 }
219 } 226 }
@@ -251,6 +258,20 @@ DriverResult JoyconDriver::SetPollingMode() {
251 generic_protocol->EnableImu(false); 258 generic_protocol->EnableImu(false);
252 } 259 }
253 260
261 if (irs_protocol->IsEnabled()) {
262 irs_protocol->DisableIrs();
263 }
264
265 if (irs_enabled && supported_features.irs) {
266 auto result = irs_protocol->EnableIrs();
267 if (result == DriverResult::Success) {
268 disable_input_thread = false;
269 return result;
270 }
271 irs_protocol->DisableIrs();
272 LOG_ERROR(Input, "Error enabling IRS");
273 }
274
254 if (nfc_protocol->IsEnabled()) { 275 if (nfc_protocol->IsEnabled()) {
255 amiibo_detected = false; 276 amiibo_detected = false;
256 nfc_protocol->DisableNfc(); 277 nfc_protocol->DisableNfc();
@@ -375,12 +396,24 @@ DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) {
375 return generic_protocol->SetLedPattern(led_pattern); 396 return generic_protocol->SetLedPattern(led_pattern);
376} 397}
377 398
399DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) {
400 std::scoped_lock lock{mutex};
401 if (disable_input_thread) {
402 return DriverResult::HandleInUse;
403 }
404 disable_input_thread = true;
405 const auto result = irs_protocol->SetIrsConfig(mode_, format_);
406 disable_input_thread = false;
407 return result;
408}
409
378DriverResult JoyconDriver::SetPasiveMode() { 410DriverResult JoyconDriver::SetPasiveMode() {
379 std::scoped_lock lock{mutex}; 411 std::scoped_lock lock{mutex};
380 motion_enabled = false; 412 motion_enabled = false;
381 hidbus_enabled = false; 413 hidbus_enabled = false;
382 nfc_enabled = false; 414 nfc_enabled = false;
383 passive_enabled = true; 415 passive_enabled = true;
416 irs_enabled = false;
384 return SetPollingMode(); 417 return SetPollingMode();
385} 418}
386 419
@@ -390,6 +423,22 @@ DriverResult JoyconDriver::SetActiveMode() {
390 hidbus_enabled = false; 423 hidbus_enabled = false;
391 nfc_enabled = false; 424 nfc_enabled = false;
392 passive_enabled = false; 425 passive_enabled = false;
426 irs_enabled = false;
427 return SetPollingMode();
428}
429
430DriverResult JoyconDriver::SetIrMode() {
431 std::scoped_lock lock{mutex};
432
433 if (!supported_features.irs) {
434 return DriverResult::NotSupported;
435 }
436
437 motion_enabled = false;
438 hidbus_enabled = false;
439 nfc_enabled = false;
440 passive_enabled = false;
441 irs_enabled = true;
393 return SetPollingMode(); 442 return SetPollingMode();
394} 443}
395 444
@@ -404,6 +453,7 @@ DriverResult JoyconDriver::SetNfcMode() {
404 hidbus_enabled = false; 453 hidbus_enabled = false;
405 nfc_enabled = true; 454 nfc_enabled = true;
406 passive_enabled = false; 455 passive_enabled = false;
456 irs_enabled = false;
407 return SetPollingMode(); 457 return SetPollingMode();
408} 458}
409 459
@@ -418,6 +468,7 @@ DriverResult JoyconDriver::SetRingConMode() {
418 hidbus_enabled = true; 468 hidbus_enabled = true;
419 nfc_enabled = false; 469 nfc_enabled = false;
420 passive_enabled = false; 470 passive_enabled = false;
471 irs_enabled = false;
421 472
422 const auto result = SetPollingMode(); 473 const auto result = SetPollingMode();
423 474
diff --git a/src/input_common/helpers/joycon_driver.h b/src/input_common/helpers/joycon_driver.h
index 5ff15c784..61ecf4a6c 100644
--- a/src/input_common/helpers/joycon_driver.h
+++ b/src/input_common/helpers/joycon_driver.h
@@ -13,6 +13,7 @@
13namespace InputCommon::Joycon { 13namespace InputCommon::Joycon {
14class CalibrationProtocol; 14class CalibrationProtocol;
15class GenericProtocol; 15class GenericProtocol;
16class IrsProtocol;
16class NfcProtocol; 17class NfcProtocol;
17class JoyconPoller; 18class JoyconPoller;
18class RingConProtocol; 19class RingConProtocol;
@@ -41,8 +42,10 @@ public:
41 42
42 DriverResult SetVibration(const VibrationValue& vibration); 43 DriverResult SetVibration(const VibrationValue& vibration);
43 DriverResult SetLedConfig(u8 led_pattern); 44 DriverResult SetLedConfig(u8 led_pattern);
45 DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_);
44 DriverResult SetPasiveMode(); 46 DriverResult SetPasiveMode();
45 DriverResult SetActiveMode(); 47 DriverResult SetActiveMode();
48 DriverResult SetIrMode();
46 DriverResult SetNfcMode(); 49 DriverResult SetNfcMode();
47 DriverResult SetRingConMode(); 50 DriverResult SetRingConMode();
48 51
@@ -87,6 +90,7 @@ private:
87 // Protocol Features 90 // Protocol Features
88 std::unique_ptr<CalibrationProtocol> calibration_protocol; 91 std::unique_ptr<CalibrationProtocol> calibration_protocol;
89 std::unique_ptr<GenericProtocol> generic_protocol; 92 std::unique_ptr<GenericProtocol> generic_protocol;
93 std::unique_ptr<IrsProtocol> irs_protocol;
90 std::unique_ptr<NfcProtocol> nfc_protocol; 94 std::unique_ptr<NfcProtocol> nfc_protocol;
91 std::unique_ptr<JoyconPoller> joycon_poller; 95 std::unique_ptr<JoyconPoller> joycon_poller;
92 std::unique_ptr<RingConProtocol> ring_protocol; 96 std::unique_ptr<RingConProtocol> ring_protocol;
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
index a4d08fdaf..a329db107 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
@@ -120,6 +120,19 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const
120 return DriverResult::Success; 120 return DriverResult::Success;
121} 121}
122 122
123DriverResult JoyconCommonProtocol::SendMcuCommand(SubCommand sc, std::span<const u8> buffer) {
124 std::vector<u8> local_buffer(MaxResponseSize);
125
126 local_buffer[0] = static_cast<u8>(OutputReport::MCU_DATA);
127 local_buffer[1] = GetCounter();
128 local_buffer[10] = static_cast<u8>(sc);
129 for (std::size_t i = 0; i < buffer.size(); ++i) {
130 local_buffer[11 + i] = buffer[i];
131 }
132
133 return SendData(local_buffer);
134}
135
123DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) { 136DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) {
124 std::vector<u8> local_buffer(MaxResponseSize); 137 std::vector<u8> local_buffer(MaxResponseSize);
125 138
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.h b/src/input_common/helpers/joycon_protocol/common_protocol.h
index a65e4aa76..2a3feaf59 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.h
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.h
@@ -75,6 +75,13 @@ public:
75 DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer, std::vector<u8>& output); 75 DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer, std::vector<u8>& output);
76 76
77 /** 77 /**
78 * Sends a mcu command to the device
79 * @param sc sub command to be send
80 * @param buffer data to be send
81 */
82 DriverResult SendMcuCommand(SubCommand sc, std::span<const u8> buffer);
83
84 /**
78 * Sends vibration data to the joycon 85 * Sends vibration data to the joycon
79 * @param buffer data to be send 86 * @param buffer data to be send
80 */ 87 */
diff --git a/src/input_common/helpers/joycon_protocol/irs.cpp b/src/input_common/helpers/joycon_protocol/irs.cpp
new file mode 100644
index 000000000..9dfa503c2
--- /dev/null
+++ b/src/input_common/helpers/joycon_protocol/irs.cpp
@@ -0,0 +1,300 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <thread>
5#include "common/logging/log.h"
6#include "input_common/helpers/joycon_protocol/irs.h"
7
8namespace InputCommon::Joycon {
9
10IrsProtocol::IrsProtocol(std::shared_ptr<JoyconHandle> handle)
11 : JoyconCommonProtocol(std::move(handle)) {}
12
13DriverResult IrsProtocol::EnableIrs() {
14 LOG_INFO(Input, "Enable IRS");
15 DriverResult result{DriverResult::Success};
16 SetBlocking();
17
18 if (result == DriverResult::Success) {
19 result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ);
20 }
21 if (result == DriverResult::Success) {
22 result = EnableMCU(true);
23 }
24 if (result == DriverResult::Success) {
25 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby);
26 }
27 if (result == DriverResult::Success) {
28 const MCUConfig config{
29 .command = MCUCommand::ConfigureMCU,
30 .sub_command = MCUSubCommand::SetMCUMode,
31 .mode = MCUMode::IR,
32 .crc = {},
33 };
34
35 result = ConfigureMCU(config);
36 }
37 if (result == DriverResult::Success) {
38 result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::IR);
39 }
40 if (result == DriverResult::Success) {
41 result = ConfigureIrs();
42 }
43 if (result == DriverResult::Success) {
44 result = WriteRegistersStep1();
45 }
46 if (result == DriverResult::Success) {
47 result = WriteRegistersStep2();
48 }
49
50 is_enabled = true;
51
52 SetNonBlocking();
53 return result;
54}
55
56DriverResult IrsProtocol::DisableIrs() {
57 LOG_DEBUG(Input, "Disable IRS");
58 DriverResult result{DriverResult::Success};
59 SetBlocking();
60
61 if (result == DriverResult::Success) {
62 result = EnableMCU(false);
63 }
64
65 is_enabled = false;
66
67 SetNonBlocking();
68 return result;
69}
70
71DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) {
72 irs_mode = mode;
73 switch (format) {
74 case IrsResolution::Size320x240:
75 resolution_code = IrsResolutionCode::Size320x240;
76 fragments = IrsFragments::Size320x240;
77 resolution = IrsResolution::Size320x240;
78 break;
79 case IrsResolution::Size160x120:
80 resolution_code = IrsResolutionCode::Size160x120;
81 fragments = IrsFragments::Size160x120;
82 resolution = IrsResolution::Size160x120;
83 break;
84 case IrsResolution::Size80x60:
85 resolution_code = IrsResolutionCode::Size80x60;
86 fragments = IrsFragments::Size80x60;
87 resolution = IrsResolution::Size80x60;
88 break;
89 case IrsResolution::Size20x15:
90 resolution_code = IrsResolutionCode::Size20x15;
91 fragments = IrsFragments::Size20x15;
92 resolution = IrsResolution::Size20x15;
93 break;
94 case IrsResolution::Size40x30:
95 default:
96 resolution_code = IrsResolutionCode::Size40x30;
97 fragments = IrsFragments::Size40x30;
98 resolution = IrsResolution::Size40x30;
99 break;
100 }
101
102 // Restart feature
103 if (is_enabled) {
104 DisableIrs();
105 return EnableIrs();
106 }
107
108 return DriverResult::Success;
109}
110
111DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
112 const u8 next_packet_fragment =
113 static_cast<u8>((packet_fragment + 1) % (static_cast<u8>(fragments) + 1));
114
115 if (buffer[0] == 0x31 && buffer[49] == 0x03) {
116 u8 new_packet_fragment = buffer[52];
117 if (new_packet_fragment == next_packet_fragment) {
118 packet_fragment = next_packet_fragment;
119 memcpy(buf_image.data() + (300 * packet_fragment), buffer.data() + 59, 300);
120
121 return RequestFrame(packet_fragment);
122 }
123
124 if (new_packet_fragment == packet_fragment) {
125 return RequestFrame(packet_fragment);
126 }
127
128 return ResendFrame(next_packet_fragment);
129 }
130
131 return RequestFrame(packet_fragment);
132}
133
134DriverResult IrsProtocol::ConfigureIrs() {
135 LOG_DEBUG(Input, "Configure IRS");
136 constexpr std::size_t max_tries = 28;
137 std::vector<u8> output;
138 std::size_t tries = 0;
139
140 const IrsConfigure irs_configuration{
141 .command = MCUCommand::ConfigureIR,
142 .sub_command = MCUSubCommand::SetDeviceMode,
143 .irs_mode = IrsMode::ImageTransfer,
144 .number_of_fragments = fragments,
145 .mcu_major_version = 0x0500,
146 .mcu_minor_version = 0x1800,
147 .crc = {},
148 };
149 buf_image.resize((static_cast<u8>(fragments) + 1) * 300);
150
151 std::vector<u8> request_data(sizeof(IrsConfigure));
152 memcpy(request_data.data(), &irs_configuration, sizeof(IrsConfigure));
153 request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36);
154 do {
155 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
156
157 if (result != DriverResult::Success) {
158 return result;
159 }
160 if (tries++ >= max_tries) {
161 return DriverResult::WrongReply;
162 }
163 } while (output[15] != 0x0b);
164
165 return DriverResult::Success;
166}
167
168DriverResult IrsProtocol::WriteRegistersStep1() {
169 LOG_DEBUG(Input, "WriteRegistersStep1");
170 DriverResult result{DriverResult::Success};
171 constexpr std::size_t max_tries = 28;
172 std::vector<u8> output;
173 std::size_t tries = 0;
174
175 const IrsWriteRegisters irs_registers{
176 .command = MCUCommand::ConfigureIR,
177 .sub_command = MCUSubCommand::WriteDeviceRegisters,
178 .number_of_registers = 0x9,
179 .registers =
180 {
181 IrsRegister{IrRegistersAddress::Resolution, static_cast<u8>(resolution_code)},
182 {IrRegistersAddress::ExposureLSB, static_cast<u8>(exposure & 0xff)},
183 {IrRegistersAddress::ExposureMSB, static_cast<u8>(exposure >> 8)},
184 {IrRegistersAddress::ExposureTime, 0x00},
185 {IrRegistersAddress::Leds, static_cast<u8>(leds)},
186 {IrRegistersAddress::DigitalGainLSB, static_cast<u8>((digital_gain & 0x0f) << 4)},
187 {IrRegistersAddress::DigitalGainMSB, static_cast<u8>((digital_gain & 0xf0) >> 4)},
188 {IrRegistersAddress::LedFilter, static_cast<u8>(led_filter)},
189 {IrRegistersAddress::WhitePixelThreshold, 0xc8},
190 },
191 .crc = {},
192 };
193
194 std::vector<u8> request_data(sizeof(IrsWriteRegisters));
195 memcpy(request_data.data(), &irs_registers, sizeof(IrsWriteRegisters));
196 request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36);
197
198 std::array<u8, 38> mcu_request{0x02};
199 mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36);
200 mcu_request[37] = 0xFF;
201
202 if (result != DriverResult::Success) {
203 return result;
204 }
205
206 do {
207 result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
208
209 // First time we need to set the report mode
210 if (result == DriverResult::Success && tries == 0) {
211 result = SendMcuCommand(SubCommand::SET_REPORT_MODE, mcu_request);
212 }
213 if (result == DriverResult::Success && tries == 0) {
214 GetSubCommandResponse(SubCommand::SET_MCU_CONFIG, output);
215 }
216
217 if (result != DriverResult::Success) {
218 return result;
219 }
220 if (tries++ >= max_tries) {
221 return DriverResult::WrongReply;
222 }
223 } while (!(output[15] == 0x13 && output[17] == 0x07) && output[15] != 0x23);
224
225 return DriverResult::Success;
226}
227
228DriverResult IrsProtocol::WriteRegistersStep2() {
229 LOG_DEBUG(Input, "WriteRegistersStep2");
230 constexpr std::size_t max_tries = 28;
231 std::vector<u8> output;
232 std::size_t tries = 0;
233
234 const IrsWriteRegisters irs_registers{
235 .command = MCUCommand::ConfigureIR,
236 .sub_command = MCUSubCommand::WriteDeviceRegisters,
237 .number_of_registers = 0x8,
238 .registers =
239 {
240 IrsRegister{IrRegistersAddress::LedIntensitiyMSB,
241 static_cast<u8>(led_intensity >> 8)},
242 {IrRegistersAddress::LedIntensitiyLSB, static_cast<u8>(led_intensity & 0xff)},
243 {IrRegistersAddress::ImageFlip, static_cast<u8>(image_flip)},
244 {IrRegistersAddress::DenoiseSmoothing, static_cast<u8>((denoise >> 16) & 0xff)},
245 {IrRegistersAddress::DenoiseEdge, static_cast<u8>((denoise >> 8) & 0xff)},
246 {IrRegistersAddress::DenoiseColor, static_cast<u8>(denoise & 0xff)},
247 {IrRegistersAddress::UpdateTime, 0x2d},
248 {IrRegistersAddress::FinalizeConfig, 0x01},
249 },
250 .crc = {},
251 };
252
253 std::vector<u8> request_data(sizeof(IrsWriteRegisters));
254 memcpy(request_data.data(), &irs_registers, sizeof(IrsWriteRegisters));
255 request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36);
256 do {
257 const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
258
259 if (result != DriverResult::Success) {
260 return result;
261 }
262 if (tries++ >= max_tries) {
263 return DriverResult::WrongReply;
264 }
265 } while (output[15] != 0x13 && output[15] != 0x23);
266
267 return DriverResult::Success;
268}
269
270DriverResult IrsProtocol::RequestFrame(u8 frame) {
271 std::array<u8, 38> mcu_request{};
272 mcu_request[3] = frame;
273 mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36);
274 mcu_request[37] = 0xFF;
275 return SendMcuCommand(SubCommand::SET_REPORT_MODE, mcu_request);
276}
277
278DriverResult IrsProtocol::ResendFrame(u8 frame) {
279 std::array<u8, 38> mcu_request{};
280 mcu_request[1] = 0x1;
281 mcu_request[2] = frame;
282 mcu_request[3] = 0x0;
283 mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36);
284 mcu_request[37] = 0xFF;
285 return SendMcuCommand(SubCommand::SET_REPORT_MODE, mcu_request);
286}
287
288std::vector<u8> IrsProtocol::GetImage() const {
289 return buf_image;
290}
291
292IrsResolution IrsProtocol::GetIrsFormat() const {
293 return resolution;
294}
295
296bool IrsProtocol::IsEnabled() const {
297 return is_enabled;
298}
299
300} // namespace InputCommon::Joycon
diff --git a/src/input_common/helpers/joycon_protocol/irs.h b/src/input_common/helpers/joycon_protocol/irs.h
new file mode 100644
index 000000000..76dfa02ea
--- /dev/null
+++ b/src/input_common/helpers/joycon_protocol/irs.h
@@ -0,0 +1,63 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4// Based on dkms-hid-nintendo implementation, CTCaer joycon toolkit and dekuNukem reverse
5// engineering https://github.com/nicman23/dkms-hid-nintendo/blob/master/src/hid-nintendo.c
6// https://github.com/CTCaer/jc_toolkit
7// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering
8
9#pragma once
10
11#include <vector>
12
13#include "input_common/helpers/joycon_protocol/common_protocol.h"
14#include "input_common/helpers/joycon_protocol/joycon_types.h"
15
16namespace InputCommon::Joycon {
17
18class IrsProtocol final : private JoyconCommonProtocol {
19public:
20 explicit IrsProtocol(std::shared_ptr<JoyconHandle> handle);
21
22 DriverResult EnableIrs();
23
24 DriverResult DisableIrs();
25
26 DriverResult SetIrsConfig(IrsMode mode, IrsResolution format);
27
28 DriverResult RequestImage(std::span<u8> buffer);
29
30 std::vector<u8> GetImage() const;
31
32 IrsResolution GetIrsFormat() const;
33
34 bool IsEnabled() const;
35
36private:
37 DriverResult ConfigureIrs();
38
39 DriverResult WriteRegistersStep1();
40 DriverResult WriteRegistersStep2();
41
42 DriverResult RequestFrame(u8 frame);
43 DriverResult ResendFrame(u8 frame);
44
45 IrsMode irs_mode{IrsMode::ImageTransfer};
46 IrsResolution resolution{IrsResolution::Size40x30};
47 IrsResolutionCode resolution_code{IrsResolutionCode::Size40x30};
48 IrsFragments fragments{IrsFragments::Size40x30};
49 IrLeds leds{IrLeds::BrightAndDim};
50 IrExLedFilter led_filter{IrExLedFilter::Enabled};
51 IrImageFlip image_flip{IrImageFlip::Normal};
52 u8 digital_gain{0x01};
53 u16 exposure{0x2490};
54 u16 led_intensity{0x0f10};
55 u32 denoise{0x012344};
56
57 u8 packet_fragment{};
58 std::vector<u8> buf_image; // 8bpp greyscale image.
59
60 bool is_enabled{};
61};
62
63} // namespace InputCommon::Joycon
diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h
index 36c00a8d7..273c8d07d 100644
--- a/src/input_common/helpers/joycon_protocol/joycon_types.h
+++ b/src/input_common/helpers/joycon_protocol/joycon_types.h
@@ -18,7 +18,7 @@
18 18
19namespace InputCommon::Joycon { 19namespace InputCommon::Joycon {
20constexpr u32 MaxErrorCount = 50; 20constexpr u32 MaxErrorCount = 50;
21constexpr u32 MaxBufferSize = 60; 21constexpr u32 MaxBufferSize = 368;
22constexpr u32 MaxResponseSize = 49; 22constexpr u32 MaxResponseSize = 49;
23constexpr u32 MaxSubCommandResponseSize = 64; 23constexpr u32 MaxSubCommandResponseSize = 64;
24constexpr std::array<u8, 8> DefaultVibrationBuffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x1, 0x40, 0x40}; 24constexpr std::array<u8, 8> DefaultVibrationBuffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x1, 0x40, 0x40};
@@ -273,6 +273,80 @@ enum class NFCTagType : u8 {
273 Ntag215 = 0x01, 273 Ntag215 = 0x01,
274}; 274};
275 275
276enum class IrsMode : u8 {
277 None = 0x02,
278 Moment = 0x03,
279 Dpd = 0x04,
280 Clustering = 0x06,
281 ImageTransfer = 0x07,
282 Silhouette = 0x08,
283 TeraImage = 0x09,
284 SilhouetteTeraImage = 0x0A,
285};
286
287enum class IrsResolution {
288 Size320x240,
289 Size160x120,
290 Size80x60,
291 Size40x30,
292 Size20x15,
293 None,
294};
295
296enum class IrsResolutionCode : u8 {
297 Size320x240 = 0x00, // Full pixel array
298 Size160x120 = 0x50, // Sensor Binning [2 X 2]
299 Size80x60 = 0x64, // Sensor Binning [4 x 2] and Skipping [1 x 2]
300 Size40x30 = 0x69, // Sensor Binning [4 x 2] and Skipping [2 x 4]
301 Size20x15 = 0x6A, // Sensor Binning [4 x 2] and Skipping [4 x 4]
302};
303
304// Size of image divided by 300
305enum class IrsFragments : u8 {
306 Size20x15 = 0x00,
307 Size40x30 = 0x03,
308 Size80x60 = 0x0f,
309 Size160x120 = 0x3f,
310 Size320x240 = 0xFF,
311};
312
313enum class IrLeds : u8 {
314 BrightAndDim = 0x00,
315 Bright = 0x20,
316 Dim = 0x10,
317 None = 0x30,
318};
319
320enum class IrExLedFilter : u8 {
321 Disabled = 0x00,
322 Enabled = 0x03,
323};
324
325enum class IrImageFlip : u8 {
326 Normal = 0x00,
327 Inverted = 0x02,
328};
329
330enum class IrRegistersAddress : u16 {
331 UpdateTime = 0x0400,
332 FinalizeConfig = 0x0700,
333 LedFilter = 0x0e00,
334 Leds = 0x1000,
335 LedIntensitiyMSB = 0x1100,
336 LedIntensitiyLSB = 0x1200,
337 ImageFlip = 0x2d00,
338 Resolution = 0x2e00,
339 DigitalGainLSB = 0x2e01,
340 DigitalGainMSB = 0x2f01,
341 ExposureLSB = 0x3001,
342 ExposureMSB = 0x3101,
343 ExposureTime = 0x3201,
344 WhitePixelThreshold = 0x4301,
345 DenoiseSmoothing = 0x6701,
346 DenoiseEdge = 0x6801,
347 DenoiseColor = 0x6901,
348};
349
276enum class DriverResult { 350enum class DriverResult {
277 Success, 351 Success,
278 WrongReply, 352 WrongReply,
@@ -456,6 +530,36 @@ struct NFCRequestState {
456}; 530};
457static_assert(sizeof(NFCRequestState) == 0x26, "NFCRequestState is an invalid size"); 531static_assert(sizeof(NFCRequestState) == 0x26, "NFCRequestState is an invalid size");
458 532
533struct IrsConfigure {
534 MCUCommand command;
535 MCUSubCommand sub_command;
536 IrsMode irs_mode;
537 IrsFragments number_of_fragments;
538 u16 mcu_major_version;
539 u16 mcu_minor_version;
540 INSERT_PADDING_BYTES(0x1D);
541 u8 crc;
542};
543static_assert(sizeof(IrsConfigure) == 0x26, "IrsConfigure is an invalid size");
544
545#pragma pack(push, 1)
546struct IrsRegister {
547 IrRegistersAddress address;
548 u8 value;
549};
550static_assert(sizeof(IrsRegister) == 0x3, "IrsRegister is an invalid size");
551
552struct IrsWriteRegisters {
553 MCUCommand command;
554 MCUSubCommand sub_command;
555 u8 number_of_registers;
556 std::array<IrsRegister, 9> registers;
557 INSERT_PADDING_BYTES(0x7);
558 u8 crc;
559};
560static_assert(sizeof(IrsWriteRegisters) == 0x26, "IrsWriteRegisters is an invalid size");
561#pragma pack(pop)
562
459struct FirmwareVersion { 563struct FirmwareVersion {
460 u8 major; 564 u8 major;
461 u8 minor; 565 u8 minor;
@@ -490,6 +594,7 @@ struct JoyconCallbacks {
490 std::function<void(int, const MotionData&)> on_motion_data; 594 std::function<void(int, const MotionData&)> on_motion_data;
491 std::function<void(f32)> on_ring_data; 595 std::function<void(f32)> on_ring_data;
492 std::function<void(const std::vector<u8>&)> on_amiibo_data; 596 std::function<void(const std::vector<u8>&)> on_amiibo_data;
597 std::function<void(const std::vector<u8>&, IrsResolution)> on_camera_data;
493}; 598};
494 599
495} // namespace InputCommon::Joycon 600} // namespace InputCommon::Joycon
diff --git a/src/input_common/helpers/joycon_protocol/poller.cpp b/src/input_common/helpers/joycon_protocol/poller.cpp
index fd05d98f3..940b20b7f 100644
--- a/src/input_common/helpers/joycon_protocol/poller.cpp
+++ b/src/input_common/helpers/joycon_protocol/poller.cpp
@@ -74,10 +74,14 @@ void JoyconPoller::UpdateColor(const Color& color) {
74 callbacks.on_color_data(color); 74 callbacks.on_color_data(color);
75} 75}
76 76
77void JoyconPoller::updateAmiibo(const std::vector<u8>& amiibo_data) { 77void JoyconPoller::UpdateAmiibo(const std::vector<u8>& amiibo_data) {
78 callbacks.on_amiibo_data(amiibo_data); 78 callbacks.on_amiibo_data(amiibo_data);
79} 79}
80 80
81void JoyconPoller::UpdateCamera(const std::vector<u8>& camera_data, IrsResolution format) {
82 callbacks.on_camera_data(camera_data, format);
83}
84
81void JoyconPoller::UpdateRing(s16 value, const RingStatus& ring_status) { 85void JoyconPoller::UpdateRing(s16 value, const RingStatus& ring_status) {
82 float normalized_value = static_cast<float>(value - ring_status.default_value); 86 float normalized_value = static_cast<float>(value - ring_status.default_value);
83 if (normalized_value > 0) { 87 if (normalized_value > 0) {
diff --git a/src/input_common/helpers/joycon_protocol/poller.h b/src/input_common/helpers/joycon_protocol/poller.h
index c40fc7bca..354d41dad 100644
--- a/src/input_common/helpers/joycon_protocol/poller.h
+++ b/src/input_common/helpers/joycon_protocol/poller.h
@@ -36,7 +36,8 @@ public:
36 36
37 void UpdateColor(const Color& color); 37 void UpdateColor(const Color& color);
38 void UpdateRing(s16 value, const RingStatus& ring_status); 38 void UpdateRing(s16 value, const RingStatus& ring_status);
39 void updateAmiibo(const std::vector<u8>& amiibo_data); 39 void UpdateAmiibo(const std::vector<u8>& amiibo_data);
40 void UpdateCamera(const std::vector<u8>& amiibo_data, IrsResolution format);
40 41
41private: 42private:
42 void UpdateActiveLeftPadInput(const InputReportActive& input, 43 void UpdateActiveLeftPadInput(const InputReportActive& input,