blob: 9333daa4fac4a0af4dd40ae345b06f6f5f4790a4 [file] [log] [blame]
Matt Spinler7f88fe62017-04-10 14:39:02 -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 */
Matthew Barth8600d9a2017-06-23 14:38:05 -050016#include <chrono>
William A. Kennington III22c36ab2018-10-30 19:50:57 -070017#include <functional>
Dinesh Chinari618027a2017-06-26 23:26:50 -050018#include <phosphor-logging/log.hpp>
Matthew Barthdf3e8d62017-05-31 11:07:24 -050019#include <phosphor-logging/elog.hpp>
Dinesh Chinari618027a2017-06-26 23:26:50 -050020#include <phosphor-logging/elog-errors.hpp>
William A. Kennington III8fd879f2018-10-30 19:49:29 -070021#include <stdexcept>
Dinesh Chinari618027a2017-06-26 23:26:50 -050022#include <xyz/openbmc_project/Common/error.hpp>
Matt Spinler7f88fe62017-04-10 14:39:02 -050023#include "zone.hpp"
Matthew Barthdf3e8d62017-05-31 11:07:24 -050024#include "utility.hpp"
Matthew Barthd953bb22017-08-22 10:45:28 -050025#include "sdbusplus.hpp"
Matt Spinler7f88fe62017-04-10 14:39:02 -050026
27namespace phosphor
28{
29namespace fan
30{
31namespace control
32{
33
Matthew Barth8600d9a2017-06-23 14:38:05 -050034using namespace std::chrono;
Matthew Barth90149802017-08-15 10:51:37 -050035using namespace phosphor::fan;
Matthew Barthdf3e8d62017-05-31 11:07:24 -050036using namespace phosphor::logging;
Dinesh Chinari618027a2017-06-26 23:26:50 -050037using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
38 Error::InternalFailure;
Matt Spinler7f88fe62017-04-10 14:39:02 -050039
Matthew Barth14184132017-05-19 14:37:30 -050040Zone::Zone(Mode mode,
41 sdbusplus::bus::bus& bus,
Matthew Barth93af4192019-01-18 09:30:57 -060042 const std::string& path,
William A. Kennington III1cfc2f12018-10-19 17:29:46 -070043 const sdeventplus::Event& event,
Matt Spinler7f88fe62017-04-10 14:39:02 -050044 const ZoneDefinition& def) :
Matthew Barth93af4192019-01-18 09:30:57 -060045 ThermalObject(bus, path.c_str(), true),
Matt Spinler7f88fe62017-04-10 14:39:02 -050046 _bus(bus),
Matthew Barth93af4192019-01-18 09:30:57 -060047 _path(path),
Matt Spinler7f88fe62017-04-10 14:39:02 -050048 _fullSpeed(std::get<fullSpeedPos>(def)),
Matthew Barth1de66622017-06-12 13:13:02 -050049 _zoneNum(std::get<zoneNumPos>(def)),
Matthew Barthe0ca13e2017-06-13 16:29:09 -050050 _defFloorSpeed(std::get<floorSpeedPos>(def)),
Matthew Barth8600d9a2017-06-23 14:38:05 -050051 _defCeilingSpeed(std::get<fullSpeedPos>(def)),
Matthew Bartha9561842017-06-29 11:43:45 -050052 _incDelay(std::get<incDelayPos>(def)),
53 _decInterval(std::get<decIntervalPos>(def)),
William A. Kennington III22c36ab2018-10-30 19:50:57 -070054 _incTimer(event, std::bind(&Zone::incTimerExpired, this)),
55 _decTimer(event, std::bind(&Zone::decTimerExpired, this)),
William A. Kennington III1cfc2f12018-10-19 17:29:46 -070056 _eventLoop(event)
Matt Spinler7f88fe62017-04-10 14:39:02 -050057{
58 auto& fanDefs = std::get<fanListPos>(def);
59
60 for (auto& def : fanDefs)
61 {
62 _fans.emplace_back(std::make_unique<Fan>(bus, def));
63 }
Matthew Barth38a93a82017-05-11 14:12:27 -050064
Matthew Barth14184132017-05-19 14:37:30 -050065 // Do not enable set speed events when in init mode
Matthew Barth93af4192019-01-18 09:30:57 -060066 if (mode == Mode::control)
Matthew Barth17d1fe22017-05-11 15:00:36 -050067 {
Matthew Barth93af4192019-01-18 09:30:57 -060068 // TODO Determine thermal control mode states
69
70 // Emit objects added in control mode only
71 this->emit_object_added();
72
Matthew Barth2b3db612017-10-25 10:56:51 -050073 // Update target speed to current zone target speed
74 if (!_fans.empty())
75 {
76 _targetSpeed = _fans.front()->getTargetSpeed();
77 }
Matthew Barthccc77702017-07-28 13:43:04 -050078 // Setup signal trigger for set speed events
79 for (auto& event : std::get<setSpeedEventsPos>(def))
80 {
81 initEvent(event);
82 }
Matthew Barth8600d9a2017-06-23 14:38:05 -050083 // Start timer for fan speed decreases
William A. Kennington III8fd879f2018-10-30 19:49:29 -070084 _decTimer.restart(_decInterval);
Matthew Barth38a93a82017-05-11 14:12:27 -050085 }
Matt Spinler7f88fe62017-04-10 14:39:02 -050086}
87
Matt Spinler7f88fe62017-04-10 14:39:02 -050088void Zone::setSpeed(uint64_t speed)
89{
Matthew Barth60b00762017-08-15 13:39:06 -050090 if (_isActive)
Matt Spinler7f88fe62017-04-10 14:39:02 -050091 {
Matthew Barth60b00762017-08-15 13:39:06 -050092 _targetSpeed = speed;
93 for (auto& fan : _fans)
94 {
95 fan->setSpeed(_targetSpeed);
96 }
97 }
98}
99
100void Zone::setFullSpeed()
101{
102 if (_fullSpeed != 0)
103 {
104 _targetSpeed = _fullSpeed;
105 for (auto& fan : _fans)
106 {
107 fan->setSpeed(_targetSpeed);
108 }
Matt Spinler7f88fe62017-04-10 14:39:02 -0500109 }
110}
111
Matthew Barth861d77c2017-05-22 14:18:25 -0500112void Zone::setActiveAllow(const Group* group, bool isActiveAllow)
113{
Matthew Barth60b00762017-08-15 13:39:06 -0500114 _active[*(group)] = isActiveAllow;
Matthew Barth861d77c2017-05-22 14:18:25 -0500115 if (!isActiveAllow)
116 {
117 _isActive = false;
118 }
119 else
120 {
121 // Check all entries are set to allow control active
122 auto actPred = [](auto const& entry) {return entry.second;};
123 _isActive = std::all_of(_active.begin(),
124 _active.end(),
125 actPred);
126 }
127}
128
Matthew Barth55dea642017-11-06 13:34:32 -0600129void Zone::removeService(const Group* group,
130 const std::string& name)
131{
132 try
133 {
134 auto& sNames = _services.at(*group);
135 auto it = std::find_if(
136 sNames.begin(),
137 sNames.end(),
138 [&name](auto const& entry)
139 {
140 return name == std::get<namePos>(entry);
141 }
142 );
143 if (it != std::end(sNames))
144 {
145 // Remove service name from group
146 sNames.erase(it);
147 }
148 }
149 catch (const std::out_of_range& oore)
150 {
151 // No services for group found
152 }
153}
154
Matthew Barthe59fdf72017-09-27 09:33:42 -0500155void Zone::setServiceOwner(const Group* group,
156 const std::string& name,
157 const bool hasOwner)
158{
159 try
160 {
161 auto& sNames = _services.at(*group);
162 auto it = std::find_if(
163 sNames.begin(),
164 sNames.end(),
165 [&name](auto const& entry)
166 {
167 return name == std::get<namePos>(entry);
168 }
169 );
170 if (it != std::end(sNames))
171 {
172 std::get<hasOwnerPos>(*it) = hasOwner;
173 }
174 else
175 {
176 _services[*group].emplace_back(name, hasOwner);
177 }
178 }
179 catch (const std::out_of_range& oore)
180 {
181 _services[*group].emplace_back(name, hasOwner);
182 }
183}
184
Matthew Barth480787c2017-11-06 11:00:00 -0600185void Zone::setServices(const Group* group)
186{
Matthew Barth55dea642017-11-06 13:34:32 -0600187 // Remove the empty service name if exists
188 removeService(group, "");
Matthew Barth480787c2017-11-06 11:00:00 -0600189 for (auto it = group->begin(); it != group->end(); ++it)
190 {
191 std::string name;
192 bool hasOwner = false;
193 try
194 {
Matthew Barthc72b8912018-01-19 17:28:18 -0600195 name = getService(it->first,
196 std::get<intfPos>(it->second));
Matthew Barth480787c2017-11-06 11:00:00 -0600197 hasOwner = util::SDBusPlus::callMethodAndRead<bool>(
198 _bus,
199 "org.freedesktop.DBus",
200 "/org/freedesktop/DBus",
201 "org.freedesktop.DBus",
202 "NameHasOwner",
203 name);
204 }
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500205 catch (const util::DBusMethodError& e)
Matthew Barth480787c2017-11-06 11:00:00 -0600206 {
207 // Failed to get service name owner state
208 hasOwner = false;
209 }
210 setServiceOwner(group, name, hasOwner);
211 }
212}
213
Matthew Barthb4a7cb92017-06-28 15:29:50 -0500214void Zone::setFloor(uint64_t speed)
215{
Matthew Barth98726c42017-10-17 10:35:20 -0500216 // Check all entries are set to allow floor to be set
217 auto pred = [](auto const& entry) {return entry.second;};
218 auto setFloor = std::all_of(_floorChange.begin(),
219 _floorChange.end(),
220 pred);
221 if (setFloor)
Matthew Barthb4a7cb92017-06-28 15:29:50 -0500222 {
Matthew Barth98726c42017-10-17 10:35:20 -0500223 _floorSpeed = speed;
224 // Floor speed above target, update target to floor speed
225 if (_targetSpeed < _floorSpeed)
226 {
227 requestSpeedIncrease(_floorSpeed - _targetSpeed);
228 }
Matthew Barthb4a7cb92017-06-28 15:29:50 -0500229 }
230}
231
Matthew Barth240397b2017-06-22 11:23:30 -0500232void Zone::requestSpeedIncrease(uint64_t targetDelta)
233{
234 // Only increase speed when delta is higher than
235 // the current increase delta for the zone and currently under ceiling
236 if (targetDelta > _incSpeedDelta &&
237 _targetSpeed < _ceilingSpeed)
238 {
Matthew Barth4e728542017-09-14 16:47:55 -0500239 auto requestTarget = getRequestSpeedBase();
Matthew Barth60b00762017-08-15 13:39:06 -0500240 requestTarget = (targetDelta - _incSpeedDelta) + requestTarget;
Matthew Barth240397b2017-06-22 11:23:30 -0500241 _incSpeedDelta = targetDelta;
Matthew Barth240397b2017-06-22 11:23:30 -0500242 // Target speed can not go above a defined ceiling speed
Matthew Barth60b00762017-08-15 13:39:06 -0500243 if (requestTarget > _ceilingSpeed)
Matthew Barth240397b2017-06-22 11:23:30 -0500244 {
Matthew Barth60b00762017-08-15 13:39:06 -0500245 requestTarget = _ceilingSpeed;
Matthew Barth240397b2017-06-22 11:23:30 -0500246 }
Matthew Barth60b00762017-08-15 13:39:06 -0500247 setSpeed(requestTarget);
William A. Kennington III8fd879f2018-10-30 19:49:29 -0700248 // Retart timer countdown for fan speed increase
249 _incTimer.restartOnce(_incDelay);
Matthew Barth240397b2017-06-22 11:23:30 -0500250 }
Matthew Barth1ee48f22017-06-27 15:14:48 -0500251}
252
253void Zone::incTimerExpired()
254{
255 // Clear increase delta when timer expires allowing additional speed
256 // increase requests or speed decreases to occur
Matthew Barth240397b2017-06-22 11:23:30 -0500257 _incSpeedDelta = 0;
258}
259
Matthew Barth0ce99d82017-06-22 15:07:29 -0500260void Zone::requestSpeedDecrease(uint64_t targetDelta)
261{
262 // Only decrease the lowest target delta requested
263 if (_decSpeedDelta == 0 || targetDelta < _decSpeedDelta)
264 {
265 _decSpeedDelta = targetDelta;
266 }
Matthew Barth8600d9a2017-06-23 14:38:05 -0500267}
Matthew Barth0ce99d82017-06-22 15:07:29 -0500268
Matthew Barth8600d9a2017-06-23 14:38:05 -0500269void Zone::decTimerExpired()
270{
Matthew Barthe4338cd2017-12-14 11:14:30 -0600271 // Check all entries are set to allow a decrease
272 auto pred = [](auto const& entry) {return entry.second;};
273 auto decAllowed = std::all_of(_decAllowed.begin(),
274 _decAllowed.end(),
275 pred);
276
277 // Only decrease speeds when allowed,
278 // where no requested increases exist and
279 // the increase timer is not running
280 // (i.e. not in the middle of increasing)
William A. Kennington III8fd879f2018-10-30 19:49:29 -0700281 if (decAllowed && _incSpeedDelta == 0 && !_incTimer.isEnabled())
Matthew Barth0ce99d82017-06-22 15:07:29 -0500282 {
Matthew Barth4e728542017-09-14 16:47:55 -0500283 auto requestTarget = getRequestSpeedBase();
Matthew Barthc63973a2017-12-08 15:31:35 -0600284 // Request target speed should not start above ceiling
285 if (requestTarget > _ceilingSpeed)
286 {
287 requestTarget = _ceilingSpeed;
288 }
Matthew Barth0ce99d82017-06-22 15:07:29 -0500289 // Target speed can not go below the defined floor speed
Matthew Barth60b00762017-08-15 13:39:06 -0500290 if ((requestTarget < _decSpeedDelta) ||
291 (requestTarget - _decSpeedDelta < _floorSpeed))
Matthew Barth0ce99d82017-06-22 15:07:29 -0500292 {
Matthew Barth60b00762017-08-15 13:39:06 -0500293 requestTarget = _floorSpeed;
Matthew Barth0ce99d82017-06-22 15:07:29 -0500294 }
295 else
296 {
Matthew Barth60b00762017-08-15 13:39:06 -0500297 requestTarget = requestTarget - _decSpeedDelta;
Matthew Barth0ce99d82017-06-22 15:07:29 -0500298 }
Matthew Barth60b00762017-08-15 13:39:06 -0500299 setSpeed(requestTarget);
Matthew Barth0ce99d82017-06-22 15:07:29 -0500300 }
301 // Clear decrease delta when timer expires
302 _decSpeedDelta = 0;
Matthew Barth8600d9a2017-06-23 14:38:05 -0500303 // Decrease timer is restarted since its repeating
Matthew Barth0ce99d82017-06-22 15:07:29 -0500304}
305
Matthew Barthccc77702017-07-28 13:43:04 -0500306void Zone::initEvent(const SetSpeedEvent& event)
Matthew Barth1bf0ce42017-06-23 16:16:30 -0500307{
Matthew Barth336f18a2017-09-26 09:15:56 -0500308 sdbusplus::message::message nullMsg{nullptr};
309
Matthew Barth67967f92017-09-22 12:43:57 -0500310 for (auto& sig : std::get<signalsPos>(event))
Matthew Barthccc77702017-07-28 13:43:04 -0500311 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500312 // Initialize the event signal using handler
313 std::get<sigHandlerPos>(sig)(_bus, nullMsg, *this);
314 // Setup signal matches of the property for event
Matthew Barthf6b76d82017-08-04 12:58:02 -0500315 std::unique_ptr<EventData> eventData =
316 std::make_unique<EventData>(
Matthew Barthf6b76d82017-08-04 12:58:02 -0500317 std::get<groupPos>(event),
Matthew Barth336f18a2017-09-26 09:15:56 -0500318 std::get<sigMatchPos>(sig),
319 std::get<sigHandlerPos>(sig),
Matthew Barthf9201ab2017-09-11 16:07:58 -0500320 std::get<actionsPos>(event)
Matthew Barthf6b76d82017-08-04 12:58:02 -0500321 );
Matthew Barth336f18a2017-09-26 09:15:56 -0500322 std::unique_ptr<sdbusplus::server::match::match> match = nullptr;
323 if (!std::get<sigMatchPos>(sig).empty())
324 {
325 match = std::make_unique<sdbusplus::server::match::match>(
326 _bus,
327 std::get<sigMatchPos>(sig).c_str(),
328 std::bind(std::mem_fn(&Zone::handleEvent),
329 this,
330 std::placeholders::_1,
331 eventData.get())
332 );
333 }
Matthew Barthf6b76d82017-08-04 12:58:02 -0500334 _signalEvents.emplace_back(std::move(eventData), std::move(match));
Matthew Barthccc77702017-07-28 13:43:04 -0500335 }
Matthew Barth90149802017-08-15 10:51:37 -0500336 // Attach a timer to run the action of an event
William A. Kennington III122b8432018-10-30 18:39:21 -0700337 auto timerConf = std::get<timerConfPos>(event);
338 if (std::get<intervalPos>(timerConf) != seconds(0))
Matthew Barth90149802017-08-15 10:51:37 -0500339 {
William A. Kennington III94fe1a02018-10-30 19:00:27 -0700340 addTimer(std::get<groupPos>(event),
341 std::get<actionsPos>(event),
342 timerConf);
Matthew Barth90149802017-08-15 10:51:37 -0500343 }
Matthew Barthf9201ab2017-09-11 16:07:58 -0500344 // Run action functions for initial event state
345 std::for_each(
346 std::get<actionsPos>(event).begin(),
347 std::get<actionsPos>(event).end(),
348 [this, &event](auto const& action)
349 {
350 action(*this,
351 std::get<groupPos>(event));
352 });
Matthew Barth1bf0ce42017-06-23 16:16:30 -0500353}
354
Matthew Barthf6b76d82017-08-04 12:58:02 -0500355void Zone::removeEvent(const SetSpeedEvent& event)
356{
Matthew Barth33bfe762018-11-05 11:13:25 -0600357 // Remove signals of the event
358 for (auto& sig : std::get<signalsPos>(event))
Matthew Barthf6b76d82017-08-04 12:58:02 -0500359 {
Matthew Barth33bfe762018-11-05 11:13:25 -0600360 auto it = findSignal(sig,
361 std::get<groupPos>(event),
362 std::get<actionsPos>(event));
363 if (it != std::end(getSignalEvents()))
Matthew Barth336f18a2017-09-26 09:15:56 -0500364 {
Matthew Barth33bfe762018-11-05 11:13:25 -0600365 removeSignal(it);
Matthew Barth336f18a2017-09-26 09:15:56 -0500366 }
Matthew Barthf6b76d82017-08-04 12:58:02 -0500367 }
Matthew Barth33bfe762018-11-05 11:13:25 -0600368 // Remove timers of the event
Matthew Barth8ce4b5f2018-11-06 13:54:46 -0600369 if (std::get<intervalPos>(std::get<timerConfPos>(event)) != seconds(0))
Matthew Barth33bfe762018-11-05 11:13:25 -0600370 {
371 auto it = findTimer(std::get<groupPos>(event),
372 std::get<actionsPos>(event));
373 if (it != std::end(getTimerEvents()))
374 {
375 removeTimer(it);
376 }
377 }
378}
379
380std::vector<SignalEvent>::iterator Zone::findSignal(
381 const Signal& signal,
382 const Group& eGroup,
383 const std::vector<Action>& eActions)
384{
385 // Find the signal in the event to be removed
386 for (auto it = _signalEvents.begin(); it != _signalEvents.end(); ++ it)
387 {
388 const auto& seEventData = *std::get<signalEventDataPos>(*it);
389 if (eGroup == std::get<eventGroupPos>(seEventData) &&
390 std::get<sigMatchPos>(signal) ==
391 std::get<eventMatchPos>(seEventData) &&
392 std::get<sigHandlerPos>(signal).target_type().name() ==
393 std::get<eventHandlerPos>(seEventData).target_type().name() &&
394 eActions.size() == std::get<eventActionsPos>(seEventData).size())
395 {
396 // TODO openbmc/openbmc#2328 - Use the function target
397 // for comparison
398 auto actsEqual = [](auto const& a1,
399 auto const& a2)
400 {
401 return a1.target_type().name() ==
402 a2.target_type().name();
403 };
404 if (std::equal(eActions.begin(),
405 eActions.end(),
406 std::get<eventActionsPos>(seEventData).begin(),
407 actsEqual))
408 {
409 return it;
410 }
411 }
412 }
413
414 return _signalEvents.end();
Matthew Barthf6b76d82017-08-04 12:58:02 -0500415}
416
Matthew Barthbfb1a562017-10-05 17:03:40 -0500417std::vector<TimerEvent>::iterator Zone::findTimer(
418 const Group& eventGroup,
419 const std::vector<Action>& eventActions)
420{
421 for (auto it = _timerEvents.begin(); it != _timerEvents.end(); ++it)
422 {
William A. Kennington III0420a932018-10-30 19:53:16 -0700423 const auto& teEventData = *std::get<timerEventDataPos>(*it);
Matthew Barthbfb1a562017-10-05 17:03:40 -0500424 if (std::get<eventActionsPos>(teEventData).size() ==
425 eventActions.size())
426 {
427 // TODO openbmc/openbmc#2328 - Use the action function target
428 // for comparison
429 auto actsEqual = [](auto const& a1,
430 auto const& a2)
431 {
432 return a1.target_type().name() ==
433 a2.target_type().name();
434 };
435 if (std::get<eventGroupPos>(teEventData) == eventGroup &&
436 std::equal(eventActions.begin(),
437 eventActions.end(),
438 std::get<eventActionsPos>(teEventData).begin(),
439 actsEqual))
440 {
441 return it;
442 }
443 }
444 }
445
446 return _timerEvents.end();
447}
448
William A. Kennington III94fe1a02018-10-30 19:00:27 -0700449void Zone::addTimer(const Group& group,
450 const std::vector<Action>& actions,
451 const TimerConf& tConf)
452{
William A. Kennington III8fd879f2018-10-30 19:49:29 -0700453 auto eventData = std::make_unique<EventData>(
William A. Kennington III94fe1a02018-10-30 19:00:27 -0700454 group,
455 "",
456 nullptr,
457 actions
458 );
William A. Kennington III8fd879f2018-10-30 19:49:29 -0700459 Timer timer(
William A. Kennington III94fe1a02018-10-30 19:00:27 -0700460 _eventLoop,
William A. Kennington IIIc0c5f072018-10-30 19:11:01 -0700461 std::bind(&Zone::timerExpired,
462 this,
William A. Kennington III8fd879f2018-10-30 19:49:29 -0700463 std::cref(std::get<Group>(*eventData)),
464 std::cref(std::get<std::vector<Action>>(*eventData))));
465 if (std::get<TimerType>(tConf) == TimerType::repeating)
William A. Kennington III94fe1a02018-10-30 19:00:27 -0700466 {
William A. Kennington III8fd879f2018-10-30 19:49:29 -0700467 timer.restart(std::get<intervalPos>(tConf));
William A. Kennington III94fe1a02018-10-30 19:00:27 -0700468 }
William A. Kennington III8fd879f2018-10-30 19:49:29 -0700469 else if (std::get<TimerType>(tConf) == TimerType::oneshot)
470 {
471 timer.restartOnce(std::get<intervalPos>(tConf));
472 }
473 else
474 {
475 throw std::invalid_argument("Invalid Timer Type");
476 }
477 _timerEvents.emplace_back(std::move(eventData), std::move(timer));
William A. Kennington III94fe1a02018-10-30 19:00:27 -0700478}
479
William A. Kennington IIIc0c5f072018-10-30 19:11:01 -0700480void Zone::timerExpired(const Group& eventGroup,
481 const std::vector<Action>& eventActions)
Matthew Barth90149802017-08-15 10:51:37 -0500482{
Matthew Barthf9201ab2017-09-11 16:07:58 -0500483 // Perform the actions
484 std::for_each(eventActions.begin(),
485 eventActions.end(),
486 [this, &eventGroup](auto const& action)
487 {
488 action(*this, eventGroup);
489 });
Matthew Barth90149802017-08-15 10:51:37 -0500490}
491
Matthew Barth38a93a82017-05-11 14:12:27 -0500492void Zone::handleEvent(sdbusplus::message::message& msg,
Matthew Barth34f1bda2017-05-31 13:45:36 -0500493 const EventData* eventData)
Matthew Barth38a93a82017-05-11 14:12:27 -0500494{
495 // Handle the callback
Matthew Barth34f1bda2017-05-31 13:45:36 -0500496 std::get<eventHandlerPos>(*eventData)(_bus, msg, *this);
Matthew Barthf9201ab2017-09-11 16:07:58 -0500497 // Perform the actions
498 std::for_each(
499 std::get<eventActionsPos>(*eventData).begin(),
500 std::get<eventActionsPos>(*eventData).end(),
501 [this, &eventData](auto const& action)
502 {
503 action(*this,
504 std::get<eventGroupPos>(*eventData));
505 });
Matthew Barth38a93a82017-05-11 14:12:27 -0500506}
507
Matthew Bartha603ed02018-01-19 16:56:26 -0600508const std::string& Zone::getService(const std::string& path,
509 const std::string& intf)
510{
511 // Retrieve service from cache
512 auto srvIter = _servTree.find(path);
513 if (srvIter != _servTree.end())
514 {
515 for (auto& serv : srvIter->second)
516 {
517 auto it = std::find_if(
518 serv.second.begin(),
519 serv.second.end(),
520 [&intf](auto const& interface)
521 {
522 return intf == interface;
523 });
524 if (it != std::end(serv.second))
525 {
526 // Service found
527 return serv.first;
528 }
529 }
530 // Interface not found in cache, add and return
531 return addServices(path, intf, 0);
532 }
533 else
534 {
535 // Path not found in cache, add and return
536 return addServices(path, intf, 0);
537 }
538}
539
540const std::string& Zone::addServices(const std::string& path,
541 const std::string& intf,
542 int32_t depth)
543{
544 static const std::string empty = "";
545 auto it = _servTree.end();
546
547 // Get all subtree objects for the given interface
548 auto objects = util::SDBusPlus::getSubTree(_bus, "/", intf, depth);
549 // Add what's returned to the cache of path->services
550 for (auto& pIter : objects)
551 {
552 auto pathIter = _servTree.find(pIter.first);
553 if (pathIter != _servTree.end())
554 {
555 // Path found in cache
556 for (auto& sIter : pIter.second)
557 {
558 auto servIter = pathIter->second.find(sIter.first);
559 if (servIter != pathIter->second.end())
560 {
561 // Service found in cache
562 for (auto& iIter : sIter.second)
563 {
Matthew Barthe8b340b2018-11-09 10:05:34 -0600564 if (std::find(servIter->second.begin(),
565 servIter->second.end(),
566 iIter) == servIter->second.end())
567 {
568 // Add interface to cache
569 servIter->second.emplace_back(iIter);
570 }
Matthew Bartha603ed02018-01-19 16:56:26 -0600571 }
572 }
573 else
574 {
575 // Service not found in cache
576 pathIter->second.insert(sIter);
577 }
578 }
579 }
580 else
581 {
582 _servTree.insert(pIter);
583 }
584 // When the paths match, since a single interface constraint is given,
585 // that is the service to return
586 if (path == pIter.first)
587 {
588 it = _servTree.find(pIter.first);
589 }
590 }
591
592 if (it != _servTree.end())
593 {
594 return it->second.begin()->first;
595 }
596
597 return empty;
598}
599
Matt Spinler7f88fe62017-04-10 14:39:02 -0500600}
601}
602}