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