blob: 69297179d20396d1e88001ef77dae80e9c819e88 [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
Matt Spinlere824f982017-05-11 10:07:55 -050035Timer::Timer(phosphor::fan::event::EventPtr& events,
Matt Spinler2de67cf2017-04-27 11:07:53 -050036 std::function<void()> callbackFunc) :
37 timeEvent(events),
38 callback(callbackFunc),
39 timeout(0)
40{
41 sd_event_source* source = nullptr;
42
43 // Start with an infinite expiration time
44 auto r = sd_event_add_time(timeEvent.get(),
45 &source,
46 CLOCK_MONOTONIC, // Time base
47 UINT64_MAX, // Expire time - way long time
48 0, // Use default event accuracy
49 timeoutHandler, // Callback handler on timeout
50 this); // User data
51 if (r < 0)
52 {
53 log<level::ERR>("Timer::Timer failed call to sd_event_add_time",
54 entry("ERROR=%s", strerror(-r)));
Dinesh Chinari618027a2017-06-26 23:26:50 -050055 elog<InternalFailure>();
Matt Spinler2de67cf2017-04-27 11:07:53 -050056 }
57
58 eventSource.reset(source);
59
60 //Ensure timer isn't running
61 setTimer(SD_EVENT_OFF);
62}
63
64
65Timer::~Timer()
66{
67 setTimer(SD_EVENT_OFF);
68}
69
70
71int Timer::timeoutHandler(sd_event_source* eventSource,
72 uint64_t usec, void* userData)
73{
74 auto timer = static_cast<Timer*>(userData);
75
76 if (timer->type == TimerType::repeating)
77 {
78 //Set the next expiration time
79 timer->setTimeout();
80 }
81
82 timer->callback();
83
84 return 0;
85}
86
87
88std::chrono::microseconds Timer::getTime()
89{
90 using namespace std::chrono;
91 auto now = steady_clock::now().time_since_epoch();
92 return duration_cast<microseconds>(now);
93}
94
95
96void Timer::setTimer(int action)
97{
98 auto r = sd_event_source_set_enabled(eventSource.get(), action);
99 if (r < 0)
100 {
101 log<level::ERR>("Failed call to sd_event_source_set_enabled",
102 entry("ERROR=%s", strerror(-r)),
103 entry("ACTION=%d", action));
Dinesh Chinari618027a2017-06-26 23:26:50 -0500104 elog<InternalFailure>();
Matt Spinler2de67cf2017-04-27 11:07:53 -0500105 }
106}
107
108
109void Timer::stop()
110{
111 setTimer(SD_EVENT_OFF);
112}
113
114
115bool Timer::running()
116{
117 int status = 0;
118
119 //returns SD_EVENT_OFF, SD_EVENT_ON, or SD_EVENT_ONESHOT
120 auto r = sd_event_source_get_enabled(eventSource.get(), &status);
121 if (r < 0)
122 {
123 log<level::ERR>("Failed call to sd_event_source_get_enabled",
124 entry("ERROR=%s", strerror(-r)));
Dinesh Chinari618027a2017-06-26 23:26:50 -0500125 elog<InternalFailure>();
Matt Spinler2de67cf2017-04-27 11:07:53 -0500126 }
127
128 return (status != SD_EVENT_OFF);
129}
130
131
132void Timer::setTimeout()
133{
134 //Get the current time and add the delta
135 static_assert(std::is_same<decltype(getTime()),
136 std::chrono::microseconds>::value,
137 "Timer::getTime() is the wrong type");
138 static_assert(std::is_same<decltype(timeout),
139 std::chrono::microseconds>::value,
140 "Timer::timeout is the wrong type");
141
142 auto expireTime = getTime() + timeout;
143
144 //Set the time
145 auto r = sd_event_source_set_time(eventSource.get(), expireTime.count());
146 if (r < 0)
147 {
148 log<level::ERR>("Failed call to sd_event_source_set_time",
149 entry("ERROR=%s", strerror(-r)));
Dinesh Chinari618027a2017-06-26 23:26:50 -0500150 elog<InternalFailure>();
Matt Spinler2de67cf2017-04-27 11:07:53 -0500151 }
152}
153
154
155void Timer::start(std::chrono::microseconds timeValue,
156 TimerType timerType)
157{
158 type = timerType;
159
160 // Disable the timer
161 setTimer(SD_EVENT_OFF);
162
163 //Rearm the timer
164 timeout = timeValue;
165 setTimeout();
166
167 setTimer((type == TimerType::oneshot) ? SD_EVENT_ONESHOT : SD_EVENT_ON);
168}
169
170
171}
172}
173}