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-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/service/glue/notif.h" | ||||
|  | ||||
| @@ -9,11 +14,11 @@ namespace Service::Glue { | ||||
| NOTIF_A::NOTIF_A(Core::System& system_) : ServiceFramework{system_, "notif:a"} { | ||||
|     // clang-format off | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {500, nullptr, "RegisterAlarmSetting"}, | ||||
|         {510, nullptr, "UpdateAlarmSetting"}, | ||||
|         {500, &NOTIF_A::RegisterAlarmSetting, "RegisterAlarmSetting"}, | ||||
|         {510, &NOTIF_A::UpdateAlarmSetting, "UpdateAlarmSetting"}, | ||||
|         {520, &NOTIF_A::ListAlarmSettings, "ListAlarmSettings"}, | ||||
|         {530, nullptr, "LoadApplicationParameter"}, | ||||
|         {540, nullptr, "DeleteAlarmSetting"}, | ||||
|         {530, &NOTIF_A::LoadApplicationParameter, "LoadApplicationParameter"}, | ||||
|         {540, &NOTIF_A::DeleteAlarmSetting, "DeleteAlarmSetting"}, | ||||
|         {1000, &NOTIF_A::Initialize, "Initialize"}, | ||||
|     }; | ||||
|     // clang-format on | ||||
| @@ -23,21 +28,132 @@ NOTIF_A::NOTIF_A(Core::System& system_) : ServiceFramework{system_, "notif:a"} { | ||||
|  | ||||
| NOTIF_A::~NOTIF_A() = default; | ||||
|  | ||||
| void NOTIF_A::ListAlarmSettings(Kernel::HLERequestContext& ctx) { | ||||
|     // Returns an array of AlarmSetting | ||||
|     constexpr s32 alarm_count = 0; | ||||
| void NOTIF_A::RegisterAlarmSetting(Kernel::HLERequestContext& ctx) { | ||||
|     const auto alarm_setting_buffer_size = ctx.GetReadBufferSize(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}; | ||||
|     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) { | ||||
|     // TODO: Load previous alarms from config | ||||
|  | ||||
|     LOG_WARNING(Service_NOTIF, "(STUBBED) called"); | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     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 | ||||
|   | ||||
| @@ -3,6 +3,10 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <array> | ||||
| #include <vector> | ||||
|  | ||||
| #include "common/uuid.h" | ||||
| #include "core/hle/service/service.h" | ||||
|  | ||||
| namespace Core { | ||||
| @@ -17,8 +21,52 @@ public: | ||||
|     ~NOTIF_A() override; | ||||
|  | ||||
| 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 LoadApplicationParameter(Kernel::HLERequestContext& ctx); | ||||
|     void DeleteAlarmSetting(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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user