From cc6a4bedfc01ef251cf9caf362997a1821fd1ffa Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 7 May 2022 15:28:51 -0500 Subject: 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`. --- src/core/hle/service/glue/notif.cpp | 132 +++++++++++++++++++++++++++++++++--- src/core/hle/service/glue/notif.h | 48 +++++++++++++ 2 files changed, 172 insertions(+), 8 deletions(-) diff --git a/src/core/hle/service/glue/notif.cpp b/src/core/hle/service/glue/notif.cpp index b971846e7..3ace2dabd 100644 --- a/src/core/hle/service/glue/notif.cpp +++ b/src/core/hle/service/glue/notif.cpp @@ -1,6 +1,11 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include +#include + +#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::RegisterAlarmSetting(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 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) { - // Returns an array of AlarmSetting - constexpr s32 alarm_count = 0; + LOG_INFO(Service_NOTIF, "called, alarm_count={}", alarms.size()); - LOG_WARNING(Service_NOTIF, "(STUBBED) called"); + // 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(alarms.size())); +} + +void NOTIF_A::LoadApplicationParameter(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto alarm_setting_id{rp.Pop()}; + + 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(application_parameter.size())); +} + +void NOTIF_A::DeleteAlarmSetting(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto alarm_setting_id{rp.Pop()}; + + 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::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 diff --git a/src/core/hle/service/glue/notif.h b/src/core/hle/service/glue/notif.h index 7310d7f72..4467e1f35 100644 --- a/src/core/hle/service/glue/notif.h +++ b/src/core/hle/service/glue/notif.h @@ -3,6 +3,10 @@ #pragma once +#include +#include + +#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; + 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 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::iterator GetAlarmFromId(AlarmSettingId alarm_setting_id); + + std::vector alarms{}; + AlarmSettingId last_alarm_setting_id{}; }; } // namespace Service::Glue -- cgit v1.2.3