17f88fe61SMatt Spinler /**
27f88fe61SMatt Spinler  * Copyright © 2017 IBM Corporation
37f88fe61SMatt Spinler  *
47f88fe61SMatt Spinler  * Licensed under the Apache License, Version 2.0 (the "License");
57f88fe61SMatt Spinler  * you may not use this file except in compliance with the License.
67f88fe61SMatt Spinler  * You may obtain a copy of the License at
77f88fe61SMatt Spinler  *
87f88fe61SMatt Spinler  *     http://www.apache.org/licenses/LICENSE-2.0
97f88fe61SMatt Spinler  *
107f88fe61SMatt Spinler  * Unless required by applicable law or agreed to in writing, software
117f88fe61SMatt Spinler  * distributed under the License is distributed on an "AS IS" BASIS,
127f88fe61SMatt Spinler  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137f88fe61SMatt Spinler  * See the License for the specific language governing permissions and
147f88fe61SMatt Spinler  * limitations under the License.
157f88fe61SMatt Spinler  */
168600d9a0SMatthew Barth #include <chrono>
17618027abSDinesh Chinari #include <phosphor-logging/log.hpp>
18df3e8d67SMatthew Barth #include <phosphor-logging/elog.hpp>
19618027abSDinesh Chinari #include <phosphor-logging/elog-errors.hpp>
20618027abSDinesh Chinari #include <xyz/openbmc_project/Common/error.hpp>
217f88fe61SMatt Spinler #include "zone.hpp"
22df3e8d67SMatthew Barth #include "utility.hpp"
23d953bb25SMatthew Barth #include "sdbusplus.hpp"
247f88fe61SMatt Spinler 
257f88fe61SMatt Spinler namespace phosphor
267f88fe61SMatt Spinler {
277f88fe61SMatt Spinler namespace fan
287f88fe61SMatt Spinler {
297f88fe61SMatt Spinler namespace control
307f88fe61SMatt Spinler {
317f88fe61SMatt Spinler 
328600d9a0SMatthew Barth using namespace std::chrono;
339014980aSMatthew Barth using namespace phosphor::fan;
34df3e8d67SMatthew Barth using namespace phosphor::logging;
35618027abSDinesh Chinari using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
36618027abSDinesh Chinari                              Error::InternalFailure;
377f88fe61SMatt Spinler 
3814184131SMatthew Barth Zone::Zone(Mode mode,
3914184131SMatthew Barth            sdbusplus::bus::bus& bus,
401cfc2f11SWilliam A. Kennington III            const sdeventplus::Event& event,
417f88fe61SMatt Spinler            const ZoneDefinition& def) :
427f88fe61SMatt Spinler     _bus(bus),
437f88fe61SMatt Spinler     _fullSpeed(std::get<fullSpeedPos>(def)),
441de66629SMatthew Barth     _zoneNum(std::get<zoneNumPos>(def)),
45e0ca13ebSMatthew Barth     _defFloorSpeed(std::get<floorSpeedPos>(def)),
468600d9a0SMatthew Barth     _defCeilingSpeed(std::get<fullSpeedPos>(def)),
47a956184bSMatthew Barth     _incDelay(std::get<incDelayPos>(def)),
48a956184bSMatthew Barth     _decInterval(std::get<decIntervalPos>(def)),
491cfc2f11SWilliam A. Kennington III     _incTimer(event, [this](){ this->incTimerExpired(); }),
501cfc2f11SWilliam A. Kennington III     _decTimer(event, [this](){ this->decTimerExpired(); }),
511cfc2f11SWilliam A. Kennington III     _eventLoop(event)
527f88fe61SMatt Spinler {
537f88fe61SMatt Spinler     auto& fanDefs = std::get<fanListPos>(def);
547f88fe61SMatt Spinler 
557f88fe61SMatt Spinler     for (auto& def : fanDefs)
567f88fe61SMatt Spinler     {
577f88fe61SMatt Spinler         _fans.emplace_back(std::make_unique<Fan>(bus, def));
587f88fe61SMatt Spinler     }
5938a93a8aSMatthew Barth 
6014184131SMatthew Barth     // Do not enable set speed events when in init mode
6114184131SMatthew Barth     if (mode != Mode::init)
6214184131SMatthew Barth     {
632b3db618SMatthew Barth         // Update target speed to current zone target speed
642b3db618SMatthew Barth         if (!_fans.empty())
652b3db618SMatthew Barth         {
662b3db618SMatthew Barth             _targetSpeed = _fans.front()->getTargetSpeed();
672b3db618SMatthew Barth         }
68ccc7770eSMatthew Barth         // Setup signal trigger for set speed events
69ccc7770eSMatthew Barth         for (auto& event : std::get<setSpeedEventsPos>(def))
70ccc7770eSMatthew Barth         {
71ccc7770eSMatthew Barth             initEvent(event);
72ccc7770eSMatthew Barth         }
738600d9a0SMatthew Barth         // Start timer for fan speed decreases
74a956184bSMatthew Barth         if (!_decTimer.running() && _decInterval != seconds::zero())
758600d9a0SMatthew Barth         {
760ce353ecSWilliam A. Kennington III             _decTimer.start(_decInterval, TimerType::repeating);
778600d9a0SMatthew Barth         }
787f88fe61SMatt Spinler     }
7914184131SMatthew Barth }
807f88fe61SMatt Spinler 
817f88fe61SMatt Spinler void Zone::setSpeed(uint64_t speed)
827f88fe61SMatt Spinler {
8360b00766SMatthew Barth     if (_isActive)
8460b00766SMatthew Barth     {
8560b00766SMatthew Barth         _targetSpeed = speed;
867f88fe61SMatt Spinler         for (auto& fan : _fans)
877f88fe61SMatt Spinler         {
8860b00766SMatthew Barth             fan->setSpeed(_targetSpeed);
8960b00766SMatthew Barth         }
9060b00766SMatthew Barth     }
9160b00766SMatthew Barth }
9260b00766SMatthew Barth 
9360b00766SMatthew Barth void Zone::setFullSpeed()
9460b00766SMatthew Barth {
9560b00766SMatthew Barth     if (_fullSpeed != 0)
9660b00766SMatthew Barth     {
9760b00766SMatthew Barth         _targetSpeed = _fullSpeed;
9860b00766SMatthew Barth         for (auto& fan : _fans)
9960b00766SMatthew Barth         {
10060b00766SMatthew Barth             fan->setSpeed(_targetSpeed);
10160b00766SMatthew Barth         }
1027f88fe61SMatt Spinler     }
1037f88fe61SMatt Spinler }
1047f88fe61SMatt Spinler 
105861d77c3SMatthew Barth void Zone::setActiveAllow(const Group* group, bool isActiveAllow)
106861d77c3SMatthew Barth {
10760b00766SMatthew Barth     _active[*(group)] = isActiveAllow;
108861d77c3SMatthew Barth     if (!isActiveAllow)
109861d77c3SMatthew Barth     {
110861d77c3SMatthew Barth         _isActive = false;
111861d77c3SMatthew Barth     }
112861d77c3SMatthew Barth     else
113861d77c3SMatthew Barth     {
114861d77c3SMatthew Barth         // Check all entries are set to allow control active
115861d77c3SMatthew Barth         auto actPred = [](auto const& entry) {return entry.second;};
116861d77c3SMatthew Barth         _isActive = std::all_of(_active.begin(),
117861d77c3SMatthew Barth                                 _active.end(),
118861d77c3SMatthew Barth                                 actPred);
119861d77c3SMatthew Barth     }
120861d77c3SMatthew Barth }
121861d77c3SMatthew Barth 
12255dea643SMatthew Barth void Zone::removeService(const Group* group,
12355dea643SMatthew Barth                          const std::string& name)
12455dea643SMatthew Barth {
12555dea643SMatthew Barth     try
12655dea643SMatthew Barth     {
12755dea643SMatthew Barth         auto& sNames = _services.at(*group);
12855dea643SMatthew Barth         auto it = std::find_if(
12955dea643SMatthew Barth             sNames.begin(),
13055dea643SMatthew Barth             sNames.end(),
13155dea643SMatthew Barth             [&name](auto const& entry)
13255dea643SMatthew Barth             {
13355dea643SMatthew Barth                 return name == std::get<namePos>(entry);
13455dea643SMatthew Barth             }
13555dea643SMatthew Barth         );
13655dea643SMatthew Barth         if (it != std::end(sNames))
13755dea643SMatthew Barth         {
13855dea643SMatthew Barth             // Remove service name from group
13955dea643SMatthew Barth             sNames.erase(it);
14055dea643SMatthew Barth         }
14155dea643SMatthew Barth     }
14255dea643SMatthew Barth     catch (const std::out_of_range& oore)
14355dea643SMatthew Barth     {
14455dea643SMatthew Barth         // No services for group found
14555dea643SMatthew Barth     }
14655dea643SMatthew Barth }
14755dea643SMatthew Barth 
148e59fdf70SMatthew Barth void Zone::setServiceOwner(const Group* group,
149e59fdf70SMatthew Barth                            const std::string& name,
150e59fdf70SMatthew Barth                            const bool hasOwner)
151e59fdf70SMatthew Barth {
152e59fdf70SMatthew Barth     try
153e59fdf70SMatthew Barth     {
154e59fdf70SMatthew Barth         auto& sNames = _services.at(*group);
155e59fdf70SMatthew Barth         auto it = std::find_if(
156e59fdf70SMatthew Barth             sNames.begin(),
157e59fdf70SMatthew Barth             sNames.end(),
158e59fdf70SMatthew Barth             [&name](auto const& entry)
159e59fdf70SMatthew Barth             {
160e59fdf70SMatthew Barth                 return name == std::get<namePos>(entry);
161e59fdf70SMatthew Barth             }
162e59fdf70SMatthew Barth         );
163e59fdf70SMatthew Barth         if (it != std::end(sNames))
164e59fdf70SMatthew Barth         {
165e59fdf70SMatthew Barth             std::get<hasOwnerPos>(*it) = hasOwner;
166e59fdf70SMatthew Barth         }
167e59fdf70SMatthew Barth         else
168e59fdf70SMatthew Barth         {
169e59fdf70SMatthew Barth             _services[*group].emplace_back(name, hasOwner);
170e59fdf70SMatthew Barth         }
171e59fdf70SMatthew Barth     }
172e59fdf70SMatthew Barth     catch (const std::out_of_range& oore)
173e59fdf70SMatthew Barth     {
174e59fdf70SMatthew Barth         _services[*group].emplace_back(name, hasOwner);
175e59fdf70SMatthew Barth     }
176e59fdf70SMatthew Barth }
177e59fdf70SMatthew Barth 
178480787c1SMatthew Barth void Zone::setServices(const Group* group)
179480787c1SMatthew Barth {
18055dea643SMatthew Barth     // Remove the empty service name if exists
18155dea643SMatthew Barth     removeService(group, "");
182480787c1SMatthew Barth     for (auto it = group->begin(); it != group->end(); ++it)
183480787c1SMatthew Barth     {
184480787c1SMatthew Barth         std::string name;
185480787c1SMatthew Barth         bool hasOwner = false;
186480787c1SMatthew Barth         try
187480787c1SMatthew Barth         {
188c72b8911SMatthew Barth             name = getService(it->first,
189480787c1SMatthew Barth                               std::get<intfPos>(it->second));
190480787c1SMatthew Barth             hasOwner = util::SDBusPlus::callMethodAndRead<bool>(
191480787c1SMatthew Barth                     _bus,
192480787c1SMatthew Barth                     "org.freedesktop.DBus",
193480787c1SMatthew Barth                     "/org/freedesktop/DBus",
194480787c1SMatthew Barth                     "org.freedesktop.DBus",
195480787c1SMatthew Barth                     "NameHasOwner",
196480787c1SMatthew Barth                     name);
197480787c1SMatthew Barth         }
198ba7b5feaSMatt Spinler         catch (const util::DBusMethodError& e)
199480787c1SMatthew Barth         {
200480787c1SMatthew Barth             // Failed to get service name owner state
201480787c1SMatthew Barth             hasOwner = false;
202480787c1SMatthew Barth         }
203480787c1SMatthew Barth         setServiceOwner(group, name, hasOwner);
204480787c1SMatthew Barth     }
205480787c1SMatthew Barth }
206480787c1SMatthew Barth 
207b4a7cb99SMatthew Barth void Zone::setFloor(uint64_t speed)
208b4a7cb99SMatthew Barth {
20998726c45SMatthew Barth     // Check all entries are set to allow floor to be set
21098726c45SMatthew Barth     auto pred = [](auto const& entry) {return entry.second;};
21198726c45SMatthew Barth     auto setFloor = std::all_of(_floorChange.begin(),
21298726c45SMatthew Barth                                 _floorChange.end(),
21398726c45SMatthew Barth                                 pred);
21498726c45SMatthew Barth     if (setFloor)
21598726c45SMatthew Barth     {
216b4a7cb99SMatthew Barth         _floorSpeed = speed;
217b4a7cb99SMatthew Barth         // Floor speed above target, update target to floor speed
218b4a7cb99SMatthew Barth         if (_targetSpeed < _floorSpeed)
219b4a7cb99SMatthew Barth         {
220b4a7cb99SMatthew Barth             requestSpeedIncrease(_floorSpeed - _targetSpeed);
221b4a7cb99SMatthew Barth         }
222b4a7cb99SMatthew Barth     }
22398726c45SMatthew Barth }
224b4a7cb99SMatthew Barth 
225240397b9SMatthew Barth void Zone::requestSpeedIncrease(uint64_t targetDelta)
226240397b9SMatthew Barth {
227240397b9SMatthew Barth     // Only increase speed when delta is higher than
228240397b9SMatthew Barth     // the current increase delta for the zone and currently under ceiling
229240397b9SMatthew Barth     if (targetDelta > _incSpeedDelta &&
230240397b9SMatthew Barth         _targetSpeed < _ceilingSpeed)
231240397b9SMatthew Barth     {
2324e728542SMatthew Barth         auto requestTarget = getRequestSpeedBase();
23360b00766SMatthew Barth         requestTarget = (targetDelta - _incSpeedDelta) + requestTarget;
234240397b9SMatthew Barth         _incSpeedDelta = targetDelta;
235240397b9SMatthew Barth         // Target speed can not go above a defined ceiling speed
23660b00766SMatthew Barth         if (requestTarget > _ceilingSpeed)
237240397b9SMatthew Barth         {
23860b00766SMatthew Barth             requestTarget = _ceilingSpeed;
239240397b9SMatthew Barth         }
2401ee48f2bSMatthew Barth         // Cancel current timer countdown
2411ee48f2bSMatthew Barth         if (_incTimer.running())
2421ee48f2bSMatthew Barth         {
2431ee48f2bSMatthew Barth             _incTimer.stop();
244240397b9SMatthew Barth         }
24560b00766SMatthew Barth         setSpeed(requestTarget);
2461ee48f2bSMatthew Barth         // Start timer countdown for fan speed increase
2470ce353ecSWilliam A. Kennington III         _incTimer.start(_incDelay, TimerType::oneshot);
2481ee48f2bSMatthew Barth     }
2491ee48f2bSMatthew Barth }
2501ee48f2bSMatthew Barth 
2511ee48f2bSMatthew Barth void Zone::incTimerExpired()
2521ee48f2bSMatthew Barth {
2531ee48f2bSMatthew Barth     // Clear increase delta when timer expires allowing additional speed
2541ee48f2bSMatthew Barth     // increase requests or speed decreases to occur
255240397b9SMatthew Barth     _incSpeedDelta = 0;
256240397b9SMatthew Barth }
257240397b9SMatthew Barth 
2580ce99d8bSMatthew Barth void Zone::requestSpeedDecrease(uint64_t targetDelta)
2590ce99d8bSMatthew Barth {
2600ce99d8bSMatthew Barth     // Only decrease the lowest target delta requested
2610ce99d8bSMatthew Barth     if (_decSpeedDelta == 0 || targetDelta < _decSpeedDelta)
2620ce99d8bSMatthew Barth     {
2630ce99d8bSMatthew Barth         _decSpeedDelta = targetDelta;
2640ce99d8bSMatthew Barth     }
2658600d9a0SMatthew Barth }
2660ce99d8bSMatthew Barth 
2678600d9a0SMatthew Barth void Zone::decTimerExpired()
2688600d9a0SMatthew Barth {
269e4338cdbSMatthew Barth     // Check all entries are set to allow a decrease
270e4338cdbSMatthew Barth     auto pred = [](auto const& entry) {return entry.second;};
271e4338cdbSMatthew Barth     auto decAllowed = std::all_of(_decAllowed.begin(),
272e4338cdbSMatthew Barth                                   _decAllowed.end(),
273e4338cdbSMatthew Barth                                   pred);
274e4338cdbSMatthew Barth 
275e4338cdbSMatthew Barth     // Only decrease speeds when allowed,
276e4338cdbSMatthew Barth     // where no requested increases exist and
277e4338cdbSMatthew Barth     // the increase timer is not running
278e4338cdbSMatthew Barth     // (i.e. not in the middle of increasing)
279e4338cdbSMatthew Barth     if (decAllowed && _incSpeedDelta == 0 && !_incTimer.running())
2800ce99d8bSMatthew Barth     {
2814e728542SMatthew Barth         auto requestTarget = getRequestSpeedBase();
282c63973a1SMatthew Barth         // Request target speed should not start above ceiling
283c63973a1SMatthew Barth         if (requestTarget > _ceilingSpeed)
284c63973a1SMatthew Barth         {
285c63973a1SMatthew Barth             requestTarget = _ceilingSpeed;
286c63973a1SMatthew Barth         }
2870ce99d8bSMatthew Barth         // Target speed can not go below the defined floor speed
28860b00766SMatthew Barth         if ((requestTarget < _decSpeedDelta) ||
28960b00766SMatthew Barth             (requestTarget - _decSpeedDelta < _floorSpeed))
2900ce99d8bSMatthew Barth         {
29160b00766SMatthew Barth             requestTarget = _floorSpeed;
2920ce99d8bSMatthew Barth         }
2930ce99d8bSMatthew Barth         else
2940ce99d8bSMatthew Barth         {
29560b00766SMatthew Barth             requestTarget = requestTarget - _decSpeedDelta;
2960ce99d8bSMatthew Barth         }
29760b00766SMatthew Barth         setSpeed(requestTarget);
2980ce99d8bSMatthew Barth     }
2990ce99d8bSMatthew Barth     // Clear decrease delta when timer expires
3000ce99d8bSMatthew Barth     _decSpeedDelta = 0;
3018600d9a0SMatthew Barth     // Decrease timer is restarted since its repeating
3020ce99d8bSMatthew Barth }
3030ce99d8bSMatthew Barth 
304ccc7770eSMatthew Barth void Zone::initEvent(const SetSpeedEvent& event)
3051bf0ce4bSMatthew Barth {
306336f18a5SMatthew Barth     sdbusplus::message::message nullMsg{nullptr};
307336f18a5SMatthew Barth 
30867967f9aSMatthew Barth     for (auto& sig : std::get<signalsPos>(event))
3091bf0ce4bSMatthew Barth     {
310336f18a5SMatthew Barth         // Initialize the event signal using handler
311336f18a5SMatthew Barth         std::get<sigHandlerPos>(sig)(_bus, nullMsg, *this);
312336f18a5SMatthew Barth         // Setup signal matches of the property for event
313f6b76d8eSMatthew Barth         std::unique_ptr<EventData> eventData =
3141bf0ce4bSMatthew Barth             std::make_unique<EventData>(
3151bf0ce4bSMatthew Barth                     std::get<groupPos>(event),
316336f18a5SMatthew Barth                     std::get<sigMatchPos>(sig),
317336f18a5SMatthew Barth                     std::get<sigHandlerPos>(sig),
318f9201abbSMatthew Barth                     std::get<actionsPos>(event)
319f6b76d8eSMatthew Barth             );
320336f18a5SMatthew Barth         std::unique_ptr<sdbusplus::server::match::match> match = nullptr;
321336f18a5SMatthew Barth         if (!std::get<sigMatchPos>(sig).empty())
322336f18a5SMatthew Barth         {
323336f18a5SMatthew Barth             match = std::make_unique<sdbusplus::server::match::match>(
3241bf0ce4bSMatthew Barth                     _bus,
325336f18a5SMatthew Barth                     std::get<sigMatchPos>(sig).c_str(),
3261bf0ce4bSMatthew Barth                     std::bind(std::mem_fn(&Zone::handleEvent),
3271bf0ce4bSMatthew Barth                               this,
3281bf0ce4bSMatthew Barth                               std::placeholders::_1,
329f6b76d8eSMatthew Barth                               eventData.get())
330f6b76d8eSMatthew Barth                 );
331336f18a5SMatthew Barth         }
332f6b76d8eSMatthew Barth         _signalEvents.emplace_back(std::move(eventData), std::move(match));
3331bf0ce4bSMatthew Barth     }
3349014980aSMatthew Barth     // Attach a timer to run the action of an event
335*122b843fSWilliam A. Kennington III     auto timerConf = std::get<timerConfPos>(event);
336*122b843fSWilliam A. Kennington III     if (std::get<intervalPos>(timerConf) != seconds(0))
3379014980aSMatthew Barth     {
338bfb1a566SMatthew Barth         // Associate event data with timer
339bfb1a566SMatthew Barth         std::unique_ptr<EventData> eventData =
340bfb1a566SMatthew Barth             std::make_unique<EventData>(
341bfb1a566SMatthew Barth                     std::get<groupPos>(event),
342bfb1a566SMatthew Barth                     "",
343bfb1a566SMatthew Barth                     nullptr,
344bfb1a566SMatthew Barth                     std::get<actionsPos>(event)
345bfb1a566SMatthew Barth             );
3469014980aSMatthew Barth         std::unique_ptr<util::Timer> timer =
3479014980aSMatthew Barth             std::make_unique<util::Timer>(
3481cfc2f11SWilliam A. Kennington III                 _eventLoop,
3499014980aSMatthew Barth                 [this,
350f9201abbSMatthew Barth                  action = &(std::get<actionsPos>(event)),
3519014980aSMatthew Barth                  group = &(std::get<groupPos>(event))]()
3529014980aSMatthew Barth                  {
3539014980aSMatthew Barth                      this->timerExpired(*group, *action);
3549014980aSMatthew Barth                  });
3559014980aSMatthew Barth         if (!timer->running())
3569014980aSMatthew Barth         {
357*122b843fSWilliam A. Kennington III             timer->start(std::get<intervalPos>(timerConf),
358*122b843fSWilliam A. Kennington III                          std::get<typePos>(timerConf));
3599014980aSMatthew Barth         }
360bfb1a566SMatthew Barth         addTimer(std::move(eventData), std::move(timer));
3619014980aSMatthew Barth     }
362f9201abbSMatthew Barth     // Run action functions for initial event state
363f9201abbSMatthew Barth     std::for_each(
364f9201abbSMatthew Barth         std::get<actionsPos>(event).begin(),
365f9201abbSMatthew Barth         std::get<actionsPos>(event).end(),
366f9201abbSMatthew Barth         [this, &event](auto const& action)
367f9201abbSMatthew Barth         {
368f9201abbSMatthew Barth             action(*this,
3691bf0ce4bSMatthew Barth                    std::get<groupPos>(event));
370f9201abbSMatthew Barth         });
3711bf0ce4bSMatthew Barth }
3721bf0ce4bSMatthew Barth 
373f6b76d8eSMatthew Barth void Zone::removeEvent(const SetSpeedEvent& event)
374f6b76d8eSMatthew Barth {
375f6b76d8eSMatthew Barth     // Find the signal event to be removed
376f6b76d8eSMatthew Barth     auto it = std::find_if(
377f6b76d8eSMatthew Barth         _signalEvents.begin(),
378f6b76d8eSMatthew Barth         _signalEvents.end(),
379f6b76d8eSMatthew Barth         [&event](auto const& se)
380f6b76d8eSMatthew Barth         {
381f6b76d8eSMatthew Barth             auto seEventData = *std::get<signalEventDataPos>(se);
382f9201abbSMatthew Barth             if (std::get<eventActionsPos>(seEventData).size() !=
383f9201abbSMatthew Barth                 std::get<actionsPos>(event).size())
384f9201abbSMatthew Barth             {
385f9201abbSMatthew Barth                 return false;
386f9201abbSMatthew Barth             }
387f9201abbSMatthew Barth             else
388f9201abbSMatthew Barth             {
389f9201abbSMatthew Barth                 // TODO openbmc/openbmc#2328 - Use the action function target
390f9201abbSMatthew Barth                 // for comparison
391f9201abbSMatthew Barth                 auto actsEqual = [](auto const& a1,
392f9201abbSMatthew Barth                                     auto const& a2)
393f9201abbSMatthew Barth                         {
394f9201abbSMatthew Barth                             return a1.target_type().name() ==
395f9201abbSMatthew Barth                                    a2.target_type().name();
396f9201abbSMatthew Barth                         };
397f6b76d8eSMatthew Barth                 return
398f6b76d8eSMatthew Barth                 (
399f6b76d8eSMatthew Barth                     std::get<eventGroupPos>(seEventData) ==
400f6b76d8eSMatthew Barth                         std::get<groupPos>(event) &&
401f9201abbSMatthew Barth                     std::equal(std::get<actionsPos>(event).begin(),
402f9201abbSMatthew Barth                                std::get<actionsPos>(event).end(),
403f9201abbSMatthew Barth                                std::get<eventActionsPos>(seEventData).begin(),
404f9201abbSMatthew Barth                                actsEqual)
405f6b76d8eSMatthew Barth                 );
406f9201abbSMatthew Barth             }
407f6b76d8eSMatthew Barth         });
408f6b76d8eSMatthew Barth     if (it != std::end(_signalEvents))
409f6b76d8eSMatthew Barth     {
410f6b76d8eSMatthew Barth         std::get<signalEventDataPos>(*it).reset();
411336f18a5SMatthew Barth         if (std::get<signalMatchPos>(*it) != nullptr)
412336f18a5SMatthew Barth         {
413f6b76d8eSMatthew Barth             std::get<signalMatchPos>(*it).reset();
414336f18a5SMatthew Barth         }
415f6b76d8eSMatthew Barth         _signalEvents.erase(it);
416f6b76d8eSMatthew Barth     }
417f6b76d8eSMatthew Barth }
418f6b76d8eSMatthew Barth 
419bfb1a566SMatthew Barth std::vector<TimerEvent>::iterator Zone::findTimer(
420bfb1a566SMatthew Barth         const Group& eventGroup,
421bfb1a566SMatthew Barth         const std::vector<Action>& eventActions)
422bfb1a566SMatthew Barth {
423bfb1a566SMatthew Barth     for (auto it = _timerEvents.begin(); it != _timerEvents.end(); ++it)
424bfb1a566SMatthew Barth     {
425bfb1a566SMatthew Barth         auto teEventData = *std::get<timerEventDataPos>(*it);
426bfb1a566SMatthew Barth         if (std::get<eventActionsPos>(teEventData).size() ==
427bfb1a566SMatthew Barth             eventActions.size())
428bfb1a566SMatthew Barth         {
429bfb1a566SMatthew Barth             // TODO openbmc/openbmc#2328 - Use the action function target
430bfb1a566SMatthew Barth             // for comparison
431bfb1a566SMatthew Barth             auto actsEqual = [](auto const& a1,
432bfb1a566SMatthew Barth                                 auto const& a2)
433bfb1a566SMatthew Barth                     {
434bfb1a566SMatthew Barth                         return a1.target_type().name() ==
435bfb1a566SMatthew Barth                                a2.target_type().name();
436bfb1a566SMatthew Barth                     };
437bfb1a566SMatthew Barth             if (std::get<eventGroupPos>(teEventData) == eventGroup &&
438bfb1a566SMatthew Barth                 std::equal(eventActions.begin(),
439bfb1a566SMatthew Barth                            eventActions.end(),
440bfb1a566SMatthew Barth                            std::get<eventActionsPos>(teEventData).begin(),
441bfb1a566SMatthew Barth                            actsEqual))
442bfb1a566SMatthew Barth             {
443bfb1a566SMatthew Barth                 return it;
444bfb1a566SMatthew Barth             }
445bfb1a566SMatthew Barth         }
446bfb1a566SMatthew Barth     }
447bfb1a566SMatthew Barth 
448bfb1a566SMatthew Barth     return _timerEvents.end();
449bfb1a566SMatthew Barth }
450bfb1a566SMatthew Barth 
451f9201abbSMatthew Barth void Zone::timerExpired(Group eventGroup, std::vector<Action> eventActions)
4529014980aSMatthew Barth {
453f9201abbSMatthew Barth     // Perform the actions
454f9201abbSMatthew Barth     std::for_each(eventActions.begin(),
455f9201abbSMatthew Barth                   eventActions.end(),
456f9201abbSMatthew Barth                   [this, &eventGroup](auto const& action)
457f9201abbSMatthew Barth                   {
458f9201abbSMatthew Barth                       action(*this, eventGroup);
459f9201abbSMatthew Barth                   });
4609014980aSMatthew Barth }
4619014980aSMatthew Barth 
46238a93a8aSMatthew Barth void Zone::handleEvent(sdbusplus::message::message& msg,
46334f1bda2SMatthew Barth                        const EventData* eventData)
46438a93a8aSMatthew Barth {
46538a93a8aSMatthew Barth     // Handle the callback
46634f1bda2SMatthew Barth     std::get<eventHandlerPos>(*eventData)(_bus, msg, *this);
467f9201abbSMatthew Barth     // Perform the actions
468f9201abbSMatthew Barth     std::for_each(
469f9201abbSMatthew Barth         std::get<eventActionsPos>(*eventData).begin(),
470f9201abbSMatthew Barth         std::get<eventActionsPos>(*eventData).end(),
471f9201abbSMatthew Barth         [this, &eventData](auto const& action)
472f9201abbSMatthew Barth         {
473f9201abbSMatthew Barth             action(*this,
47434f1bda2SMatthew Barth                    std::get<eventGroupPos>(*eventData));
475f9201abbSMatthew Barth         });
47638a93a8aSMatthew Barth }
47738a93a8aSMatthew Barth 
478a603ed01SMatthew Barth const std::string& Zone::getService(const std::string& path,
479a603ed01SMatthew Barth                                     const std::string& intf)
480a603ed01SMatthew Barth {
481a603ed01SMatthew Barth     // Retrieve service from cache
482a603ed01SMatthew Barth     auto srvIter = _servTree.find(path);
483a603ed01SMatthew Barth     if (srvIter != _servTree.end())
484a603ed01SMatthew Barth     {
485a603ed01SMatthew Barth         for (auto& serv : srvIter->second)
486a603ed01SMatthew Barth         {
487a603ed01SMatthew Barth             auto it = std::find_if(
488a603ed01SMatthew Barth                 serv.second.begin(),
489a603ed01SMatthew Barth                 serv.second.end(),
490a603ed01SMatthew Barth                 [&intf](auto const& interface)
491a603ed01SMatthew Barth                 {
492a603ed01SMatthew Barth                     return intf == interface;
493a603ed01SMatthew Barth                 });
494a603ed01SMatthew Barth             if (it != std::end(serv.second))
495a603ed01SMatthew Barth             {
496a603ed01SMatthew Barth                 // Service found
497a603ed01SMatthew Barth                 return serv.first;
498a603ed01SMatthew Barth             }
499a603ed01SMatthew Barth         }
500a603ed01SMatthew Barth         // Interface not found in cache, add and return
501a603ed01SMatthew Barth         return addServices(path, intf, 0);
502a603ed01SMatthew Barth     }
503a603ed01SMatthew Barth     else
504a603ed01SMatthew Barth     {
505a603ed01SMatthew Barth         // Path not found in cache, add and return
506a603ed01SMatthew Barth         return addServices(path, intf, 0);
507a603ed01SMatthew Barth     }
508a603ed01SMatthew Barth }
509a603ed01SMatthew Barth 
510a603ed01SMatthew Barth const std::string& Zone::addServices(const std::string& path,
511a603ed01SMatthew Barth                                      const std::string& intf,
512a603ed01SMatthew Barth                                      int32_t depth)
513a603ed01SMatthew Barth {
514a603ed01SMatthew Barth     static const std::string empty = "";
515a603ed01SMatthew Barth     auto it = _servTree.end();
516a603ed01SMatthew Barth 
517a603ed01SMatthew Barth     // Get all subtree objects for the given interface
518a603ed01SMatthew Barth     auto objects = util::SDBusPlus::getSubTree(_bus, "/", intf, depth);
519a603ed01SMatthew Barth     // Add what's returned to the cache of path->services
520a603ed01SMatthew Barth     for (auto& pIter : objects)
521a603ed01SMatthew Barth     {
522a603ed01SMatthew Barth         auto pathIter = _servTree.find(pIter.first);
523a603ed01SMatthew Barth         if (pathIter != _servTree.end())
524a603ed01SMatthew Barth         {
525a603ed01SMatthew Barth             // Path found in cache
526a603ed01SMatthew Barth             for (auto& sIter : pIter.second)
527a603ed01SMatthew Barth             {
528a603ed01SMatthew Barth                 auto servIter = pathIter->second.find(sIter.first);
529a603ed01SMatthew Barth                 if (servIter != pathIter->second.end())
530a603ed01SMatthew Barth                 {
531a603ed01SMatthew Barth                     // Service found in cache
532a603ed01SMatthew Barth                     for (auto& iIter : sIter.second)
533a603ed01SMatthew Barth                     {
534a603ed01SMatthew Barth                         // Add interface to cache
535a603ed01SMatthew Barth                         servIter->second.emplace_back(iIter);
536a603ed01SMatthew Barth                     }
537a603ed01SMatthew Barth                 }
538a603ed01SMatthew Barth                 else
539a603ed01SMatthew Barth                 {
540a603ed01SMatthew Barth                     // Service not found in cache
541a603ed01SMatthew Barth                     pathIter->second.insert(sIter);
542a603ed01SMatthew Barth                 }
543a603ed01SMatthew Barth             }
544a603ed01SMatthew Barth         }
545a603ed01SMatthew Barth         else
546a603ed01SMatthew Barth         {
547a603ed01SMatthew Barth             _servTree.insert(pIter);
548a603ed01SMatthew Barth         }
549a603ed01SMatthew Barth         // When the paths match, since a single interface constraint is given,
550a603ed01SMatthew Barth         // that is the service to return
551a603ed01SMatthew Barth         if (path == pIter.first)
552a603ed01SMatthew Barth         {
553a603ed01SMatthew Barth             it = _servTree.find(pIter.first);
554a603ed01SMatthew Barth         }
555a603ed01SMatthew Barth     }
556a603ed01SMatthew Barth 
557a603ed01SMatthew Barth     if (it != _servTree.end())
558a603ed01SMatthew Barth     {
559a603ed01SMatthew Barth         return it->second.begin()->first;
560a603ed01SMatthew Barth     }
561a603ed01SMatthew Barth 
562a603ed01SMatthew Barth     return empty;
563a603ed01SMatthew Barth }
564a603ed01SMatthew Barth 
5657f88fe61SMatt Spinler }
5667f88fe61SMatt Spinler }
5677f88fe61SMatt Spinler }
568