diff options
| -rw-r--r-- | src/core/hid/emulated_controller.cpp | 6 | ||||
| -rw-r--r-- | src/core/hid/emulated_controller.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp.cpp | 664 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp.h | 189 |
4 files changed, 672 insertions, 189 deletions
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index a7cdf45e6..61ceea629 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp | |||
| @@ -884,6 +884,12 @@ bool EmulatedController::TestVibration(std::size_t device_index) { | |||
| 884 | return SetVibration(device_index, DEFAULT_VIBRATION_VALUE); | 884 | return SetVibration(device_index, DEFAULT_VIBRATION_VALUE); |
| 885 | } | 885 | } |
| 886 | 886 | ||
| 887 | bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) { | ||
| 888 | LOG_INFO(Service_HID, "Set polling mode {}", polling_mode); | ||
| 889 | auto& output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | ||
| 890 | return output_device->SetPollingMode(polling_mode) == Common::Input::PollingError::None; | ||
| 891 | } | ||
| 892 | |||
| 887 | void EmulatedController::SetLedPattern() { | 893 | void EmulatedController::SetLedPattern() { |
| 888 | for (auto& device : output_devices) { | 894 | for (auto& device : output_devices) { |
| 889 | if (!device) { | 895 | if (!device) { |
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index d8642c5b3..7785e6110 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h | |||
| @@ -309,6 +309,8 @@ public: | |||
| 309 | */ | 309 | */ |
| 310 | bool TestVibration(std::size_t device_index); | 310 | bool TestVibration(std::size_t device_index); |
| 311 | 311 | ||
| 312 | bool SetPollingMode(Common::Input::PollingMode polling_mode); | ||
| 313 | |||
| 312 | /// Returns the led pattern corresponding to this emulated controller | 314 | /// Returns the led pattern corresponding to this emulated controller |
| 313 | LedPattern GetLedPattern() const; | 315 | LedPattern GetLedPattern() const; |
| 314 | 316 | ||
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index cedade5c2..7f1fb3a71 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp | |||
| @@ -7,6 +7,9 @@ | |||
| 7 | 7 | ||
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "core/core.h" | 9 | #include "core/core.h" |
| 10 | #include "core/hid/emulated_controller.h" | ||
| 11 | #include "core/hid/hid_core.h" | ||
| 12 | #include "core/hid/hid_types.h" | ||
| 10 | #include "core/hle/ipc_helpers.h" | 13 | #include "core/hle/ipc_helpers.h" |
| 11 | #include "core/hle/kernel/k_event.h" | 14 | #include "core/hle/kernel/k_event.h" |
| 12 | #include "core/hle/service/nfp/nfp.h" | 15 | #include "core/hle/service/nfp/nfp.h" |
| @@ -14,12 +17,18 @@ | |||
| 14 | 17 | ||
| 15 | namespace Service::NFP { | 18 | namespace Service::NFP { |
| 16 | namespace ErrCodes { | 19 | namespace ErrCodes { |
| 17 | constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152); | 20 | constexpr ResultCode DeviceNotFound(ErrorModule::NFP, 64); |
| 21 | constexpr ResultCode WrongDeviceState(ErrorModule::NFP, 73); | ||
| 22 | constexpr ResultCode ApplicationAreaIsNotInitialized(ErrorModule::NFP, 128); | ||
| 23 | constexpr ResultCode NoApplicationArea(ErrorModule::NFP, 152); | ||
| 24 | constexpr ResultCode ApplicationAreaExist(ErrorModule::NFP, 168); | ||
| 18 | } // namespace ErrCodes | 25 | } // namespace ErrCodes |
| 19 | 26 | ||
| 27 | constexpr u32 ApplicationAreaSize = 0xD8; | ||
| 28 | |||
| 20 | IUser::IUser(Module::Interface& nfp_interface_, Core::System& system_) | 29 | IUser::IUser(Module::Interface& nfp_interface_, Core::System& system_) |
| 21 | : ServiceFramework{system_, "NFP::IUser"}, nfp_interface{nfp_interface_}, | 30 | : ServiceFramework{system_, "NFP::IUser"}, service_context{system_, service_name}, |
| 22 | deactivate_event{system.Kernel()}, availability_change_event{system.Kernel()} { | 31 | nfp_interface{nfp_interface_} { |
| 23 | static const FunctionInfo functions[] = { | 32 | static const FunctionInfo functions[] = { |
| 24 | {0, &IUser::Initialize, "Initialize"}, | 33 | {0, &IUser::Initialize, "Initialize"}, |
| 25 | {1, &IUser::Finalize, "Finalize"}, | 34 | {1, &IUser::Finalize, "Finalize"}, |
| @@ -30,10 +39,10 @@ IUser::IUser(Module::Interface& nfp_interface_, Core::System& system_) | |||
| 30 | {6, &IUser::Unmount, "Unmount"}, | 39 | {6, &IUser::Unmount, "Unmount"}, |
| 31 | {7, &IUser::OpenApplicationArea, "OpenApplicationArea"}, | 40 | {7, &IUser::OpenApplicationArea, "OpenApplicationArea"}, |
| 32 | {8, &IUser::GetApplicationArea, "GetApplicationArea"}, | 41 | {8, &IUser::GetApplicationArea, "GetApplicationArea"}, |
| 33 | {9, nullptr, "SetApplicationArea"}, | 42 | {9, &IUser::SetApplicationArea, "SetApplicationArea"}, |
| 34 | {10, nullptr, "Flush"}, | 43 | {10, nullptr, "Flush"}, |
| 35 | {11, nullptr, "Restore"}, | 44 | {11, nullptr, "Restore"}, |
| 36 | {12, nullptr, "CreateApplicationArea"}, | 45 | {12, &IUser::CreateApplicationArea, "CreateApplicationArea"}, |
| 37 | {13, &IUser::GetTagInfo, "GetTagInfo"}, | 46 | {13, &IUser::GetTagInfo, "GetTagInfo"}, |
| 38 | {14, &IUser::GetRegisterInfo, "GetRegisterInfo"}, | 47 | {14, &IUser::GetRegisterInfo, "GetRegisterInfo"}, |
| 39 | {15, &IUser::GetCommonInfo, "GetCommonInfo"}, | 48 | {15, &IUser::GetCommonInfo, "GetCommonInfo"}, |
| @@ -49,220 +58,416 @@ IUser::IUser(Module::Interface& nfp_interface_, Core::System& system_) | |||
| 49 | }; | 58 | }; |
| 50 | RegisterHandlers(functions); | 59 | RegisterHandlers(functions); |
| 51 | 60 | ||
| 52 | Kernel::KAutoObject::Create(std::addressof(deactivate_event)); | 61 | availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent"); |
| 53 | Kernel::KAutoObject::Create(std::addressof(availability_change_event)); | ||
| 54 | |||
| 55 | deactivate_event.Initialize("IUser:DeactivateEvent"); | ||
| 56 | availability_change_event.Initialize("IUser:AvailabilityChangeEvent"); | ||
| 57 | } | 62 | } |
| 58 | 63 | ||
| 59 | void IUser::Initialize(Kernel::HLERequestContext& ctx) { | 64 | void IUser::Initialize(Kernel::HLERequestContext& ctx) { |
| 60 | LOG_DEBUG(Service_NFC, "called"); | 65 | LOG_INFO(Service_NFC, "called"); |
| 66 | |||
| 67 | state = State::Initialized; | ||
| 68 | |||
| 69 | // TODO(german77): Loop through all interfaces | ||
| 70 | nfp_interface.Initialize(); | ||
| 61 | 71 | ||
| 62 | IPC::ResponseBuilder rb{ctx, 2, 0}; | 72 | IPC::ResponseBuilder rb{ctx, 2, 0}; |
| 63 | rb.Push(ResultSuccess); | 73 | rb.Push(ResultSuccess); |
| 64 | |||
| 65 | state = State::Initialized; | ||
| 66 | } | 74 | } |
| 67 | 75 | ||
| 68 | void IUser::Finalize(Kernel::HLERequestContext& ctx) { | 76 | void IUser::Finalize(Kernel::HLERequestContext& ctx) { |
| 69 | LOG_DEBUG(Service_NFP, "called"); | 77 | LOG_INFO(Service_NFP, "called"); |
| 78 | |||
| 79 | state = State::NonInitialized; | ||
| 70 | 80 | ||
| 71 | device_state = DeviceState::Finalized; | 81 | // TODO(german77): Loop through all interfaces |
| 82 | nfp_interface.Finalize(); | ||
| 72 | 83 | ||
| 73 | IPC::ResponseBuilder rb{ctx, 2}; | 84 | IPC::ResponseBuilder rb{ctx, 2}; |
| 74 | rb.Push(ResultSuccess); | 85 | rb.Push(ResultSuccess); |
| 75 | } | 86 | } |
| 76 | 87 | ||
| 77 | void IUser::ListDevices(Kernel::HLERequestContext& ctx) { | 88 | void IUser::ListDevices(Kernel::HLERequestContext& ctx) { |
| 78 | IPC::RequestParser rp{ctx}; | 89 | LOG_INFO(Service_NFP, "called"); |
| 79 | const u32 array_size = rp.Pop<u32>(); | 90 | |
| 80 | LOG_DEBUG(Service_NFP, "called, array_size={}", array_size); | 91 | std::vector<u64> devices; |
| 92 | |||
| 93 | // TODO(german77): Loop through all interfaces | ||
| 94 | devices.push_back(nfp_interface.GetHandle()); | ||
| 81 | 95 | ||
| 82 | ctx.WriteBuffer(device_handle); | 96 | ctx.WriteBuffer(devices); |
| 83 | 97 | ||
| 84 | IPC::ResponseBuilder rb{ctx, 3}; | 98 | IPC::ResponseBuilder rb{ctx, 3}; |
| 85 | rb.Push(ResultSuccess); | 99 | rb.Push(ResultSuccess); |
| 86 | rb.Push<u32>(1); | 100 | rb.Push(devices.size()); |
| 87 | } | 101 | } |
| 88 | 102 | ||
| 89 | void IUser::StartDetection(Kernel::HLERequestContext& ctx) { | 103 | void IUser::StartDetection(Kernel::HLERequestContext& ctx) { |
| 90 | LOG_DEBUG(Service_NFP, "called"); | 104 | IPC::RequestParser rp{ctx}; |
| 91 | 105 | const auto device_handle{rp.Pop<u64>()}; | |
| 92 | if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { | 106 | const auto nfp_protocol{rp.Pop<s32>()}; |
| 93 | device_state = DeviceState::SearchingForTag; | 107 | LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); |
| 108 | |||
| 109 | // TODO(german77): Loop through all interfaces | ||
| 110 | if (device_handle == nfp_interface.GetHandle()) { | ||
| 111 | const auto result = nfp_interface.StartDetection(); | ||
| 112 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 113 | rb.Push(result); | ||
| 114 | return; | ||
| 94 | } | 115 | } |
| 116 | |||
| 117 | LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); | ||
| 118 | |||
| 95 | IPC::ResponseBuilder rb{ctx, 2}; | 119 | IPC::ResponseBuilder rb{ctx, 2}; |
| 96 | rb.Push(ResultSuccess); | 120 | rb.Push(ErrCodes::DeviceNotFound); |
| 97 | } | 121 | } |
| 98 | 122 | ||
| 99 | void IUser::StopDetection(Kernel::HLERequestContext& ctx) { | 123 | void IUser::StopDetection(Kernel::HLERequestContext& ctx) { |
| 100 | LOG_DEBUG(Service_NFP, "called"); | 124 | IPC::RequestParser rp{ctx}; |
| 101 | 125 | const auto device_handle{rp.Pop<u64>()}; | |
| 102 | switch (device_state) { | 126 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); |
| 103 | case DeviceState::TagFound: | 127 | |
| 104 | case DeviceState::TagMounted: | 128 | // TODO(german77): Loop through all interfaces |
| 105 | deactivate_event.GetWritableEvent().Signal(); | 129 | if (device_handle == nfp_interface.GetHandle()) { |
| 106 | device_state = DeviceState::Initialized; | 130 | const auto result = nfp_interface.StopDetection(); |
| 107 | break; | 131 | IPC::ResponseBuilder rb{ctx, 2}; |
| 108 | case DeviceState::SearchingForTag: | 132 | rb.Push(result); |
| 109 | case DeviceState::TagRemoved: | 133 | return; |
| 110 | device_state = DeviceState::Initialized; | ||
| 111 | break; | ||
| 112 | default: | ||
| 113 | break; | ||
| 114 | } | 134 | } |
| 135 | |||
| 136 | LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); | ||
| 137 | |||
| 115 | IPC::ResponseBuilder rb{ctx, 2}; | 138 | IPC::ResponseBuilder rb{ctx, 2}; |
| 116 | rb.Push(ResultSuccess); | 139 | rb.Push(ErrCodes::DeviceNotFound); |
| 117 | } | 140 | } |
| 118 | 141 | ||
| 119 | void IUser::Mount(Kernel::HLERequestContext& ctx) { | 142 | void IUser::Mount(Kernel::HLERequestContext& ctx) { |
| 120 | LOG_DEBUG(Service_NFP, "called"); | 143 | IPC::RequestParser rp{ctx}; |
| 144 | const auto device_handle{rp.Pop<u64>()}; | ||
| 145 | const auto model_type{rp.PopEnum<ModelType>()}; | ||
| 146 | const auto mount_target{rp.PopEnum<MountTarget>()}; | ||
| 147 | LOG_INFO(Service_NFP, "called, device_handle={}, model_type={}, mount_target={}", device_handle, | ||
| 148 | model_type, mount_target); | ||
| 149 | |||
| 150 | // TODO(german77): Loop through all interfaces | ||
| 151 | if (device_handle == nfp_interface.GetHandle()) { | ||
| 152 | const auto result = nfp_interface.Mount(); | ||
| 153 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 154 | rb.Push(result); | ||
| 155 | return; | ||
| 156 | } | ||
| 157 | |||
| 158 | LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); | ||
| 121 | 159 | ||
| 122 | device_state = DeviceState::TagMounted; | ||
| 123 | IPC::ResponseBuilder rb{ctx, 2}; | 160 | IPC::ResponseBuilder rb{ctx, 2}; |
| 124 | rb.Push(ResultSuccess); | 161 | rb.Push(ErrCodes::DeviceNotFound); |
| 125 | } | 162 | } |
| 126 | 163 | ||
| 127 | void IUser::Unmount(Kernel::HLERequestContext& ctx) { | 164 | void IUser::Unmount(Kernel::HLERequestContext& ctx) { |
| 128 | LOG_DEBUG(Service_NFP, "called"); | 165 | IPC::RequestParser rp{ctx}; |
| 166 | const auto device_handle{rp.Pop<u64>()}; | ||
| 167 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | ||
| 168 | |||
| 169 | // TODO(german77): Loop through all interfaces | ||
| 170 | if (device_handle == nfp_interface.GetHandle()) { | ||
| 171 | const auto result = nfp_interface.Unmount(); | ||
| 172 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 173 | rb.Push(result); | ||
| 174 | return; | ||
| 175 | } | ||
| 129 | 176 | ||
| 130 | device_state = DeviceState::TagFound; | 177 | LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); |
| 131 | 178 | ||
| 132 | IPC::ResponseBuilder rb{ctx, 2}; | 179 | IPC::ResponseBuilder rb{ctx, 2}; |
| 133 | rb.Push(ResultSuccess); | 180 | rb.Push(ErrCodes::DeviceNotFound); |
| 134 | } | 181 | } |
| 135 | 182 | ||
| 136 | void IUser::OpenApplicationArea(Kernel::HLERequestContext& ctx) { | 183 | void IUser::OpenApplicationArea(Kernel::HLERequestContext& ctx) { |
| 137 | LOG_WARNING(Service_NFP, "(STUBBED) called"); | 184 | IPC::RequestParser rp{ctx}; |
| 185 | const auto device_handle{rp.Pop<u64>()}; | ||
| 186 | const auto access_id{rp.Pop<u32>()}; | ||
| 187 | LOG_INFO(Service_NFP, "called, device_handle={}, access_id={}", device_handle, access_id); | ||
| 188 | |||
| 189 | // TODO(german77): Loop through all interfaces | ||
| 190 | if (device_handle == nfp_interface.GetHandle()) { | ||
| 191 | const auto result = nfp_interface.OpenApplicationArea(access_id); | ||
| 192 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 193 | rb.Push(result); | ||
| 194 | return; | ||
| 195 | } | ||
| 196 | |||
| 197 | LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); | ||
| 198 | |||
| 138 | IPC::ResponseBuilder rb{ctx, 2}; | 199 | IPC::ResponseBuilder rb{ctx, 2}; |
| 139 | rb.Push(ErrCodes::ERR_NO_APPLICATION_AREA); | 200 | rb.Push(ErrCodes::DeviceNotFound); |
| 140 | } | 201 | } |
| 141 | 202 | ||
| 142 | void IUser::GetApplicationArea(Kernel::HLERequestContext& ctx) { | 203 | void IUser::GetApplicationArea(Kernel::HLERequestContext& ctx) { |
| 143 | LOG_WARNING(Service_NFP, "(STUBBED) called"); | 204 | IPC::RequestParser rp{ctx}; |
| 205 | const auto device_handle{rp.Pop<u64>()}; | ||
| 206 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | ||
| 207 | |||
| 208 | // TODO(german77): Loop through all interfaces | ||
| 209 | if (device_handle == nfp_interface.GetHandle()) { | ||
| 210 | std::vector<u8> data{}; | ||
| 211 | const auto result = nfp_interface.GetApplicationArea(data); | ||
| 212 | |||
| 213 | ctx.WriteBuffer(data); | ||
| 214 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 215 | rb.Push(result); | ||
| 216 | rb.PushRaw<u32>(data.size()); | ||
| 217 | return; | ||
| 218 | } | ||
| 144 | 219 | ||
| 145 | // TODO(ogniK): Pull application area from amiibo | 220 | LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); |
| 146 | 221 | ||
| 147 | IPC::ResponseBuilder rb{ctx, 3}; | 222 | IPC::ResponseBuilder rb{ctx, 2}; |
| 148 | rb.Push(ResultSuccess); | 223 | rb.Push(ErrCodes::DeviceNotFound); |
| 149 | rb.PushRaw<u32>(0); // This is from the GetCommonInfo stub | 224 | } |
| 225 | |||
| 226 | void IUser::SetApplicationArea(Kernel::HLERequestContext& ctx) { | ||
| 227 | IPC::RequestParser rp{ctx}; | ||
| 228 | const auto device_handle{rp.Pop<u64>()}; | ||
| 229 | const auto data{ctx.ReadBuffer()}; | ||
| 230 | LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}", device_handle, data.size()); | ||
| 231 | |||
| 232 | // TODO(german77): Loop through all interfaces | ||
| 233 | if (device_handle == nfp_interface.GetHandle()) { | ||
| 234 | const auto result = nfp_interface.SetApplicationArea(data); | ||
| 235 | |||
| 236 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 237 | rb.Push(result); | ||
| 238 | return; | ||
| 239 | } | ||
| 240 | |||
| 241 | LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); | ||
| 242 | |||
| 243 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 244 | rb.Push(ErrCodes::DeviceNotFound); | ||
| 245 | } | ||
| 246 | |||
| 247 | void IUser::CreateApplicationArea(Kernel::HLERequestContext& ctx) { | ||
| 248 | IPC::RequestParser rp{ctx}; | ||
| 249 | const auto device_handle{rp.Pop<u64>()}; | ||
| 250 | const auto access_id{rp.Pop<u32>()}; | ||
| 251 | const auto data{ctx.ReadBuffer()}; | ||
| 252 | LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}, access_id={}", device_handle, | ||
| 253 | access_id, data.size()); | ||
| 254 | |||
| 255 | // TODO(german77): Loop through all interfaces | ||
| 256 | if (device_handle == nfp_interface.GetHandle()) { | ||
| 257 | const auto result = nfp_interface.CreateApplicationArea(access_id, data); | ||
| 258 | |||
| 259 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 260 | rb.Push(result); | ||
| 261 | return; | ||
| 262 | } | ||
| 263 | |||
| 264 | LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); | ||
| 265 | |||
| 266 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 267 | rb.Push(ErrCodes::DeviceNotFound); | ||
| 150 | } | 268 | } |
| 151 | 269 | ||
| 152 | void IUser::GetTagInfo(Kernel::HLERequestContext& ctx) { | 270 | void IUser::GetTagInfo(Kernel::HLERequestContext& ctx) { |
| 153 | LOG_DEBUG(Service_NFP, "called"); | 271 | IPC::RequestParser rp{ctx}; |
| 272 | const auto device_handle{rp.Pop<u64>()}; | ||
| 273 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | ||
| 274 | |||
| 275 | // TODO(german77): Loop through all interfaces | ||
| 276 | if (device_handle == nfp_interface.GetHandle()) { | ||
| 277 | TagInfo tag_info{}; | ||
| 278 | const auto result = nfp_interface.GetTagInfo(tag_info); | ||
| 279 | ctx.WriteBuffer(tag_info); | ||
| 280 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 281 | rb.Push(result); | ||
| 282 | return; | ||
| 283 | } | ||
| 284 | |||
| 285 | LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); | ||
| 154 | 286 | ||
| 155 | IPC::ResponseBuilder rb{ctx, 2}; | 287 | IPC::ResponseBuilder rb{ctx, 2}; |
| 156 | const auto& amiibo = nfp_interface.GetAmiiboBuffer(); | 288 | rb.Push(ErrCodes::DeviceNotFound); |
| 157 | const TagInfo tag_info{ | ||
| 158 | .uuid = amiibo.uuid, | ||
| 159 | .uuid_length = static_cast<u8>(amiibo.uuid.size()), | ||
| 160 | .protocol = 1, // TODO(ogniK): Figure out actual values | ||
| 161 | .tag_type = 2, | ||
| 162 | }; | ||
| 163 | ctx.WriteBuffer(tag_info); | ||
| 164 | rb.Push(ResultSuccess); | ||
| 165 | } | 289 | } |
| 166 | 290 | ||
| 167 | void IUser::GetRegisterInfo(Kernel::HLERequestContext& ctx) { | 291 | void IUser::GetRegisterInfo(Kernel::HLERequestContext& ctx) { |
| 168 | LOG_WARNING(Service_NFP, "(STUBBED) called"); | 292 | IPC::RequestParser rp{ctx}; |
| 293 | const auto device_handle{rp.Pop<u64>()}; | ||
| 294 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | ||
| 295 | |||
| 296 | // TODO(german77): Loop through all interfaces | ||
| 297 | if (device_handle == nfp_interface.GetHandle()) { | ||
| 298 | RegisterInfo register_info{}; | ||
| 299 | const auto result = nfp_interface.GetRegisterInfo(register_info); | ||
| 300 | ctx.WriteBuffer(register_info); | ||
| 301 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 302 | rb.Push(result); | ||
| 303 | return; | ||
| 304 | } | ||
| 169 | 305 | ||
| 170 | // TODO(ogniK): Pull Mii and owner data from amiibo | 306 | LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); |
| 171 | 307 | ||
| 172 | IPC::ResponseBuilder rb{ctx, 2}; | 308 | IPC::ResponseBuilder rb{ctx, 2}; |
| 173 | rb.Push(ResultSuccess); | 309 | rb.Push(ErrCodes::DeviceNotFound); |
| 174 | } | 310 | } |
| 175 | 311 | ||
| 176 | void IUser::GetCommonInfo(Kernel::HLERequestContext& ctx) { | 312 | void IUser::GetCommonInfo(Kernel::HLERequestContext& ctx) { |
| 177 | LOG_WARNING(Service_NFP, "(STUBBED) called"); | 313 | IPC::RequestParser rp{ctx}; |
| 178 | 314 | const auto device_handle{rp.Pop<u64>()}; | |
| 179 | // TODO(ogniK): Pull common information from amiibo | 315 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); |
| 316 | |||
| 317 | // TODO(german77): Loop through all interfaces | ||
| 318 | if (device_handle == nfp_interface.GetHandle()) { | ||
| 319 | CommonInfo common_info{}; | ||
| 320 | const auto result = nfp_interface.GetCommonInfo(common_info); | ||
| 321 | ctx.WriteBuffer(common_info); | ||
| 322 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 323 | rb.Push(result); | ||
| 324 | return; | ||
| 325 | } | ||
| 180 | 326 | ||
| 181 | CommonInfo common_info{}; | 327 | LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); |
| 182 | common_info.application_area_size = 0; | ||
| 183 | ctx.WriteBuffer(common_info); | ||
| 184 | 328 | ||
| 185 | IPC::ResponseBuilder rb{ctx, 2}; | 329 | IPC::ResponseBuilder rb{ctx, 2}; |
| 186 | rb.Push(ResultSuccess); | 330 | rb.Push(ErrCodes::DeviceNotFound); |
| 187 | } | 331 | } |
| 188 | 332 | ||
| 189 | void IUser::GetModelInfo(Kernel::HLERequestContext& ctx) { | 333 | void IUser::GetModelInfo(Kernel::HLERequestContext& ctx) { |
| 190 | LOG_DEBUG(Service_NFP, "called"); | 334 | IPC::RequestParser rp{ctx}; |
| 335 | const auto device_handle{rp.Pop<u64>()}; | ||
| 336 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | ||
| 337 | |||
| 338 | // TODO(german77): Loop through all interfaces | ||
| 339 | if (device_handle == nfp_interface.GetHandle()) { | ||
| 340 | ModelInfo model_info{}; | ||
| 341 | const auto result = nfp_interface.GetModelInfo(model_info); | ||
| 342 | ctx.WriteBuffer(model_info); | ||
| 343 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 344 | rb.Push(ResultSuccess); | ||
| 345 | return; | ||
| 346 | } | ||
| 347 | |||
| 348 | LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); | ||
| 191 | 349 | ||
| 192 | IPC::ResponseBuilder rb{ctx, 2}; | 350 | IPC::ResponseBuilder rb{ctx, 2}; |
| 193 | const auto& amiibo = nfp_interface.GetAmiiboBuffer(); | 351 | rb.Push(ErrCodes::DeviceNotFound); |
| 194 | ctx.WriteBuffer(amiibo.model_info); | ||
| 195 | rb.Push(ResultSuccess); | ||
| 196 | } | 352 | } |
| 197 | 353 | ||
| 198 | void IUser::AttachActivateEvent(Kernel::HLERequestContext& ctx) { | 354 | void IUser::AttachActivateEvent(Kernel::HLERequestContext& ctx) { |
| 199 | IPC::RequestParser rp{ctx}; | 355 | IPC::RequestParser rp{ctx}; |
| 200 | const u64 dev_handle = rp.Pop<u64>(); | 356 | const auto device_handle{rp.Pop<u64>()}; |
| 201 | LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); | 357 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); |
| 358 | |||
| 359 | // TODO(german77): Loop through all interfaces | ||
| 360 | if (device_handle == nfp_interface.GetHandle()) { | ||
| 361 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 362 | rb.Push(ResultSuccess); | ||
| 363 | rb.PushCopyObjects(nfp_interface.GetActivateEvent()); | ||
| 364 | return; | ||
| 365 | } | ||
| 202 | 366 | ||
| 203 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 367 | LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); |
| 204 | rb.Push(ResultSuccess); | 368 | |
| 205 | rb.PushCopyObjects(nfp_interface.GetNFCEvent()); | 369 | IPC::ResponseBuilder rb{ctx, 2}; |
| 206 | has_attached_handle = true; | 370 | rb.Push(ErrCodes::DeviceNotFound); |
| 207 | } | 371 | } |
| 208 | 372 | ||
| 209 | void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) { | 373 | void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) { |
| 210 | IPC::RequestParser rp{ctx}; | 374 | IPC::RequestParser rp{ctx}; |
| 211 | const u64 dev_handle = rp.Pop<u64>(); | 375 | const auto device_handle{rp.Pop<u64>()}; |
| 212 | LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); | 376 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); |
| 377 | |||
| 378 | // TODO(german77): Loop through all interfaces | ||
| 379 | if (device_handle == nfp_interface.GetHandle()) { | ||
| 380 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 381 | rb.Push(ResultSuccess); | ||
| 382 | rb.PushCopyObjects(nfp_interface.GetDeactivateEvent()); | ||
| 383 | return; | ||
| 384 | } | ||
| 213 | 385 | ||
| 214 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 386 | LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); |
| 215 | rb.Push(ResultSuccess); | 387 | |
| 216 | rb.PushCopyObjects(deactivate_event.GetReadableEvent()); | 388 | IPC::ResponseBuilder rb{ctx, 2}; |
| 389 | rb.Push(ErrCodes::DeviceNotFound); | ||
| 217 | } | 390 | } |
| 218 | 391 | ||
| 219 | void IUser::GetState(Kernel::HLERequestContext& ctx) { | 392 | void IUser::GetState(Kernel::HLERequestContext& ctx) { |
| 220 | LOG_DEBUG(Service_NFC, "called"); | 393 | LOG_INFO(Service_NFC, "called"); |
| 221 | 394 | ||
| 222 | IPC::ResponseBuilder rb{ctx, 3, 0}; | 395 | IPC::ResponseBuilder rb{ctx, 3, 0}; |
| 223 | rb.Push(ResultSuccess); | 396 | rb.Push(ResultSuccess); |
| 224 | rb.PushRaw<u32>(static_cast<u32>(state)); | 397 | rb.PushEnum(state); |
| 225 | } | 398 | } |
| 226 | 399 | ||
| 227 | void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) { | 400 | void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) { |
| 228 | LOG_DEBUG(Service_NFP, "called"); | 401 | IPC::RequestParser rp{ctx}; |
| 402 | const auto device_handle{rp.Pop<u64>()}; | ||
| 403 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | ||
| 404 | |||
| 405 | // TODO(german77): Loop through all interfaces | ||
| 406 | if (device_handle == nfp_interface.GetHandle()) { | ||
| 407 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 408 | rb.Push(ResultSuccess); | ||
| 409 | rb.PushEnum(nfp_interface.GetCurrentState()); | ||
| 410 | return; | ||
| 411 | } | ||
| 229 | 412 | ||
| 230 | IPC::ResponseBuilder rb{ctx, 3}; | 413 | LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); |
| 231 | rb.Push(ResultSuccess); | 414 | |
| 232 | rb.Push<u32>(static_cast<u32>(device_state)); | 415 | IPC::ResponseBuilder rb{ctx, 2}; |
| 416 | rb.Push(ErrCodes::DeviceNotFound); | ||
| 233 | } | 417 | } |
| 234 | 418 | ||
| 235 | void IUser::GetNpadId(Kernel::HLERequestContext& ctx) { | 419 | void IUser::GetNpadId(Kernel::HLERequestContext& ctx) { |
| 236 | IPC::RequestParser rp{ctx}; | 420 | IPC::RequestParser rp{ctx}; |
| 237 | const u64 dev_handle = rp.Pop<u64>(); | 421 | const auto device_handle{rp.Pop<u64>()}; |
| 238 | LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); | 422 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); |
| 423 | |||
| 424 | // TODO(german77): Loop through all interfaces | ||
| 425 | if (device_handle == nfp_interface.GetHandle()) { | ||
| 426 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 427 | rb.Push(ResultSuccess); | ||
| 428 | rb.PushEnum(nfp_interface.GetNpadId()); | ||
| 429 | return; | ||
| 430 | } | ||
| 239 | 431 | ||
| 240 | IPC::ResponseBuilder rb{ctx, 3}; | 432 | LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); |
| 241 | rb.Push(ResultSuccess); | 433 | |
| 242 | rb.Push<u32>(npad_id); | 434 | IPC::ResponseBuilder rb{ctx, 2}; |
| 435 | rb.Push(ErrCodes::DeviceNotFound); | ||
| 243 | } | 436 | } |
| 244 | 437 | ||
| 245 | void IUser::GetApplicationAreaSize(Kernel::HLERequestContext& ctx) { | 438 | void IUser::GetApplicationAreaSize(Kernel::HLERequestContext& ctx) { |
| 246 | LOG_WARNING(Service_NFP, "(STUBBED) called"); | 439 | IPC::RequestParser rp{ctx}; |
| 247 | // We don't need to worry about this since we can just open the file | 440 | const auto device_handle{rp.Pop<u64>()}; |
| 248 | IPC::ResponseBuilder rb{ctx, 3}; | 441 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); |
| 249 | rb.Push(ResultSuccess); | 442 | |
| 250 | rb.PushRaw<u32>(0); // This is from the GetCommonInfo stub | 443 | // TODO(german77): Loop through all interfaces |
| 444 | if (device_handle == nfp_interface.GetHandle()) { | ||
| 445 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 446 | rb.Push(ResultSuccess); | ||
| 447 | rb.Push(ApplicationAreaSize); | ||
| 448 | return; | ||
| 449 | } | ||
| 450 | |||
| 451 | LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); | ||
| 452 | |||
| 453 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 454 | rb.Push(ErrCodes::DeviceNotFound); | ||
| 251 | } | 455 | } |
| 252 | 456 | ||
| 253 | void IUser::AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) { | 457 | void IUser::AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) { |
| 254 | LOG_WARNING(Service_NFP, "(STUBBED) called"); | 458 | LOG_DEBUG(Service_NFP, "(STUBBED) called"); |
| 255 | 459 | ||
| 256 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 460 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 257 | rb.Push(ResultSuccess); | 461 | rb.Push(ResultSuccess); |
| 258 | rb.PushCopyObjects(availability_change_event.GetReadableEvent()); | 462 | rb.PushCopyObjects(availability_change_event->GetReadableEvent()); |
| 259 | } | 463 | } |
| 260 | 464 | ||
| 261 | Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, | 465 | Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, |
| 262 | const char* name) | 466 | const char* name) |
| 263 | : ServiceFramework{system_, name}, nfc_tag_load{system.Kernel()}, module{std::move(module_)} { | 467 | : ServiceFramework{system_, name}, module{std::move(module_)}, |
| 264 | Kernel::KAutoObject::Create(std::addressof(nfc_tag_load)); | 468 | npad_id{Core::HID::NpadIdType::Player1}, service_context{system_, service_name} { |
| 265 | nfc_tag_load.Initialize("IUser:NFCTagDetected"); | 469 | activate_event = service_context.CreateEvent("IUser:NFPActivateEvent"); |
| 470 | deactivate_event = service_context.CreateEvent("IUser:NFPDeactivateEvent"); | ||
| 266 | } | 471 | } |
| 267 | 472 | ||
| 268 | Module::Interface::~Interface() = default; | 473 | Module::Interface::~Interface() = default; |
| @@ -272,25 +477,254 @@ void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { | |||
| 272 | 477 | ||
| 273 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 478 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 274 | rb.Push(ResultSuccess); | 479 | rb.Push(ResultSuccess); |
| 275 | rb.PushIpcInterface<IUser>(*this, system, service_context); | 480 | rb.PushIpcInterface<IUser>(*this, system); |
| 276 | } | 481 | } |
| 277 | 482 | ||
| 278 | bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { | 483 | bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { |
| 279 | if (buffer.size() < sizeof(AmiiboFile)) { | 484 | if (buffer.size() < sizeof(AmiiboFile)) { |
| 485 | LOG_ERROR(Service_NFP, "Wrong file size"); | ||
| 280 | return false; | 486 | return false; |
| 281 | } | 487 | } |
| 282 | 488 | ||
| 489 | if (device_state != DeviceState::SearchingForTag) { | ||
| 490 | LOG_ERROR(Service_NFP, "Game is not looking for amiibos, current state {}", device_state); | ||
| 491 | return false; | ||
| 492 | } | ||
| 493 | |||
| 494 | LOG_INFO(Service_NFP, "New Amiibo detected"); | ||
| 283 | std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); | 495 | std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); |
| 284 | nfc_tag_load->GetWritableEvent().Signal(); | 496 | device_state = DeviceState::TagFound; |
| 497 | activate_event->GetWritableEvent().Signal(); | ||
| 285 | return true; | 498 | return true; |
| 286 | } | 499 | } |
| 287 | 500 | ||
| 288 | Kernel::KReadableEvent& Module::Interface::GetNFCEvent() { | 501 | void Module::Interface::CloseAmiibo() { |
| 289 | return nfc_tag_load->GetReadableEvent(); | 502 | LOG_INFO(Service_NFP, "Remove amiibo"); |
| 503 | device_state = DeviceState::TagRemoved; | ||
| 504 | write_counter = 0; | ||
| 505 | is_application_area_initialized = false; | ||
| 506 | application_area_id = 0; | ||
| 507 | application_area_data.clear(); | ||
| 508 | deactivate_event->GetWritableEvent().Signal(); | ||
| 509 | } | ||
| 510 | |||
| 511 | Kernel::KReadableEvent& Module::Interface::GetActivateEvent() const { | ||
| 512 | return activate_event->GetReadableEvent(); | ||
| 513 | } | ||
| 514 | |||
| 515 | Kernel::KReadableEvent& Module::Interface::GetDeactivateEvent() const { | ||
| 516 | return deactivate_event->GetReadableEvent(); | ||
| 517 | } | ||
| 518 | |||
| 519 | void Module::Interface::Initialize() { | ||
| 520 | device_state = DeviceState::Initialized; | ||
| 521 | } | ||
| 522 | |||
| 523 | void Module::Interface::Finalize() { | ||
| 524 | device_state = DeviceState::Unaviable; | ||
| 525 | write_counter = 0; | ||
| 526 | is_application_area_initialized = false; | ||
| 527 | application_area_id = 0; | ||
| 528 | application_area_data.clear(); | ||
| 529 | } | ||
| 530 | |||
| 531 | ResultCode Module::Interface::StartDetection() { | ||
| 532 | auto npad_device = system.HIDCore().GetEmulatedController(npad_id); | ||
| 533 | |||
| 534 | // TODO(german77): Add callback for when nfc data is available | ||
| 535 | |||
| 536 | if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { | ||
| 537 | npad_device->SetPollingMode(Common::Input::PollingMode::NFC); | ||
| 538 | device_state = DeviceState::SearchingForTag; | ||
| 539 | return ResultSuccess; | ||
| 540 | } | ||
| 541 | |||
| 542 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||
| 543 | return ErrCodes::WrongDeviceState; | ||
| 544 | } | ||
| 545 | |||
| 546 | ResultCode Module::Interface::StopDetection() { | ||
| 547 | auto npad_device = system.HIDCore().GetEmulatedController(npad_id); | ||
| 548 | npad_device->SetPollingMode(Common::Input::PollingMode::Active); | ||
| 549 | |||
| 550 | if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) { | ||
| 551 | CloseAmiibo(); | ||
| 552 | return ResultSuccess; | ||
| 553 | } | ||
| 554 | if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { | ||
| 555 | device_state = DeviceState::Initialized; | ||
| 556 | return ResultSuccess; | ||
| 557 | } | ||
| 558 | |||
| 559 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||
| 560 | return ErrCodes::WrongDeviceState; | ||
| 561 | } | ||
| 562 | |||
| 563 | ResultCode Module::Interface::Mount() { | ||
| 564 | if (device_state == DeviceState::TagFound) { | ||
| 565 | device_state = DeviceState::TagMounted; | ||
| 566 | return ResultSuccess; | ||
| 567 | } | ||
| 568 | |||
| 569 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||
| 570 | return ErrCodes::WrongDeviceState; | ||
| 571 | } | ||
| 572 | |||
| 573 | ResultCode Module::Interface::Unmount() { | ||
| 574 | if (device_state == DeviceState::TagMounted) { | ||
| 575 | is_application_area_initialized = false; | ||
| 576 | application_area_id = 0; | ||
| 577 | application_area_data.clear(); | ||
| 578 | device_state = DeviceState::TagFound; | ||
| 579 | return ResultSuccess; | ||
| 580 | } | ||
| 581 | |||
| 582 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||
| 583 | return ErrCodes::WrongDeviceState; | ||
| 584 | } | ||
| 585 | |||
| 586 | ResultCode Module::Interface::GetTagInfo(TagInfo& tag_info) const { | ||
| 587 | if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) { | ||
| 588 | // Read this data from the amiibo save file | ||
| 589 | tag_info = { | ||
| 590 | .uuid = amiibo.uuid, | ||
| 591 | .uuid_length = static_cast<u8>(amiibo.uuid.size()), | ||
| 592 | .protocol = 0xFFFFFFFF, // TODO(ogniK): Figure out actual values | ||
| 593 | .tag_type = 0xFFFFFFFF, | ||
| 594 | }; | ||
| 595 | return ResultSuccess; | ||
| 596 | } | ||
| 597 | |||
| 598 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||
| 599 | return ErrCodes::WrongDeviceState; | ||
| 600 | } | ||
| 601 | |||
| 602 | ResultCode Module::Interface::GetCommonInfo(CommonInfo& common_info) const { | ||
| 603 | if (device_state != DeviceState::TagMounted) { | ||
| 604 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||
| 605 | return ErrCodes::WrongDeviceState; | ||
| 606 | } | ||
| 607 | |||
| 608 | // Read this data from the amiibo save file | ||
| 609 | common_info = { | ||
| 610 | .last_write_year = 2022, | ||
| 611 | .last_write_month = 2, | ||
| 612 | .last_write_day = 7, | ||
| 613 | .write_counter = write_counter, | ||
| 614 | .version = 1, | ||
| 615 | .application_area_size = ApplicationAreaSize, | ||
| 616 | }; | ||
| 617 | return ResultSuccess; | ||
| 618 | } | ||
| 619 | |||
| 620 | ResultCode Module::Interface::GetModelInfo(ModelInfo& model_info) const { | ||
| 621 | if (device_state != DeviceState::TagMounted) { | ||
| 622 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||
| 623 | return ErrCodes::WrongDeviceState; | ||
| 624 | } | ||
| 625 | |||
| 626 | model_info = amiibo.model_info; | ||
| 627 | return ResultSuccess; | ||
| 628 | } | ||
| 629 | |||
| 630 | ResultCode Module::Interface::GetRegisterInfo(RegisterInfo& register_info) const { | ||
| 631 | if (device_state != DeviceState::TagMounted) { | ||
| 632 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||
| 633 | return ErrCodes::WrongDeviceState; | ||
| 634 | } | ||
| 635 | |||
| 636 | Service::Mii::MiiManager manager; | ||
| 637 | |||
| 638 | // Read this data from the amiibo save file | ||
| 639 | register_info = { | ||
| 640 | .mii_char_info = manager.BuildDefault(0), | ||
| 641 | .first_write_year = 2022, | ||
| 642 | .first_write_month = 2, | ||
| 643 | .first_write_day = 7, | ||
| 644 | .amiibo_name = {'Y', 'u', 'z', 'u', 'A', 'm', 'i', 'i', 'b', 'o', 0}, | ||
| 645 | .unknown = {}, | ||
| 646 | }; | ||
| 647 | return ResultSuccess; | ||
| 648 | } | ||
| 649 | |||
| 650 | ResultCode Module::Interface::OpenApplicationArea(u32 access_id) { | ||
| 651 | if (device_state != DeviceState::TagMounted) { | ||
| 652 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||
| 653 | return ErrCodes::WrongDeviceState; | ||
| 654 | } | ||
| 655 | // if (AmiiboApplicationDataExist(access_id)) { | ||
| 656 | // application_area_data = LoadAmiiboApplicationData(access_id); | ||
| 657 | // application_area_id = access_id; | ||
| 658 | // is_application_area_initialized = true; | ||
| 659 | // } | ||
| 660 | if (!is_application_area_initialized) { | ||
| 661 | LOG_ERROR(Service_NFP, "Application area is not initialized"); | ||
| 662 | return ErrCodes::ApplicationAreaIsNotInitialized; | ||
| 663 | } | ||
| 664 | return ResultSuccess; | ||
| 665 | } | ||
| 666 | |||
| 667 | ResultCode Module::Interface::GetApplicationArea(std::vector<u8>& data) const { | ||
| 668 | if (device_state != DeviceState::TagMounted) { | ||
| 669 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||
| 670 | return ErrCodes::WrongDeviceState; | ||
| 671 | } | ||
| 672 | if (!is_application_area_initialized) { | ||
| 673 | LOG_ERROR(Service_NFP, "Application area is not initialized"); | ||
| 674 | return ErrCodes::ApplicationAreaIsNotInitialized; | ||
| 675 | } | ||
| 676 | |||
| 677 | data = application_area_data; | ||
| 678 | |||
| 679 | return ResultSuccess; | ||
| 680 | } | ||
| 681 | |||
| 682 | ResultCode Module::Interface::SetApplicationArea(const std::vector<u8>& data) { | ||
| 683 | if (device_state != DeviceState::TagMounted) { | ||
| 684 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||
| 685 | return ErrCodes::WrongDeviceState; | ||
| 686 | } | ||
| 687 | if (!is_application_area_initialized) { | ||
| 688 | LOG_ERROR(Service_NFP, "Application area is not initialized"); | ||
| 689 | return ErrCodes::ApplicationAreaIsNotInitialized; | ||
| 690 | } | ||
| 691 | application_area_data = data; | ||
| 692 | write_counter++; | ||
| 693 | // SaveAmiiboApplicationData(application_area_id,application_area_data); | ||
| 694 | return ResultSuccess; | ||
| 695 | } | ||
| 696 | |||
| 697 | ResultCode Module::Interface::CreateApplicationArea(u32 access_id, const std::vector<u8>& data) { | ||
| 698 | if (device_state != DeviceState::TagMounted) { | ||
| 699 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||
| 700 | return ErrCodes::WrongDeviceState; | ||
| 701 | } | ||
| 702 | // if (AmiiboApplicationDataExist(access_id)) { | ||
| 703 | // LOG_ERROR(Service_NFP, "Application area already exist"); | ||
| 704 | // return ErrCodes::ApplicationAreaExist; | ||
| 705 | // } | ||
| 706 | // if (LoadAmiiboApplicationData(access_id,data)) { | ||
| 707 | // is_application_area_initialized = true; | ||
| 708 | // application_area_id = access_id; | ||
| 709 | // } | ||
| 710 | application_area_data = data; | ||
| 711 | application_area_id = access_id; | ||
| 712 | write_counter = 0; | ||
| 713 | // SaveAmiiboApplicationData(application_area_id,application_area_data); | ||
| 714 | return ResultSuccess; | ||
| 715 | } | ||
| 716 | |||
| 717 | u64 Module::Interface::GetHandle() const { | ||
| 718 | // Generate a handle based of the npad id | ||
| 719 | return static_cast<u64>(npad_id); | ||
| 720 | } | ||
| 721 | |||
| 722 | DeviceState Module::Interface::GetCurrentState() const { | ||
| 723 | return device_state; | ||
| 290 | } | 724 | } |
| 291 | 725 | ||
| 292 | const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const { | 726 | Core::HID::NpadIdType Module::Interface::GetNpadId() const { |
| 293 | return amiibo; | 727 | return npad_id; |
| 294 | } | 728 | } |
| 295 | 729 | ||
| 296 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { | 730 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index 8d9db880a..4642ed634 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h | |||
| @@ -8,79 +8,155 @@ | |||
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | 9 | ||
| 10 | #include "core/hle/service/kernel_helpers.h" | 10 | #include "core/hle/service/kernel_helpers.h" |
| 11 | #include "core/hle/kernel/k_event.h" | 11 | #include "core/hle/service/mii/mii_manager.h" |
| 12 | #include "core/hle/service/mii/manager.h" | ||
| 13 | #include "core/hle/service/service.h" | 12 | #include "core/hle/service/service.h" |
| 14 | 13 | ||
| 15 | namespace Kernel { | 14 | namespace Kernel { |
| 16 | class KEvent; | 15 | class KEvent; |
| 17 | } | 16 | class KReadableEvent; |
| 17 | } // namespace Kernel | ||
| 18 | |||
| 19 | namespace Core::HID { | ||
| 20 | enum class NpadIdType : u32; | ||
| 21 | } // namespace Core::HID | ||
| 18 | 22 | ||
| 19 | namespace Service::NFP { | 23 | namespace Service::NFP { |
| 20 | 24 | ||
| 21 | enum class ServiceType : u32 { | 25 | enum class ServiceType : u32 { |
| 22 | User = 0, | 26 | User, |
| 23 | Debug = 1, | 27 | Debug, |
| 24 | System = 2, | 28 | System, |
| 25 | }; | 29 | }; |
| 26 | 30 | ||
| 27 | enum class State : u32 { | 31 | enum class State : u32 { |
| 28 | NonInitialized = 0, | 32 | NonInitialized, |
| 29 | Initialized = 1, | 33 | Initialized, |
| 30 | }; | 34 | }; |
| 31 | 35 | ||
| 32 | enum class DeviceState : u32 { | 36 | enum class DeviceState : u32 { |
| 33 | Initialized = 0, | 37 | Initialized, |
| 34 | SearchingForTag = 1, | 38 | SearchingForTag, |
| 35 | TagFound = 2, | 39 | TagFound, |
| 36 | TagRemoved = 3, | 40 | TagRemoved, |
| 37 | TagMounted = 4, | 41 | TagMounted, |
| 38 | Unaviable = 5, | 42 | Unaviable, |
| 39 | Finalized = 6 | 43 | Finalized, |
| 44 | }; | ||
| 45 | |||
| 46 | enum class ModelType : u32 { | ||
| 47 | Amiibo, | ||
| 40 | }; | 48 | }; |
| 41 | 49 | ||
| 42 | enum class MountTarget : u32 { | 50 | enum class MountTarget : u32 { |
| 43 | Rom = 1, | 51 | Rom, |
| 44 | Ram = 2, | 52 | Ram, |
| 45 | All = 3, | 53 | All, |
| 46 | }; | 54 | }; |
| 47 | 55 | ||
| 48 | struct TagInfo { | 56 | struct TagInfo { |
| 49 | std::array<u8, 10> uuid; | 57 | std::array<u8, 10> uuid; |
| 50 | u8 uuid_length; | 58 | u8 uuid_length; |
| 51 | INSERT_PADDING_BYTES(0x15); | 59 | INSERT_PADDING_BYTES(0x15); |
| 52 | u32_le protocol; | 60 | u32 protocol; |
| 53 | u32_le tag_type; | 61 | u32 tag_type; |
| 54 | INSERT_PADDING_BYTES(0x2c); | 62 | INSERT_PADDING_BYTES(0x30); |
| 55 | }; | 63 | }; |
| 56 | static_assert(sizeof(TagInfo) == 0x54, "TagInfo is an invalid size"); | 64 | static_assert(sizeof(TagInfo) == 0x58, "TagInfo is an invalid size"); |
| 57 | 65 | ||
| 58 | struct CommonInfo { | 66 | struct CommonInfo { |
| 59 | u16_be last_write_year; | 67 | u16 last_write_year; |
| 60 | u8 last_write_month; | 68 | u8 last_write_month; |
| 61 | u8 last_write_day; | 69 | u8 last_write_day; |
| 62 | u16_be write_counter; | 70 | u16 write_counter; |
| 63 | u16_be version; | 71 | u16 version; |
| 64 | u32_be application_area_size; | 72 | u32 application_area_size; |
| 65 | INSERT_PADDING_BYTES(0x34); | 73 | INSERT_PADDING_BYTES(0x34); |
| 66 | }; | 74 | }; |
| 67 | static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size"); | 75 | static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size"); |
| 68 | 76 | ||
| 69 | struct ModelInfo { | 77 | struct ModelInfo { |
| 70 | std::array<u8, 0x8> ammibo_id; | 78 | u16 character_id; |
| 71 | INSERT_PADDING_BYTES(0x38); | 79 | u8 character_variant; |
| 80 | u8 figure_type; | ||
| 81 | u16 model_number; | ||
| 82 | u8 series; | ||
| 83 | INSERT_PADDING_BYTES(0x39); | ||
| 72 | }; | 84 | }; |
| 73 | static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size"); | 85 | static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size"); |
| 74 | 86 | ||
| 75 | struct RegisterInfo { | 87 | struct RegisterInfo { |
| 76 | Service::Mii::MiiInfo mii; | 88 | Service::Mii::MiiInfo mii_char_info; |
| 77 | u16_be first_write_year; | 89 | u16 first_write_year; |
| 78 | u8 first_write_month; | 90 | u8 first_write_month; |
| 79 | u8 first_write_day; | 91 | u8 first_write_day; |
| 80 | std::array<u8, 11> amiibo_name; | 92 | std::array<u8, 11> amiibo_name; |
| 81 | INSERT_PADDING_BYTES(0x99); | 93 | u8 unknown; |
| 94 | INSERT_PADDING_BYTES(0x98); | ||
| 95 | }; | ||
| 96 | static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); | ||
| 97 | |||
| 98 | class Module final { | ||
| 99 | public: | ||
| 100 | class Interface : public ServiceFramework<Interface> { | ||
| 101 | public: | ||
| 102 | explicit Interface(std::shared_ptr<Module> module_, Core::System& system_, | ||
| 103 | const char* name); | ||
| 104 | ~Interface() override; | ||
| 105 | |||
| 106 | struct AmiiboFile { | ||
| 107 | std::array<u8, 10> uuid; | ||
| 108 | INSERT_PADDING_BYTES(0x4); // Compability container | ||
| 109 | INSERT_PADDING_BYTES(0x46); | ||
| 110 | ModelInfo model_info; | ||
| 111 | }; | ||
| 112 | static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size"); | ||
| 113 | |||
| 114 | void CreateUserInterface(Kernel::HLERequestContext& ctx); | ||
| 115 | bool LoadAmiibo(const std::vector<u8>& buffer); | ||
| 116 | void CloseAmiibo(); | ||
| 117 | |||
| 118 | void Initialize(); | ||
| 119 | void Finalize(); | ||
| 120 | |||
| 121 | ResultCode StartDetection(); | ||
| 122 | ResultCode StopDetection(); | ||
| 123 | ResultCode Mount(); | ||
| 124 | ResultCode Unmount(); | ||
| 125 | |||
| 126 | ResultCode GetTagInfo(TagInfo& tag_info) const; | ||
| 127 | ResultCode GetCommonInfo(CommonInfo& common_info) const; | ||
| 128 | ResultCode GetModelInfo(ModelInfo& model_info) const; | ||
| 129 | ResultCode GetRegisterInfo(RegisterInfo& register_info) const; | ||
| 130 | |||
| 131 | ResultCode OpenApplicationArea(u32 access_id); | ||
| 132 | ResultCode GetApplicationArea(std::vector<u8>& data) const; | ||
| 133 | ResultCode SetApplicationArea(const std::vector<u8>& data); | ||
| 134 | ResultCode CreateApplicationArea(u32 access_id, const std::vector<u8>& data); | ||
| 135 | |||
| 136 | u64 GetHandle() const; | ||
| 137 | DeviceState GetCurrentState() const; | ||
| 138 | Core::HID::NpadIdType GetNpadId() const; | ||
| 139 | |||
| 140 | Kernel::KReadableEvent& GetActivateEvent() const; | ||
| 141 | Kernel::KReadableEvent& GetDeactivateEvent() const; | ||
| 142 | |||
| 143 | protected: | ||
| 144 | std::shared_ptr<Module> module; | ||
| 145 | |||
| 146 | private: | ||
| 147 | const Core::HID::NpadIdType npad_id; | ||
| 148 | |||
| 149 | DeviceState device_state{DeviceState::Unaviable}; | ||
| 150 | KernelHelpers::ServiceContext service_context; | ||
| 151 | Kernel::KEvent* activate_event; | ||
| 152 | Kernel::KEvent* deactivate_event; | ||
| 153 | AmiiboFile amiibo{}; | ||
| 154 | u16 write_counter{}; | ||
| 155 | bool is_application_area_initialized{}; | ||
| 156 | u32 application_area_id; | ||
| 157 | std::vector<u8> application_area_data; | ||
| 158 | }; | ||
| 82 | }; | 159 | }; |
| 83 | // static_assert(sizeof(RegisterInfo) == 0x106, "RegisterInfo is an invalid size"); | ||
| 84 | 160 | ||
| 85 | class IUser final : public ServiceFramework<IUser> { | 161 | class IUser final : public ServiceFramework<IUser> { |
| 86 | public: | 162 | public: |
| @@ -96,6 +172,8 @@ private: | |||
| 96 | void Unmount(Kernel::HLERequestContext& ctx); | 172 | void Unmount(Kernel::HLERequestContext& ctx); |
| 97 | void OpenApplicationArea(Kernel::HLERequestContext& ctx); | 173 | void OpenApplicationArea(Kernel::HLERequestContext& ctx); |
| 98 | void GetApplicationArea(Kernel::HLERequestContext& ctx); | 174 | void GetApplicationArea(Kernel::HLERequestContext& ctx); |
| 175 | void SetApplicationArea(Kernel::HLERequestContext& ctx); | ||
| 176 | void CreateApplicationArea(Kernel::HLERequestContext& ctx); | ||
| 99 | void GetTagInfo(Kernel::HLERequestContext& ctx); | 177 | void GetTagInfo(Kernel::HLERequestContext& ctx); |
| 100 | void GetRegisterInfo(Kernel::HLERequestContext& ctx); | 178 | void GetRegisterInfo(Kernel::HLERequestContext& ctx); |
| 101 | void GetCommonInfo(Kernel::HLERequestContext& ctx); | 179 | void GetCommonInfo(Kernel::HLERequestContext& ctx); |
| @@ -108,50 +186,13 @@ private: | |||
| 108 | void GetApplicationAreaSize(Kernel::HLERequestContext& ctx); | 186 | void GetApplicationAreaSize(Kernel::HLERequestContext& ctx); |
| 109 | void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx); | 187 | void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx); |
| 110 | 188 | ||
| 111 | bool has_attached_handle{}; | 189 | KernelHelpers::ServiceContext service_context; |
| 112 | const u64 device_handle{0}; // Npad device 1 | ||
| 113 | const u32 npad_id{0}; // Player 1 controller | ||
| 114 | State state{State::NonInitialized}; | ||
| 115 | DeviceState device_state{DeviceState::Initialized}; | ||
| 116 | Module::Interface& nfp_interface; | ||
| 117 | Kernel::KEvent deactivate_event; | ||
| 118 | Kernel::KEvent availability_change_event; | ||
| 119 | }; | ||
| 120 | 190 | ||
| 121 | class Module final { | 191 | // TODO(german77): We should have a vector of interfaces |
| 122 | public: | 192 | Module::Interface& nfp_interface; |
| 123 | class Interface : public ServiceFramework<Interface> { | ||
| 124 | public: | ||
| 125 | explicit Interface(std::shared_ptr<Module> module_, Core::System& system_, | ||
| 126 | const char* name); | ||
| 127 | ~Interface() override; | ||
| 128 | |||
| 129 | struct ModelInfo { | ||
| 130 | std::array<u8, 0x8> amiibo_identification_block; | ||
| 131 | INSERT_PADDING_BYTES(0x38); | ||
| 132 | }; | ||
| 133 | static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size"); | ||
| 134 | |||
| 135 | struct AmiiboFile { | ||
| 136 | std::array<u8, 10> uuid; | ||
| 137 | INSERT_PADDING_BYTES(0x4a); | ||
| 138 | ModelInfo model_info; | ||
| 139 | }; | ||
| 140 | static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size"); | ||
| 141 | |||
| 142 | void CreateUserInterface(Kernel::HLERequestContext& ctx); | ||
| 143 | bool LoadAmiibo(const std::vector<u8>& buffer); | ||
| 144 | Kernel::KReadableEvent& GetNFCEvent(); | ||
| 145 | const AmiiboFile& GetAmiiboBuffer() const; | ||
| 146 | |||
| 147 | protected: | ||
| 148 | std::shared_ptr<Module> module; | ||
| 149 | 193 | ||
| 150 | private: | 194 | State state{State::NonInitialized}; |
| 151 | KernelHelpers::ServiceContext service_context; | 195 | Kernel::KEvent* availability_change_event; |
| 152 | Kernel::KEvent* nfc_tag_load; | ||
| 153 | AmiiboFile amiibo{}; | ||
| 154 | }; | ||
| 155 | }; | 196 | }; |
| 156 | 197 | ||
| 157 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); | 198 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |