1 /**
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 <phosphor-logging/elog.hpp>
17 #include "zone.hpp"
18 #include "utility.hpp"
19 
20 namespace phosphor
21 {
22 namespace fan
23 {
24 namespace control
25 {
26 
27 using namespace phosphor::logging;
28 
29 Zone::Zone(Mode mode,
30            sdbusplus::bus::bus& bus,
31            const ZoneDefinition& def) :
32     _bus(bus),
33     _fullSpeed(std::get<fullSpeedPos>(def)),
34     _zoneNum(std::get<zoneNumPos>(def))
35 {
36     auto& fanDefs = std::get<fanListPos>(def);
37 
38     for (auto& def : fanDefs)
39     {
40         _fans.emplace_back(std::make_unique<Fan>(bus, def));
41     }
42 
43     // Do not enable set speed events when in init mode
44     if (mode != Mode::init)
45     {
46         // Setup signal trigger for set speed events
47         for (auto& event : std::get<setSpeedEventsPos>(def))
48         {
49             // Get the current value for each property
50             for (auto& entry : std::get<groupPos>(event))
51             {
52                 try
53                 {
54                     bool value = false;
55                     getProperty(_bus,
56                                 entry.first,
57                                 std::get<intfPos>(entry.second),
58                                 std::get<propPos>(entry.second),
59                                 value);
60                     setPropertyValue(entry.first.c_str(),
61                                      std::get<propPos>(entry.second).c_str(),
62                                      value);
63                 }
64                 catch (const std::exception& e)
65                 {
66                     log<level::ERR>(e.what());
67                 }
68             }
69             // Setup signal matches for property change events
70             for (auto& prop : std::get<propChangeListPos>(event))
71             {
72                 _signalEvents.emplace_back(
73                         std::make_unique<EventData>(
74                                 EventData
75                                 {
76                                     std::get<groupPos>(event),
77                                     std::get<handlerObjPos>(prop),
78                                     std::get<actionPos>(event)
79                                 }));
80                 _matches.emplace_back(
81                         bus,
82                         std::get<signaturePos>(prop).c_str(),
83                         std::bind(std::mem_fn(&Zone::handleEvent),
84                                   this,
85                                   std::placeholders::_1,
86                                   _signalEvents.back().get()));
87             }
88             // Run action function for initial event state
89             std::get<actionPos>(event)(*this,
90                                        std::get<groupPos>(event));
91         }
92     }
93 }
94 
95 
96 void Zone::setSpeed(uint64_t speed)
97 {
98     for (auto& fan : _fans)
99     {
100         fan->setSpeed(speed);
101     }
102 }
103 
104 void Zone::setActiveAllow(const Group* group, bool isActiveAllow)
105 {
106     _active[group] = isActiveAllow;
107     if (!isActiveAllow)
108     {
109         _isActive = false;
110     }
111     else
112     {
113         // Check all entries are set to allow control active
114         auto actPred = [](auto const& entry) {return entry.second;};
115         _isActive = std::all_of(_active.begin(),
116                                 _active.end(),
117                                 actPred);
118     }
119 }
120 
121 template <typename T>
122 void Zone::getProperty(sdbusplus::bus::bus& bus,
123                        const std::string& path,
124                        const std::string& iface,
125                        const std::string& prop,
126                        T& value)
127 {
128     sdbusplus::message::variant<T> property;
129     auto serv = phosphor::fan::util::getService(path, iface, bus);
130     auto hostCall = bus.new_method_call(serv.c_str(),
131                                         path.c_str(),
132                                         "org.freedesktop.DBus.Properties",
133                                         "Get");
134     hostCall.append(iface);
135     hostCall.append(prop);
136     auto hostResponseMsg = bus.call(hostCall);
137     if (hostResponseMsg.is_method_error())
138     {
139         throw std::runtime_error(
140             "Error in host call response for retrieving property");
141     }
142     hostResponseMsg.read(property);
143     value = sdbusplus::message::variant_ns::get<T>(property);
144 }
145 
146 void Zone::handleEvent(sdbusplus::message::message& msg,
147                        const EventData* eventData)
148 {
149     // Handle the callback
150     std::get<eventHandlerPos>(*eventData)(_bus, msg, *this);
151     // Perform the action
152     std::get<eventActionPos>(*eventData)(*this,
153                                          std::get<eventGroupPos>(*eventData));
154 }
155 
156 }
157 }
158 }
159