service: notifa: Implement most part of this service
Implements partially RegisterAlarmSetting, UpdateAlarmSetting, LoadApplicationParameter, DeleteAlarmSetting. Needed for Fitness `Boxing 2: Rhythm & Exercise` and `Ring Fit Adventure`.
This commit is contained in:
		| @@ -1,6 +1,11 @@ | |||||||
| // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||||||
| // SPDX-License-Identifier: GPL-2.0-or-later | // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  | ||||||
|  | #include <algorithm> | ||||||
|  | #include <cstring> | ||||||
|  |  | ||||||
|  | #include "common/assert.h" | ||||||
|  | #include "common/logging/log.h" | ||||||
| #include "core/hle/ipc_helpers.h" | #include "core/hle/ipc_helpers.h" | ||||||
| #include "core/hle/service/glue/notif.h" | #include "core/hle/service/glue/notif.h" | ||||||
|  |  | ||||||
| @@ -9,11 +14,11 @@ namespace Service::Glue { | |||||||
| NOTIF_A::NOTIF_A(Core::System& system_) : ServiceFramework{system_, "notif:a"} { | NOTIF_A::NOTIF_A(Core::System& system_) : ServiceFramework{system_, "notif:a"} { | ||||||
|     // clang-format off |     // clang-format off | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {500, nullptr, "RegisterAlarmSetting"}, |         {500, &NOTIF_A::RegisterAlarmSetting, "RegisterAlarmSetting"}, | ||||||
|         {510, nullptr, "UpdateAlarmSetting"}, |         {510, &NOTIF_A::UpdateAlarmSetting, "UpdateAlarmSetting"}, | ||||||
|         {520, &NOTIF_A::ListAlarmSettings, "ListAlarmSettings"}, |         {520, &NOTIF_A::ListAlarmSettings, "ListAlarmSettings"}, | ||||||
|         {530, nullptr, "LoadApplicationParameter"}, |         {530, &NOTIF_A::LoadApplicationParameter, "LoadApplicationParameter"}, | ||||||
|         {540, nullptr, "DeleteAlarmSetting"}, |         {540, &NOTIF_A::DeleteAlarmSetting, "DeleteAlarmSetting"}, | ||||||
|         {1000, &NOTIF_A::Initialize, "Initialize"}, |         {1000, &NOTIF_A::Initialize, "Initialize"}, | ||||||
|     }; |     }; | ||||||
|     // clang-format on |     // clang-format on | ||||||
| @@ -23,21 +28,132 @@ NOTIF_A::NOTIF_A(Core::System& system_) : ServiceFramework{system_, "notif:a"} { | |||||||
|  |  | ||||||
| NOTIF_A::~NOTIF_A() = default; | NOTIF_A::~NOTIF_A() = default; | ||||||
|  |  | ||||||
| void NOTIF_A::ListAlarmSettings(Kernel::HLERequestContext& ctx) { | void NOTIF_A::RegisterAlarmSetting(Kernel::HLERequestContext& ctx) { | ||||||
|     // Returns an array of AlarmSetting |     const auto alarm_setting_buffer_size = ctx.GetReadBufferSize(0); | ||||||
|     constexpr s32 alarm_count = 0; |     const auto application_parameter_size = ctx.GetReadBufferSize(1); | ||||||
|  |  | ||||||
|     LOG_WARNING(Service_NOTIF, "(STUBBED) called"); |     ASSERT_MSG(alarm_setting_buffer_size == sizeof(AlarmSetting), | ||||||
|  |                "alarm_setting_buffer_size is not 0x40 bytes"); | ||||||
|  |     ASSERT_MSG(application_parameter_size <= sizeof(ApplicationParameter), | ||||||
|  |                "application_parameter_size is bigger than 0x400 bytes"); | ||||||
|  |  | ||||||
|  |     AlarmSetting new_alarm{}; | ||||||
|  |     memcpy(&new_alarm, ctx.ReadBuffer(0).data(), sizeof(AlarmSetting)); | ||||||
|  |  | ||||||
|  |     // TODO: Count alarms per game id | ||||||
|  |     if (alarms.size() >= max_alarms) { | ||||||
|  |         LOG_ERROR(Service_NOTIF, "Alarm limit reached"); | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(ResultUnknown); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     new_alarm.alarm_setting_id = last_alarm_setting_id++; | ||||||
|  |     alarms.push_back(new_alarm); | ||||||
|  |  | ||||||
|  |     // TODO: Save application parameter data | ||||||
|  |  | ||||||
|  |     LOG_WARNING(Service_NOTIF, | ||||||
|  |                 "(STUBBED) called, application_parameter_size={}, setting_id={}, kind={}, muted={}", | ||||||
|  |                 application_parameter_size, new_alarm.alarm_setting_id, new_alarm.kind, | ||||||
|  |                 new_alarm.muted); | ||||||
|  |  | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |     rb.Push(ResultSuccess); | ||||||
|  |     rb.Push(new_alarm.alarm_setting_id); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void NOTIF_A::UpdateAlarmSetting(Kernel::HLERequestContext& ctx) { | ||||||
|  |     const auto alarm_setting_buffer_size = ctx.GetReadBufferSize(0); | ||||||
|  |     const auto application_parameter_size = ctx.GetReadBufferSize(1); | ||||||
|  |  | ||||||
|  |     ASSERT_MSG(alarm_setting_buffer_size == sizeof(AlarmSetting), | ||||||
|  |                "alarm_setting_buffer_size is not 0x40 bytes"); | ||||||
|  |     ASSERT_MSG(application_parameter_size <= sizeof(ApplicationParameter), | ||||||
|  |                "application_parameter_size is bigger than 0x400 bytes"); | ||||||
|  |  | ||||||
|  |     AlarmSetting alarm_setting{}; | ||||||
|  |     memcpy(&alarm_setting, ctx.ReadBuffer(0).data(), sizeof(AlarmSetting)); | ||||||
|  |  | ||||||
|  |     const auto alarm_it = GetAlarmFromId(alarm_setting.alarm_setting_id); | ||||||
|  |     if (alarm_it != alarms.end()) { | ||||||
|  |         LOG_DEBUG(Service_NOTIF, "Alarm updated"); | ||||||
|  |         *alarm_it = alarm_setting; | ||||||
|  |         // TODO: Save application parameter data | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     LOG_WARNING(Service_NOTIF, | ||||||
|  |                 "(STUBBED) called, application_parameter_size={}, setting_id={}, kind={}, muted={}", | ||||||
|  |                 application_parameter_size, alarm_setting.alarm_setting_id, alarm_setting.kind, | ||||||
|  |                 alarm_setting.muted); | ||||||
|  |  | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |     rb.Push(ResultSuccess); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void NOTIF_A::ListAlarmSettings(Kernel::HLERequestContext& ctx) { | ||||||
|  |     LOG_INFO(Service_NOTIF, "called, alarm_count={}", alarms.size()); | ||||||
|  |  | ||||||
|  |     // TODO: Only return alarms of this game id | ||||||
|  |     ctx.WriteBuffer(alarms); | ||||||
|  |  | ||||||
|     IPC::ResponseBuilder rb{ctx, 3}; |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.Push(alarm_count); |     rb.Push(static_cast<u32>(alarms.size())); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void NOTIF_A::LoadApplicationParameter(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp{ctx}; | ||||||
|  |     const auto alarm_setting_id{rp.Pop<AlarmSettingId>()}; | ||||||
|  |  | ||||||
|  |     const auto alarm_it = GetAlarmFromId(alarm_setting_id); | ||||||
|  |     if (alarm_it == alarms.end()) { | ||||||
|  |         LOG_ERROR(Service_NOTIF, "Invalid alarm setting id={}", alarm_setting_id); | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(ResultUnknown); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // TODO: Read application parameter related to this setting id | ||||||
|  |     ApplicationParameter application_parameter{}; | ||||||
|  |  | ||||||
|  |     LOG_WARNING(Service_NOTIF, "(STUBBED) called, alarm_setting_id={}", alarm_setting_id); | ||||||
|  |  | ||||||
|  |     ctx.WriteBuffer(application_parameter); | ||||||
|  |  | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |     rb.Push(ResultSuccess); | ||||||
|  |     rb.Push(static_cast<u32>(application_parameter.size())); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void NOTIF_A::DeleteAlarmSetting(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp{ctx}; | ||||||
|  |     const auto alarm_setting_id{rp.Pop<AlarmSettingId>()}; | ||||||
|  |  | ||||||
|  |     std::erase_if(alarms, [alarm_setting_id](const AlarmSetting& alarm) { | ||||||
|  |         return alarm.alarm_setting_id == alarm_setting_id; | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     LOG_INFO(Service_NOTIF, "called, alarm_setting_id={}", alarm_setting_id); | ||||||
|  |  | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
|  |  | ||||||
| void NOTIF_A::Initialize(Kernel::HLERequestContext& ctx) { | void NOTIF_A::Initialize(Kernel::HLERequestContext& ctx) { | ||||||
|  |     // TODO: Load previous alarms from config | ||||||
|  |  | ||||||
|     LOG_WARNING(Service_NOTIF, "(STUBBED) called"); |     LOG_WARNING(Service_NOTIF, "(STUBBED) called"); | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | std::vector<NOTIF_A::AlarmSetting>::iterator NOTIF_A::GetAlarmFromId( | ||||||
|  |     AlarmSettingId alarm_setting_id) { | ||||||
|  |     return std::find_if(alarms.begin(), alarms.end(), | ||||||
|  |                         [alarm_setting_id](const AlarmSetting& alarm) { | ||||||
|  |                             return alarm.alarm_setting_id == alarm_setting_id; | ||||||
|  |                         }); | ||||||
|  | } | ||||||
|  |  | ||||||
| } // namespace Service::Glue | } // namespace Service::Glue | ||||||
|   | |||||||
| @@ -3,6 +3,10 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
|  | #include <array> | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | #include "common/uuid.h" | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
|  |  | ||||||
| namespace Core { | namespace Core { | ||||||
| @@ -17,8 +21,52 @@ public: | |||||||
|     ~NOTIF_A() override; |     ~NOTIF_A() override; | ||||||
|  |  | ||||||
| private: | private: | ||||||
|  |     static constexpr std::size_t max_alarms = 8; | ||||||
|  |  | ||||||
|  |     // This is nn::notification::AlarmSettingId | ||||||
|  |     using AlarmSettingId = u16; | ||||||
|  |     static_assert(sizeof(AlarmSettingId) == 0x2, "AlarmSettingId is an invalid size"); | ||||||
|  |  | ||||||
|  |     using ApplicationParameter = std::array<u8, 0x400>; | ||||||
|  |     static_assert(sizeof(ApplicationParameter) == 0x400, "ApplicationParameter is an invalid size"); | ||||||
|  |  | ||||||
|  |     struct DailyAlarmSetting { | ||||||
|  |         s8 hour; | ||||||
|  |         s8 minute; | ||||||
|  |     }; | ||||||
|  |     static_assert(sizeof(DailyAlarmSetting) == 0x2, "DailyAlarmSetting is an invalid size"); | ||||||
|  |  | ||||||
|  |     struct WeeklyScheduleAlarmSetting { | ||||||
|  |         INSERT_PADDING_BYTES(0xA); | ||||||
|  |         std::array<DailyAlarmSetting, 0x7> day_of_week; | ||||||
|  |     }; | ||||||
|  |     static_assert(sizeof(WeeklyScheduleAlarmSetting) == 0x18, | ||||||
|  |                   "WeeklyScheduleAlarmSetting is an invalid size"); | ||||||
|  |  | ||||||
|  |     // This is nn::notification::AlarmSetting | ||||||
|  |     struct AlarmSetting { | ||||||
|  |         AlarmSettingId alarm_setting_id; | ||||||
|  |         u8 kind; | ||||||
|  |         u8 muted; | ||||||
|  |         INSERT_PADDING_BYTES(0x4); | ||||||
|  |         Common::UUID account_id; | ||||||
|  |         u64 application_id; | ||||||
|  |         INSERT_PADDING_BYTES(0x8); | ||||||
|  |         WeeklyScheduleAlarmSetting schedule; | ||||||
|  |     }; | ||||||
|  |     static_assert(sizeof(AlarmSetting) == 0x40, "AlarmSetting is an invalid size"); | ||||||
|  |  | ||||||
|  |     void RegisterAlarmSetting(Kernel::HLERequestContext& ctx); | ||||||
|  |     void UpdateAlarmSetting(Kernel::HLERequestContext& ctx); | ||||||
|     void ListAlarmSettings(Kernel::HLERequestContext& ctx); |     void ListAlarmSettings(Kernel::HLERequestContext& ctx); | ||||||
|  |     void LoadApplicationParameter(Kernel::HLERequestContext& ctx); | ||||||
|  |     void DeleteAlarmSetting(Kernel::HLERequestContext& ctx); | ||||||
|     void Initialize(Kernel::HLERequestContext& ctx); |     void Initialize(Kernel::HLERequestContext& ctx); | ||||||
|  |  | ||||||
|  |     std::vector<AlarmSetting>::iterator GetAlarmFromId(AlarmSettingId alarm_setting_id); | ||||||
|  |  | ||||||
|  |     std::vector<AlarmSetting> alarms{}; | ||||||
|  |     AlarmSettingId last_alarm_setting_id{}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| } // namespace Service::Glue | } // namespace Service::Glue | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user