blob: 36057ab99a904d858f92eb2ce57975d4ed0ff185 [file] [log] [blame]
Matt Spinler2de67cf2017-04-27 11:07:53 -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>
Dinesh Chinari618027a2017-06-26 23:26:50 -050018#include <phosphor-logging/elog.hpp>
19#include <phosphor-logging/elog-errors.hpp>
20#include <xyz/openbmc_project/Common/error.hpp>
Matt Spinler2de67cf2017-04-27 11:07:53 -050021#include <type_traits>
22#include "timer.hpp"
23
24namespace phosphor
25{
26namespace fan
27{
28namespace util
29{
30
31using namespace phosphor::logging;
Dinesh Chinari618027a2017-06-26 23:26:50 -050032using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
33 Error::InternalFailure;
Matt Spinler2de67cf2017-04-27 11:07:53 -050034
William A. Kennington III1cfc2f12018-10-19 17:29:46 -070035Timer::Timer(const sdeventplus::Event& event,
Matt Spinler2de67cf2017-04-27 11:07:53 -050036 std::function<void()> callbackFunc) :
Matt Spinler2de67cf2017-04-27 11:07:53 -050037 callback(callbackFunc),
38 timeout(0)
39{
40 sd_event_source* source = nullptr;
41
42 // Start with an infinite expiration time
William A. Kennington III1cfc2f12018-10-19 17:29:46 -070043 auto r = sd_event_add_time(event.get(),
Matt Spinler2de67cf2017-04-27 11:07:53 -050044 &source,
45 CLOCK_MONOTONIC, // Time base
46 UINT64_MAX, // Expire time - way long time
47 0, // Use default event accuracy
48 timeoutHandler, // Callback handler on timeout
49 this); // User data
50 if (r < 0)
51 {
52 log<level::ERR>("Timer::Timer failed call to sd_event_add_time",
53 entry("ERROR=%s", strerror(-r)));
Dinesh Chinari618027a2017-06-26 23:26:50 -050054 elog<InternalFailure>();
Matt Spinler2de67cf2017-04-27 11:07:53 -050055 }
56
57 eventSource.reset(source);
58
59 //Ensure timer isn't running
60 setTimer(SD_EVENT_OFF);
61}
62
63
64Timer::~Timer()
65{
66 setTimer(SD_EVENT_OFF);
67}
68
69
70int Timer::timeoutHandler(sd_event_source* eventSource,
71 uint64_t usec, void* userData)
72{
73 auto timer = static_cast<Timer*>(userData);
74
75 if (timer->type == TimerType::repeating)
76 {
77 //Set the next expiration time
78 timer->setTimeout();
79 }
80
81 timer->callback();
82
83 return 0;
84}
85
86
87std::chrono::microseconds Timer::getTime()
88{
89 using namespace std::chrono;
90 auto now = steady_clock::now().time_since_epoch();
91 return duration_cast<microseconds>(now);
92}
93
94
95void Timer::setTimer(int action)
96{
97 auto r = sd_event_source_set_enabled(eventSource.get(), action);
98 if (r < 0)
99 {
100 log<level::ERR>("Failed call to sd_event_source_set_enabled",
101 entry("ERROR=%s", strerror(-r)),
102 entry("ACTION=%d", action));
Dinesh Chinari618027a2017-06-26 23:26:50 -0500103 elog<InternalFailure>();
Matt Spinler2de67cf2017-04-27 11:07:53 -0500104 }
105}
106
107
108void Timer::stop()
109{
110 setTimer(SD_EVENT_OFF);
111}
112
113
114bool Timer::running()
115{
116 int status = 0;
117
118 //returns SD_EVENT_OFF, SD_EVENT_ON, or SD_EVENT_ONESHOT
119 auto r = sd_event_source_get_enabled(eventSource.get(), &status);
120 if (r < 0)
121 {
122 log<level::ERR>("Failed call to sd_event_source_get_enabled",
123 entry("ERROR=%s", strerror(-r)));
Dinesh Chinari618027a2017-06-26 23:26:50 -0500124 elog<InternalFailure>();
Matt Spinler2de67cf2017-04-27 11:07:53 -0500125 }
126
127 return (status != SD_EVENT_OFF);
128}
129
130
131void Timer::setTimeout()
132{
133 //Get the current time and add the delta
134 static_assert(std::is_same<decltype(getTime()),
135 std::chrono::microseconds>::value,
136 "Timer::getTime() is the wrong type");
137 static_assert(std::is_same<decltype(timeout),
138 std::chrono::microseconds>::value,
139 "Timer::timeout is the wrong type");
140
141 auto expireTime = getTime() + timeout;
142
143 //Set the time
144 auto r = sd_event_source_set_time(eventSource.get(), expireTime.count());
145 if (r < 0)
146 {
147 log<level::ERR>("Failed call to sd_event_source_set_time",
148 entry("ERROR=%s", strerror(-r)));
Dinesh Chinari618027a2017-06-26 23:26:50 -0500149 elog<InternalFailure>();
Matt Spinler2de67cf2017-04-27 11:07:53 -0500150 }
151}
152
153
154void Timer::start(std::chrono::microseconds timeValue,
155 TimerType timerType)
156{
157 type = timerType;
158
159 // Disable the timer
160 setTimer(SD_EVENT_OFF);
161
162 //Rearm the timer
163 timeout = timeValue;
164 setTimeout();
165
166 setTimer((type == TimerType::oneshot) ? SD_EVENT_ONESHOT : SD_EVENT_ON);
167}
168
169
170}
171}
172}