xref: /openbmc/phosphor-fan-presence/control/json/actions/count_state_floor.cpp (revision dfddd648cb81b27492afead4e2346f5fcd1397cb)
165dfe1eaSMatt Spinler /**
265dfe1eaSMatt Spinler  * Copyright © 2021 IBM Corporation
365dfe1eaSMatt Spinler  *
465dfe1eaSMatt Spinler  * Licensed under the Apache License, Version 2.0 (the "License");
565dfe1eaSMatt Spinler  * you may not use this file except in compliance with the License.
665dfe1eaSMatt Spinler  * You may obtain a copy of the License at
765dfe1eaSMatt Spinler  *
865dfe1eaSMatt Spinler  *     http://www.apache.org/licenses/LICENSE-2.0
965dfe1eaSMatt Spinler  *
1065dfe1eaSMatt Spinler  * Unless required by applicable law or agreed to in writing, software
1165dfe1eaSMatt Spinler  * distributed under the License is distributed on an "AS IS" BASIS,
1265dfe1eaSMatt Spinler  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1365dfe1eaSMatt Spinler  * See the License for the specific language governing permissions and
1465dfe1eaSMatt Spinler  * limitations under the License.
1565dfe1eaSMatt Spinler  */
1665dfe1eaSMatt Spinler #include "count_state_floor.hpp"
1765dfe1eaSMatt Spinler 
1865dfe1eaSMatt Spinler #include "../manager.hpp"
1965dfe1eaSMatt Spinler #include "../zone.hpp"
2065dfe1eaSMatt Spinler #include "action.hpp"
2165dfe1eaSMatt Spinler #include "group.hpp"
227fa4d16eSMatt Spinler #include "sdeventplus.hpp"
2365dfe1eaSMatt Spinler 
2465dfe1eaSMatt Spinler namespace phosphor::fan::control::json
2565dfe1eaSMatt Spinler {
2665dfe1eaSMatt Spinler 
CountStateFloor(const json & jsonObj,const std::vector<Group> & groups)2765dfe1eaSMatt Spinler CountStateFloor::CountStateFloor(const json& jsonObj,
2865dfe1eaSMatt Spinler                                  const std::vector<Group>& groups) :
2965dfe1eaSMatt Spinler     ActionBase(jsonObj, groups)
3065dfe1eaSMatt Spinler {
3165dfe1eaSMatt Spinler     setCount(jsonObj);
3265dfe1eaSMatt Spinler     setState(jsonObj);
3365dfe1eaSMatt Spinler     setFloor(jsonObj);
347fa4d16eSMatt Spinler     setDelayTime(jsonObj);
3565dfe1eaSMatt Spinler }
3665dfe1eaSMatt Spinler 
run(Zone & zone)3765dfe1eaSMatt Spinler void CountStateFloor::run(Zone& zone)
3865dfe1eaSMatt Spinler {
397fa4d16eSMatt Spinler     auto countReached = doCount();
407fa4d16eSMatt Spinler 
417fa4d16eSMatt Spinler     if (_delayTime == std::chrono::seconds::zero())
427fa4d16eSMatt Spinler     {
437fa4d16eSMatt Spinler         // If no delay time configured, can immediately update the hold.
447fa4d16eSMatt Spinler         zone.setFloorHold(getUniqueName(), _floor, countReached);
457fa4d16eSMatt Spinler         return;
467fa4d16eSMatt Spinler     }
477fa4d16eSMatt Spinler 
487fa4d16eSMatt Spinler     if (!countReached)
497fa4d16eSMatt Spinler     {
507fa4d16eSMatt Spinler         if (_timer && _timer->isEnabled())
517fa4d16eSMatt Spinler         {
527fa4d16eSMatt Spinler             record("Stopping delay timer");
537fa4d16eSMatt Spinler             _timer->setEnabled(false);
547fa4d16eSMatt Spinler         }
557fa4d16eSMatt Spinler 
567fa4d16eSMatt Spinler         zone.setFloorHold(getUniqueName(), _floor, countReached);
577fa4d16eSMatt Spinler         return;
587fa4d16eSMatt Spinler     }
597fa4d16eSMatt Spinler 
607fa4d16eSMatt Spinler     // The count has been reached and a delay is configured, so either:
617fa4d16eSMatt Spinler     // 1. This hold has already been set, so don't need to do anything else.
627fa4d16eSMatt Spinler     // 2. The timer hasn't been started yet, so start it (May need to create
637fa4d16eSMatt Spinler     //    it first).
647fa4d16eSMatt Spinler     // 3. The timer is already running, don't need to do anything else.
657fa4d16eSMatt Spinler     // When the timer expires, then count again and set the hold.
667fa4d16eSMatt Spinler 
677fa4d16eSMatt Spinler     if (zone.hasFloorHold(getUniqueName()))
687fa4d16eSMatt Spinler     {
697fa4d16eSMatt Spinler         return;
707fa4d16eSMatt Spinler     }
717fa4d16eSMatt Spinler 
727fa4d16eSMatt Spinler     if (!_timer)
737fa4d16eSMatt Spinler     {
74*dfddd648SPatrick Williams         _timer = std::make_unique<Timer>(
75*dfddd648SPatrick Williams             util::SDEventPlus::getEvent(), [&zone, this](Timer&) {
767fa4d16eSMatt Spinler                 zone.setFloorHold(getUniqueName(), _floor, doCount());
777fa4d16eSMatt Spinler             });
787fa4d16eSMatt Spinler     }
797fa4d16eSMatt Spinler 
807fa4d16eSMatt Spinler     if (!_timer->isEnabled())
817fa4d16eSMatt Spinler     {
827fa4d16eSMatt Spinler         record("Starting delay timer");
837fa4d16eSMatt Spinler         _timer->restartOnce(_delayTime);
847fa4d16eSMatt Spinler     }
857fa4d16eSMatt Spinler }
867fa4d16eSMatt Spinler 
doCount()877fa4d16eSMatt Spinler bool CountStateFloor::doCount()
887fa4d16eSMatt Spinler {
8965dfe1eaSMatt Spinler     size_t numAtState = 0;
907fa4d16eSMatt Spinler 
9165dfe1eaSMatt Spinler     for (const auto& group : _groups)
9265dfe1eaSMatt Spinler     {
9365dfe1eaSMatt Spinler         for (const auto& member : group.getMembers())
9465dfe1eaSMatt Spinler         {
9565dfe1eaSMatt Spinler             try
9665dfe1eaSMatt Spinler             {
9765dfe1eaSMatt Spinler                 if (Manager::getObjValueVariant(member, group.getInterface(),
9865dfe1eaSMatt Spinler                                                 group.getProperty()) == _state)
9965dfe1eaSMatt Spinler                 {
10065dfe1eaSMatt Spinler                     numAtState++;
1017fa4d16eSMatt Spinler                     if (numAtState >= _count)
1027fa4d16eSMatt Spinler                     {
1037fa4d16eSMatt Spinler                         return true;
1047fa4d16eSMatt Spinler                     }
10565dfe1eaSMatt Spinler                 }
10665dfe1eaSMatt Spinler             }
10765dfe1eaSMatt Spinler             catch (const std::out_of_range& oore)
10865dfe1eaSMatt Spinler             {
10965dfe1eaSMatt Spinler                 // Default to property not equal when not found
11065dfe1eaSMatt Spinler             }
11165dfe1eaSMatt Spinler         }
11265dfe1eaSMatt Spinler     }
11365dfe1eaSMatt Spinler 
1147fa4d16eSMatt Spinler     return false;
11565dfe1eaSMatt Spinler }
11665dfe1eaSMatt Spinler 
setCount(const json & jsonObj)11765dfe1eaSMatt Spinler void CountStateFloor::setCount(const json& jsonObj)
11865dfe1eaSMatt Spinler {
11965dfe1eaSMatt Spinler     if (!jsonObj.contains("count"))
12065dfe1eaSMatt Spinler     {
12165dfe1eaSMatt Spinler         throw ActionParseError{ActionBase::getName(),
12265dfe1eaSMatt Spinler                                "Missing required count value"};
12365dfe1eaSMatt Spinler     }
12465dfe1eaSMatt Spinler     _count = jsonObj["count"].get<size_t>();
12565dfe1eaSMatt Spinler }
12665dfe1eaSMatt Spinler 
setState(const json & jsonObj)12765dfe1eaSMatt Spinler void CountStateFloor::setState(const json& jsonObj)
12865dfe1eaSMatt Spinler {
12965dfe1eaSMatt Spinler     if (!jsonObj.contains("state"))
13065dfe1eaSMatt Spinler     {
13165dfe1eaSMatt Spinler         throw ActionParseError{ActionBase::getName(),
13265dfe1eaSMatt Spinler                                "Missing required state value"};
13365dfe1eaSMatt Spinler     }
13465dfe1eaSMatt Spinler     _state = getJsonValue(jsonObj["state"]);
13565dfe1eaSMatt Spinler }
13665dfe1eaSMatt Spinler 
setFloor(const json & jsonObj)13765dfe1eaSMatt Spinler void CountStateFloor::setFloor(const json& jsonObj)
13865dfe1eaSMatt Spinler {
13965dfe1eaSMatt Spinler     if (!jsonObj.contains("floor"))
14065dfe1eaSMatt Spinler     {
14165dfe1eaSMatt Spinler         throw ActionParseError{ActionBase::getName(),
14265dfe1eaSMatt Spinler                                "Missing required floor value"};
14365dfe1eaSMatt Spinler     }
14465dfe1eaSMatt Spinler     _floor = jsonObj["floor"].get<uint64_t>();
14565dfe1eaSMatt Spinler }
14665dfe1eaSMatt Spinler 
setDelayTime(const json & jsonObj)1477fa4d16eSMatt Spinler void CountStateFloor::setDelayTime(const json& jsonObj)
1487fa4d16eSMatt Spinler {
1497fa4d16eSMatt Spinler     if (jsonObj.contains("delay"))
1507fa4d16eSMatt Spinler     {
1517fa4d16eSMatt Spinler         _delayTime = std::chrono::seconds(jsonObj["delay"].get<size_t>());
1527fa4d16eSMatt Spinler     }
1537fa4d16eSMatt Spinler }
1547fa4d16eSMatt Spinler 
15565dfe1eaSMatt Spinler } // namespace phosphor::fan::control::json
156