blob: fba28456bc25fc6dd13ef132833cc25a2cd8abbf [file] [log] [blame]
Matt Spinlerd82a5f42017-07-24 13:40:37 -05001/**
2 * Copyright © 2017 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include <chrono>
17#include <phosphor-logging/log.hpp>
18#include <phosphor-logging/elog.hpp>
19#include <phosphor-logging/elog-errors.hpp>
20#include <xyz/openbmc_project/Common/error.hpp>
21#include <type_traits>
22#include "timer.hpp"
23
24namespace witherspoon
25{
26namespace power
27{
28
29using namespace phosphor::logging;
30using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
31 Error::InternalFailure;
32
William A. Kennington IIIe5a8b472018-10-18 00:40:04 -070033Timer::Timer(const sdeventplus::Event& event,
Matt Spinlerd82a5f42017-07-24 13:40:37 -050034 std::function<void()> callbackFunc) :
William A. Kennington IIIe5a8b472018-10-18 00:40:04 -070035 eventSource(nullptr),
Matt Spinlerd82a5f42017-07-24 13:40:37 -050036 callback(callbackFunc),
37 timeout(0)
38{
Matt Spinlerd82a5f42017-07-24 13:40:37 -050039 // Start with an infinite expiration time
William A. Kennington IIIe5a8b472018-10-18 00:40:04 -070040 auto r = sd_event_add_time(event.get(),
41 &eventSource,
Matt Spinlerd82a5f42017-07-24 13:40:37 -050042 CLOCK_MONOTONIC, // Time base
43 UINT64_MAX, // Expire time - way long time
44 0, // Use default event accuracy
45 timeoutHandler, // Callback handler on timeout
46 this); // User data
47 if (r < 0)
48 {
49 log<level::ERR>("Timer::Timer failed call to sd_event_add_time",
50 entry("ERROR=%s", strerror(-r)));
51 elog<InternalFailure>();
52 }
53
Matt Spinlerd82a5f42017-07-24 13:40:37 -050054 //Ensure timer isn't running
55 setTimer(SD_EVENT_OFF);
56}
57
58
59Timer::~Timer()
60{
61 setTimer(SD_EVENT_OFF);
William A. Kennington IIIe5a8b472018-10-18 00:40:04 -070062 sd_event_source_unref(eventSource);
Matt Spinlerd82a5f42017-07-24 13:40:37 -050063}
64
65
66int Timer::timeoutHandler(sd_event_source* eventSource,
67 uint64_t usec, void* userData)
68{
69 auto timer = static_cast<Timer*>(userData);
70
71 if (timer->type == TimerType::repeating)
72 {
73 //Set the next expiration time
74 timer->setTimeout();
75 }
76
77 timer->callback();
78
79 return 0;
80}
81
82
83std::chrono::microseconds Timer::getTime()
84{
85 using namespace std::chrono;
86 auto now = steady_clock::now().time_since_epoch();
87 return duration_cast<microseconds>(now);
88}
89
90
91void Timer::setTimer(int action)
92{
William A. Kennington IIIe5a8b472018-10-18 00:40:04 -070093 auto r = sd_event_source_set_enabled(eventSource, action);
Matt Spinlerd82a5f42017-07-24 13:40:37 -050094 if (r < 0)
95 {
96 log<level::ERR>("Failed call to sd_event_source_set_enabled",
97 entry("ERROR=%s", strerror(-r)),
98 entry("ACTION=%d", action));
99 elog<InternalFailure>();
100 }
101}
102
103
104void Timer::stop()
105{
106 setTimer(SD_EVENT_OFF);
107}
108
109
110bool Timer::running()
111{
112 int status = 0;
113
114 //returns SD_EVENT_OFF, SD_EVENT_ON, or SD_EVENT_ONESHOT
William A. Kennington IIIe5a8b472018-10-18 00:40:04 -0700115 auto r = sd_event_source_get_enabled(eventSource, &status);
Matt Spinlerd82a5f42017-07-24 13:40:37 -0500116 if (r < 0)
117 {
118 log<level::ERR>("Failed call to sd_event_source_get_enabled",
119 entry("ERROR=%s", strerror(-r)));
120 elog<InternalFailure>();
121 }
122
123 return (status != SD_EVENT_OFF);
124}
125
126
127void Timer::setTimeout()
128{
129 //Get the current time and add the delta
130 static_assert(std::is_same<decltype(getTime()),
131 std::chrono::microseconds>::value,
132 "Timer::getTime() is the wrong type");
133 static_assert(std::is_same<decltype(timeout),
134 std::chrono::microseconds>::value,
135 "Timer::timeout is the wrong type");
136
137 auto expireTime = getTime() + timeout;
138
139 //Set the time
William A. Kennington IIIe5a8b472018-10-18 00:40:04 -0700140 auto r = sd_event_source_set_time(eventSource, expireTime.count());
Matt Spinlerd82a5f42017-07-24 13:40:37 -0500141 if (r < 0)
142 {
143 log<level::ERR>("Failed call to sd_event_source_set_time",
144 entry("ERROR=%s", strerror(-r)));
145 elog<InternalFailure>();
146 }
147}
148
149
150void Timer::start(std::chrono::microseconds timeValue,
151 TimerType timerType)
152{
153 type = timerType;
154
155 // Disable the timer
156 setTimer(SD_EVENT_OFF);
157
158 //Rearm the timer
159 timeout = timeValue;
160 setTimeout();
161
162 setTimer((type == TimerType::oneshot) ? SD_EVENT_ONESHOT : SD_EVENT_ON);
163}
164
165
166}
167}