I don't like abstract npad

This commit is contained in:
Narr the Reg 2023-08-17 23:32:39 -06:00
parent 74a1fba8e0
commit d669f7e15f
10 changed files with 491 additions and 23 deletions

View File

@ -534,6 +534,7 @@ add_library(core STATIC
hle/service/hid/resource_manager/npad_resource/npad_controller_state.h
hle/service/hid/resource_manager/npad_resource/npad_state.cpp
hle/service/hid/resource_manager/npad_resource/npad_state.h
hle/service/hid/resource_manager/npad_resource/npad_shared_types.h
hle/service/hid/resource_manager/base_resource.cpp
hle/service/hid/resource_manager/base_resource.h
hle/service/hid/resource_manager/debug_pad.cpp
@ -546,6 +547,7 @@ add_library(core STATIC
hle/service/hid/resource_manager/mouse.h
hle/service/hid/resource_manager/palma.cpp
hle/service/hid/resource_manager/palma.h
hle/service/hid/resource_manager/ring_lifo.h
hle/service/hid/resource_manager/sixaxis.cpp
hle/service/hid/resource_manager/sixaxis.h
hle/service/hid/resource_manager/touch_screen.cpp

View File

@ -1264,7 +1264,7 @@ void IHidServer::ActivateNpad(HLERequestContext& ctx) {
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
const auto npad = GetResourceManager()->GetNpad();
npad->ActivateWithRevision(applet_resource_user_id, 0);
npad->ActivateWithRevision(applet_resource_user_id, NpadRevision::Revision0);
const auto result = npad->Activate(applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
@ -1370,7 +1370,7 @@ void IHidServer::GetPlayerLedPattern(HLERequestContext& ctx) {
void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
s32 revision;
NpadRevision revision;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};

View File

@ -220,15 +220,15 @@ enum class NpadIdType : u32 {
Invalid = 0xFFFFFFFF,
};
enum class MaskIndex : u32 {
Normal = 0,
GC = 1,
Extended = 2,
Full = 3,
enum class NpadRevision : u32 {
Revision0 = 0,
Revision1 = 1,
Revision2 = 2,
Revision3 = 3,
};
static_assert(sizeof(MaskIndex) == 4, "MaskIndex is an invalid size");
static_assert(sizeof(NpadRevision) == 4, "NpadRevision is an invalid size");
// This is nn::hid::NpadStyleIndex
// This is nn::hid::NpadStyleIndex
enum class NpadStyleIndex : u8 {
None = 0,
FullKey = 3,
@ -271,7 +271,6 @@ enum class NpadStyleSet : u32 {
DECLARE_ENUM_FLAG_OPERATORS(NpadStyleSet);
static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size");
// This is nn::hid::VibrationDevicePosition
enum class VibrationDevicePosition : u32 {
None = 0,
@ -364,6 +363,131 @@ enum class NpadJoyHoldType : u64 {
Horizontal = 1,
};
// This is nn::hid::system::AppletFooterUiAttributesSet
struct AppletFooterUiAttributes {
INSERT_PADDING_BYTES(0x4);
};
// This is nn::hid::system::AppletFooterUiType
enum class AppletFooterUiType : u8 {
None = 0,
HandheldNone = 1,
HandheldJoyConLeftOnly = 1,
HandheldJoyConRightOnly = 3,
HandheldJoyConLeftJoyConRight = 4,
JoyDual = 5,
JoyDualLeftOnly = 6,
JoyDualRightOnly = 7,
JoyLeftHorizontal = 8,
JoyLeftVertical = 9,
JoyRightHorizontal = 10,
JoyRightVertical = 11,
SwitchProController = 12,
CompatibleProController = 13,
CompatibleJoyCon = 14,
LarkHvc1 = 15,
LarkHvc2 = 16,
LarkNesLeft = 17,
LarkNesRight = 18,
Lucia = 19,
Verification = 20,
Lagon = 21,
};
// This is nn::hid::detail::ColorAttribute
enum class ColorAttribute : u32 {
Ok = 0,
ReadError = 1,
NoController = 2,
};
static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size");
// This is nn::hid::NpadLarkType
enum class NpadLarkType : u32 {
Invalid,
H1,
H2,
NL,
NR,
};
// This is nn::hid::NpadLuciaType
enum class NpadLuciaType : u32 {
Invalid,
J,
E,
U,
};
// This is nn::hid::NpadLagonType
enum class NpadLagonType : u32 {
Invalid,
};
// This is nn::hid::NpadLagerType
enum class NpadLagerType : u32 {
Invalid,
J,
E,
U,
};
// This is nn::hid::NpadSystemProperties
struct NPadSystemProperties {
union {
s64 raw{};
BitField<0, 1, s64> is_charging_joy_dual;
BitField<1, 1, s64> is_charging_joy_left;
BitField<2, 1, s64> is_charging_joy_right;
BitField<3, 1, s64> is_powered_joy_dual;
BitField<4, 1, s64> is_powered_joy_left;
BitField<5, 1, s64> is_powered_joy_right;
BitField<9, 1, s64> is_system_unsupported_button;
BitField<10, 1, s64> is_system_ext_unsupported_button;
BitField<11, 1, s64> is_vertical;
BitField<12, 1, s64> is_horizontal;
BitField<13, 1, s64> use_plus;
BitField<14, 1, s64> use_minus;
BitField<15, 1, s64> use_directional_buttons;
};
};
static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size");
// This is nn::hid::NpadSystemButtonProperties
struct NpadSystemButtonProperties {
union {
s32 raw{};
BitField<0, 1, s32> is_home_button_protection_enabled;
};
};
static_assert(sizeof(NpadSystemButtonProperties) == 0x4, "NPadButtonProperties is an invalid size");
// This is nn::hid::system::DeviceType
struct DeviceType {
union {
u32 raw{};
BitField<0, 1, s32> fullkey;
BitField<1, 1, s32> debug_pad;
BitField<2, 1, s32> handheld_left;
BitField<3, 1, s32> handheld_right;
BitField<4, 1, s32> joycon_left;
BitField<5, 1, s32> joycon_right;
BitField<6, 1, s32> palma;
BitField<7, 1, s32> lark_hvc_left;
BitField<8, 1, s32> lark_hvc_right;
BitField<9, 1, s32> lark_nes_left;
BitField<10, 1, s32> lark_nes_right;
BitField<11, 1, s32> handheld_lark_hvc_left;
BitField<12, 1, s32> handheld_lark_hvc_right;
BitField<13, 1, s32> handheld_lark_nes_left;
BitField<14, 1, s32> handheld_lark_nes_right;
BitField<15, 1, s32> lucia;
BitField<16, 1, s32> lagon;
BitField<17, 1, s32> lager;
BitField<31, 1, s32> system;
};
};
// This is nn::hid::TouchAttribute
struct TouchAttribute {
union {
@ -374,6 +498,20 @@ struct TouchAttribute {
};
static_assert(sizeof(TouchAttribute) == 0x4, "TouchAttribute is an invalid size");
// This is nn::hid::NpadAttribute
struct NpadAttribute {
union {
u32 raw{};
BitField<0, 1, u32> is_connected;
BitField<1, 1, u32> is_wired;
BitField<2, 1, u32> is_left_connected;
BitField<3, 1, u32> is_left_wired;
BitField<4, 1, u32> is_right_connected;
BitField<5, 1, u32> is_right_wired;
};
};
static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size");
// This is nn::hid::TouchState
struct TouchState {
u64 delta_time{};

View File

@ -7,6 +7,7 @@ namespace Service::HID {
constexpr std::size_t ARUID_MAX = 0x2; // Console real limit is 0x20
constexpr std::size_t PLAYERS_MAX = 10;
constexpr std::size_t SUPPORTED_NPAD_TYPES_MAX = 11;
constexpr std::size_t HID_ENTRY_COUNT = 17;
class BaseResource {
public:

View File

@ -8,9 +8,69 @@
#include "core/hle/service/hid/resource_manager/npad_resource/npad.h"
#include "core/hle/service/hid/resource_manager/npad_resource/npad_controller_state.h"
#include "core/hle/service/hid/resource_manager/npad_resource/npad_state.h"
#include "core/hle/service/hid/resource_manager/npad_resource/npad_shared_types.h"
namespace Service::HID {
AbstractNpadState::AbstractNpadState() {}
AbstractNpadState::~AbstractNpadState() = default;
Result AbstractNpadState::ActivateNpad(const u64 aruid) {
Result result{}; // UpdateSpecial Controller State
if (result.IsSuccess()) {
result = UpdateNpadLifo(aruid);
if (result.IsError()) {
return result;
}
result = UpdateSixaxisLifo(aruid);
if (result.IsError()) {
return result;
}
result = UpdateBatteryLifo(aruid);
}
return result;
}
Result AbstractNpadState::UpdateNpadLifo(const u64 aruid) {}
Result AbstractNpadState::UpdateSixaxisLifo(const u64 aruid) {}
Result AbstractNpadState::UpdateBatteryLifo(const u64 aruid) {}
void AbstractNpadState::UpdateNpadLifoImpl(const BatteryState& battery_state,
NpadInternalState& internal_state) {}
void AbstractNpadState::UpdateSixaxisLifoImpl(const BatteryState& battery_state,
NpadInternalState& internal_state) {
}
void AbstractNpadState::UpdateBatteryLifoImpl(const BatteryState& battery_state,
NpadInternalState& internal_state) {
NPadSystemProperties properties{};
if (battery_state.is_powered_joy_dual) {
properties.is_powered_joy_dual.Assign(1);
}
if (battery_state.is_powered_joy_left) {
properties.is_powered_joy_left.Assign(1);
}
if (battery_state.is_powered_joy_right) {
properties.is_powered_joy_right.Assign(1);
}
if (battery_state.is_charging_joy_dual) {
properties.is_charging_joy_dual.Assign(1);
}
if (battery_state.is_charging_joy_left) {
properties.is_charging_joy_left.Assign(1);
}
if (battery_state.is_charging_joy_right) {
properties.is_charging_joy_right.Assign(1);
}
internal_state.system_properties = properties;
internal_state.battery_level_dual = battery_state.battery_level_dual;
internal_state.battery_level_left = battery_state.battery_level_left;
internal_state.battery_level_right = battery_state.battery_level_right;
}
Npad::Npad(KernelHelpers::ServiceContext& context) : service_context{context} {
for (auto& npad : npad_state) {
npad = std::make_shared<NpadState>();
@ -26,11 +86,28 @@ Npad::Npad(KernelHelpers::ServiceContext& context) : service_context{context} {
Npad::~Npad() = default;
Result Npad::Activate(const u64 aruid) {
// No mistake was made here. It uses two different locks
std::scoped_lock lock{mutex};
std::scoped_lock lock{recursive_mutex};
for (std::size_t i = 0; i < PLAYERS_MAX; ++i) {
const Result result= abstract_npad_state[i]->ActivateNpad(aruid);
if (result.IsError()) {
return result;
}
}
return ResultSuccess;
}
Result Npad::ActivateWithRevision(const u64 aruid, const s32 revision) {
return ResultSuccess;
void Npad::ActivateWithRevision(const u64 aruid, const NpadRevision revision) {
const auto index = GetIndexFromAruid(aruid);
if (index >= ARUID_MAX) {
return;
}
npad_state[index]->SetNpadRevision(revision);
}
void Npad::DisconnectNpad(const u64 aruid, const NpadIdType npad_id) {
@ -711,19 +788,19 @@ Result Npad::GetMaskedSupportedNpadStyleSetImpl(const u64 aruid,
out_npad_styleset = npad_state[index]->GetSupportedNpadStyleSet();
if (index < ARUID_MAX) {
switch (npad_state[index]->GetMaskIndex()) {
case MaskIndex::GC:
switch (npad_state[index]->GetNpadRevision()) {
case NpadRevision::Revision1:
mask = NpadStyleSet::Fullkey | NpadStyleSet::Handheld | NpadStyleSet::JoyDual |
NpadStyleSet::JoyLeft | NpadStyleSet::JoyRight | NpadStyleSet::Gc |
NpadStyleSet::SystemExt | NpadStyleSet::System;
break;
case MaskIndex::Extended:
case NpadRevision::Revision2:
mask = NpadStyleSet::Fullkey | NpadStyleSet::Handheld | NpadStyleSet::JoyDual |
NpadStyleSet::JoyLeft | NpadStyleSet::JoyRight | NpadStyleSet::Gc |
NpadStyleSet::Palma | NpadStyleSet::Lark | NpadStyleSet::SystemExt |
NpadStyleSet::System;
break;
case MaskIndex::Full:
case NpadRevision::Revision3:
mask = NpadStyleSet::Fullkey | NpadStyleSet::Handheld | NpadStyleSet::JoyDual |
NpadStyleSet::JoyLeft | NpadStyleSet::JoyRight | NpadStyleSet::Gc |
NpadStyleSet::Palma | NpadStyleSet::Lark | NpadStyleSet::HandheldLark |

View File

@ -29,22 +29,60 @@ enum class NpadJoyDeviceType : s64;
enum class NpadStyleSet : u32;
enum class NpadJoyHoldType : u64;
enum class NpadButton : u64;
enum class MaskIndex : u32;
enum class NpadRevision : u32;
struct SixAxisSensorHandle;
struct NpadInternalState;
class NpadState;
} // namespace Service::HID
namespace Service::HID {
class AbstractNpadState {
public:
explicit AbstractNpadState();
~AbstractNpadState();
Result ActivateNpad(const u64 aruid);
private:
struct BatteryState {
INSERT_PADDING_BYTES(0x1c);
bool is_powered_joy_dual;
bool is_charging_joy_dual;
INSERT_PADDING_BYTES(0x6);
NpadBatteryLevel battery_level_dual;
bool is_powered_joy_left;
bool is_charging_joy_left;
INSERT_PADDING_BYTES(0x6);
NpadBatteryLevel battery_level_left;
bool is_powered_joy_right;
bool is_charging_joy_right;
INSERT_PADDING_BYTES(0x6);
NpadBatteryLevel battery_level_right;
};
static_assert(sizeof(BatteryState) == 0x40, "BatteryState is an invalid size");
Result UpdateNpadLifo(const u64 aruid);
Result UpdateSixaxisLifo(const u64 aruid);
Result UpdateBatteryLifo(const u64 aruid);
void UpdateNpadLifoImpl(const BatteryState& battery_state, NpadInternalState& internal_state);
void UpdateSixaxisLifoImpl(const BatteryState& battery_state,
NpadInternalState& internal_state);
void UpdateBatteryLifoImpl(const BatteryState& battery_state,
NpadInternalState& internal_state);
};
class Npad final : public BaseResource {
public:
explicit Npad(KernelHelpers::ServiceContext& context);
~Npad();
Result Activate(const u64 aruid);
Result ActivateWithRevision(const u64 aruid, const s32 revision);
void ActivateWithRevision(const u64 aruid, const NpadRevision revision);
void DisconnectNpad(const u64 aruid, const NpadIdType npad_id);
void ForceDisconnectNpad(const NpadIdType npad_id);
void DisconnectAbstractPad(const NpadIdType npad_id);
@ -136,10 +174,12 @@ private:
u64 GetNpadActiveAruid();
mutable std::mutex mutex;
mutable std::recursive_mutex recursive_mutex;
u64 active_aruid{};
std::shared_ptr<NpadState> active_npad_state = nullptr;
NpadJoyHoldType default_joy_hold_type{};
std::array<std::shared_ptr<NpadState>, ARUID_MAX> npad_state{};
std::array<std::shared_ptr<AbstractNpadState>, PLAYERS_MAX> abstract_npad_state;
KernelHelpers::ServiceContext& service_context;
};

View File

@ -0,0 +1,151 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <array>
#include <memory>
#include <mutex>
#include <span>
#include "common/common_types.h"
#include "common/vector_math.h"
#include "core/hle/service/hid/hid_types.h"
#include "core/hle/service/hid/resource_manager/base_resource.h"
#include "core/hle/service/hid/resource_manager/ring_lifo.h"
namespace Service::HID {
// This is nn::hid::detail::NpadFullKeyColorState
struct NpadFullKeyColorState {
ColorAttribute attribute{ColorAttribute::NoController};
NpadControllerColor fullkey{};
};
static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size");
// This is nn::hid::detail::NpadJoyColorState
struct NpadJoyColorState {
ColorAttribute attribute{ColorAttribute::NoController};
NpadControllerColor left{};
NpadControllerColor right{};
};
static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size");
// This is nn::hid::NpadFullKeyState
// This is nn::hid::NpadHandheldState
// This is nn::hid::NpadJoyDualState
// This is nn::hid::NpadJoyLeftState
// This is nn::hid::NpadJoyRightState
// This is nn::hid::NpadPalmaState
// This is nn::hid::NpadSystemExtState
struct NPadGenericState {
s64_le sampling_number{};
NpadButtonState npad_buttons{};
AnalogStickState l_stick{};
AnalogStickState r_stick{};
NpadAttribute connection_status{};
INSERT_PADDING_BYTES(4); // Reserved
};
static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size");
// This is nn::hid::SixAxisSensorAttribute
struct SixAxisSensorAttribute {
union {
u32 raw{};
BitField<0, 1, u32> is_connected;
BitField<1, 1, u32> is_interpolated;
};
};
static_assert(sizeof(SixAxisSensorAttribute) == 4, "SixAxisSensorAttribute is an invalid size");
// This is nn::hid::SixAxisSensorState
struct SixAxisSensorState {
s64 delta_time{};
s64 sampling_number{};
Common::Vec3f accel{};
Common::Vec3f gyro{};
Common::Vec3f rotation{};
std::array<Common::Vec3f, 3> orientation{};
SixAxisSensorAttribute attribute{};
INSERT_PADDING_BYTES(4); // Reserved
};
static_assert(sizeof(SixAxisSensorState) == 0x60, "SixAxisSensorState is an invalid size");
// This is nn::hid::server::NpadGcTriggerState
struct NpadGcTriggerState {
s64 sampling_number{};
s32 l_analog{};
s32 r_analog{};
};
static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
// This is nn::hid::detail::NfcXcdDeviceHandleStateImpl
struct NfcXcdDeviceHandleStateImpl {
u64 handle{};
bool is_available{};
bool is_activated{};
INSERT_PADDING_BYTES(0x6); // Reserved
u64 sampling_number{};
};
static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18,
"NfcXcdDeviceHandleStateImpl is an invalid size");
struct AppletFooterUi {
AppletFooterUiAttributes attributes{};
AppletFooterUiType type{AppletFooterUiType::None};
INSERT_PADDING_BYTES(0x5B); // Reserved
};
static_assert(sizeof(AppletFooterUi) == 0x60, "AppletFooterUi is an invalid size");
struct AppletNfcXcd {
union {
AppletFooterUi applet_footer{};
Lifo<NfcXcdDeviceHandleStateImpl, 0x2> nfc_xcd_device_lifo;
};
};
// This is nn::hid::detail::NpadInternalState
struct NpadInternalState {
NpadStyleTag style_tag{NpadStyleSet::None};
NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual};
NpadFullKeyColorState fullkey_color{};
NpadJoyColorState joycon_color{};
Lifo<NPadGenericState, HID_ENTRY_COUNT> fullkey_lifo{};
Lifo<NPadGenericState, HID_ENTRY_COUNT> handheld_lifo{};
Lifo<NPadGenericState, HID_ENTRY_COUNT> joy_dual_lifo{};
Lifo<NPadGenericState, HID_ENTRY_COUNT> joy_left_lifo{};
Lifo<NPadGenericState, HID_ENTRY_COUNT> joy_right_lifo{};
Lifo<NPadGenericState, HID_ENTRY_COUNT> palma_lifo{};
Lifo<NPadGenericState, HID_ENTRY_COUNT> system_ext_lifo{};
Lifo<SixAxisSensorState, HID_ENTRY_COUNT> sixaxis_fullkey_lifo{};
Lifo<SixAxisSensorState, HID_ENTRY_COUNT> sixaxis_handheld_lifo{};
Lifo<SixAxisSensorState, HID_ENTRY_COUNT> sixaxis_dual_left_lifo{};
Lifo<SixAxisSensorState, HID_ENTRY_COUNT> sixaxis_dual_right_lifo{};
Lifo<SixAxisSensorState, HID_ENTRY_COUNT> sixaxis_left_lifo{};
Lifo<SixAxisSensorState, HID_ENTRY_COUNT> sixaxis_right_lifo{};
DeviceType device_type{};
INSERT_PADDING_BYTES(0x4); // Reserved
NPadSystemProperties system_properties{};
NpadSystemButtonProperties button_properties{};
NpadBatteryLevel battery_level_dual{};
NpadBatteryLevel battery_level_left{};
NpadBatteryLevel battery_level_right{};
AppletNfcXcd applet_nfc_xcd{};
INSERT_PADDING_BYTES(0x20); // Unknown
Lifo<NpadGcTriggerState, HID_ENTRY_COUNT> gc_trigger_lifo{};
NpadLarkType lark_type_l_and_main{};
NpadLarkType lark_type_r{};
NpadLuciaType lucia_type{};
NpadLagonType lagon_type{};
NpadLagerType lager_type{};
SixAxisSensorProperties sixaxis_fullkey_properties;
SixAxisSensorProperties sixaxis_handheld_properties;
SixAxisSensorProperties sixaxis_dual_left_properties;
SixAxisSensorProperties sixaxis_dual_right_properties;
SixAxisSensorProperties sixaxis_left_properties;
SixAxisSensorProperties sixaxis_right_properties;
INSERT_PADDING_BYTES(0xc06); // Unknown
};
static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size");
} // namespace Service::HID

View File

@ -194,8 +194,13 @@ void NpadState::SetAssigningSingleOnSlSrPress(const bool is_enabled) {
data.status.assigning_single_on_sl_sr_press.Assign(is_enabled);
}
MaskIndex NpadState::GetMaskIndex() const {
return mask_index;
NpadRevision NpadState::GetNpadRevision() const {
return npad_revision;
}
void NpadState::SetNpadRevision(const NpadRevision revision) {
npad_revision = revision;
}
} // namespace Service::HID

View File

@ -19,7 +19,7 @@ enum class NpadHandheldActivationMode : u64;
enum class NpadStyleSet : u32;
enum class NpadJoyHoldType : u64;
enum class NpadButton : u64;
enum class MaskIndex : u32;
enum class NpadRevision : u32;
class NpadControllerState;
} // namespace Service::HID
@ -75,7 +75,8 @@ public:
bool GetAssigningSingleOnSlSrPress() const;
void SetAssigningSingleOnSlSrPress(const bool is_enabled);
MaskIndex GetMaskIndex() const;
NpadRevision GetNpadRevision() const;
void SetNpadRevision(const NpadRevision revision);
private:
struct DataStructure {
@ -95,7 +96,7 @@ private:
DataStructure data{};
std::array<std::shared_ptr<NpadControllerState>, PLAYERS_MAX> state;
MaskIndex mask_index{};
NpadRevision npad_revision{};
};
} // namespace Service::HID

View File

@ -0,0 +1,53 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include "common/common_types.h"
namespace Service::HID {
template <typename State>
struct AtomicStorage {
s64 sampling_number;
State state;
};
template <typename State, std::size_t max_buffer_size>
struct Lifo {
s64 timestamp{};
s64 total_buffer_count = static_cast<s64>(max_buffer_size);
s64 buffer_tail{};
s64 buffer_count{};
std::array<AtomicStorage<State>, max_buffer_size> entries{};
const AtomicStorage<State>& ReadCurrentEntry() const {
return entries[buffer_tail];
}
const AtomicStorage<State>& ReadPreviousEntry() const {
return entries[GetPreviousEntryIndex()];
}
std::size_t GetPreviousEntryIndex() const {
return static_cast<size_t>((buffer_tail + total_buffer_count - 1) % total_buffer_count);
}
std::size_t GetNextEntryIndex() const {
return static_cast<size_t>((buffer_tail + 1) % total_buffer_count);
}
void WriteNextEntry(const State& new_state) {
if (buffer_count < total_buffer_count - 1) {
buffer_count++;
}
buffer_tail = GetNextEntryIndex();
const auto& previous_entry = ReadPreviousEntry();
entries[buffer_tail].sampling_number = previous_entry.sampling_number + 1;
entries[buffer_tail].state = new_state;
}
};
} // namespace Service::HID