aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs
blob: e661ab53804a2bff4dbb0763c9fdce9c3d8849f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Bpc;
using Ryujinx.HLE.Utilities;
using System;

namespace Ryujinx.HLE.HOS.Services.Time.Clock
{
    class SteadyClockCore
    {
        private long         _setupValue;
        private ResultCode   _setupResultCode;
        private bool         _isRtcResetDetected;
        private TimeSpanType _testOffset;
        private TimeSpanType _internalOffset;
        private UInt128      _clockSourceId;

        private static SteadyClockCore instance;

        public static SteadyClockCore Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new SteadyClockCore();
                }

                return instance;
            }
        }

        private SteadyClockCore()
        {
            _testOffset     = new TimeSpanType(0);
            _internalOffset = new TimeSpanType(0);
            _clockSourceId  = new UInt128(Guid.NewGuid().ToByteArray());
        }

        private SteadyClockTimePoint GetTimePoint(KThread thread)
        {
            SteadyClockTimePoint result = new SteadyClockTimePoint
            {
                TimePoint     = 0,
                ClockSourceId = _clockSourceId
            };

            TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.ThreadState.CntpctEl0, thread.Context.ThreadState.CntfrqEl0);

            result.TimePoint = _setupValue + ticksTimeSpan.ToSeconds();

            return result;
        }

        public UInt128 GetClockSourceId()
        {
            return _clockSourceId;
        }

        public SteadyClockTimePoint GetCurrentTimePoint(KThread thread)
        {
            SteadyClockTimePoint result = GetTimePoint(thread);

            result.TimePoint += _testOffset.ToSeconds();
            result.TimePoint += _internalOffset.ToSeconds();

            return result;
        }

        public TimeSpanType GetTestOffset()
        {
            return _testOffset;
        }

        public void SetTestOffset(TimeSpanType testOffset)
        {
            _testOffset = testOffset;
        }

        public ResultCode GetRtcValue(out ulong rtcValue)
        {
            return (ResultCode)IRtcManager.GetExternalRtcValue(out rtcValue);
        }

        public bool IsRtcResetDetected()
        {
            return _isRtcResetDetected;
        }

        public ResultCode GetSetupResultCode()
        {
            return _setupResultCode;
        }

        public TimeSpanType GetInternalOffset()
        {
            return _internalOffset;
        }

        public void SetInternalOffset(TimeSpanType internalOffset)
        {
            _internalOffset = internalOffset;
        }

        public ResultCode GetSetupResultValue()
        {
            return _setupResultCode;
        }

        public void ConfigureSetupValue()
        {
            int retry = 0;

            ResultCode result = ResultCode.Success;

            while (retry < 20)
            {
                result = (ResultCode)IRtcManager.GetExternalRtcValue(out ulong rtcValue);

                if (result == ResultCode.Success)
                {
                    _setupValue = (long)rtcValue;
                    break;
                }

                retry++;
            }

            _setupResultCode = result;
        }
    }
}