xref: /openbmc/phosphor-pid-control/sensors/builder.cpp (revision a076487aab0ee71ea32d53f798d5ca6b31677278)
1 /**
2  * Copyright 2017 Google Inc.
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 
17 #include <iostream>
18 #include <map>
19 #include <string>
20 
21 /* Configuration. */
22 #include "conf.hpp"
23 #include "dbus/dbuspassive.hpp"
24 #include "dbus/dbuswrite.hpp"
25 #include "errors/exception.hpp"
26 #include "interfaces.hpp"
27 #include "notimpl/readonly.hpp"
28 #include "notimpl/writeonly.hpp"
29 #include "sensors/build_utils.hpp"
30 #include "sensors/builder.hpp"
31 #include "sensors/host.hpp"
32 #include "sensors/manager.hpp"
33 #include "sensors/pluggable.hpp"
34 #include "sysfs/sysfsread.hpp"
35 #include "sysfs/sysfswrite.hpp"
36 #include "util.hpp"
37 
38 namespace pid_control
39 {
40 
41 static constexpr bool deferSignals = true;
42 static DbusHelper helper;
43 
44 SensorManager
45     buildSensors(const std::map<std::string, struct conf::SensorConfig>& config,
46                  sdbusplus::bus::bus& passive, sdbusplus::bus::bus& host)
47 {
48     SensorManager mgmr(passive, host);
49     auto& hostSensorBus = mgmr.getHostBus();
50     auto& passiveListeningBus = mgmr.getPassiveBus();
51 
52     for (const auto& it : config)
53     {
54         std::unique_ptr<ReadInterface> ri;
55         std::unique_ptr<WriteInterface> wi;
56 
57         std::string name = it.first;
58         const struct conf::SensorConfig* info = &it.second;
59 
60         std::cerr << "Sensor: " << name << " " << info->type << " ";
61         std::cerr << info->readPath << " " << info->writePath << "\n";
62 
63         IOInterfaceType rtype = getReadInterfaceType(info->readPath);
64         IOInterfaceType wtype = getWriteInterfaceType(info->writePath);
65 
66         // fan sensors can be ready any way and written others.
67         // fan sensors are the only sensors this is designed to write.
68         // Nothing here should be write-only, although, in theory a fan could
69         // be. I'm just not sure how that would fit together.
70         // TODO(venture): It should check with the ObjectMapper to check if
71         // that sensor exists on the Dbus.
72         switch (rtype)
73         {
74             case IOInterfaceType::DBUSPASSIVE:
75                 // we only need to make one match based on the dbus object
76                 static std::shared_ptr<DbusPassiveRedundancy> redundancy =
77                     std::make_shared<DbusPassiveRedundancy>(
78                         passiveListeningBus);
79 
80                 if (info->type == "fan")
81                 {
82                     ri = DbusPassive::createDbusPassive(
83                         passiveListeningBus, info->type, name, &helper, info,
84                         redundancy);
85                 }
86                 else
87                 {
88                     ri = DbusPassive::createDbusPassive(passiveListeningBus,
89                                                         info->type, name,
90                                                         &helper, info, nullptr);
91                 }
92                 if (ri == nullptr)
93                 {
94                     throw SensorBuildException(
95                         "Failed to create dbus passive sensor: " + name +
96                         " of type: " + info->type);
97                 }
98                 break;
99             case IOInterfaceType::EXTERNAL:
100                 // These are a special case for read-only.
101                 break;
102             case IOInterfaceType::SYSFS:
103                 ri = std::make_unique<SysFsRead>(info->readPath);
104                 break;
105             default:
106                 ri = std::make_unique<WriteOnly>();
107                 break;
108         }
109 
110         if (info->type == "fan")
111         {
112             switch (wtype)
113             {
114                 case IOInterfaceType::SYSFS:
115                     if (info->max > 0)
116                     {
117                         wi = std::make_unique<SysFsWritePercent>(
118                             info->writePath, info->min, info->max);
119                     }
120                     else
121                     {
122                         wi = std::make_unique<SysFsWrite>(info->writePath,
123                                                           info->min, info->max);
124                     }
125 
126                     break;
127                 case IOInterfaceType::DBUSACTIVE:
128                     if (info->max > 0)
129                     {
130                         wi = DbusWritePercent::createDbusWrite(
131                             info->writePath, info->min, info->max, helper);
132                     }
133                     else
134                     {
135                         wi = DbusWrite::createDbusWrite(
136                             info->writePath, info->min, info->max, helper);
137                     }
138 
139                     if (wi == nullptr)
140                     {
141                         throw SensorBuildException(
142                             "Unable to create write dbus interface for path: " +
143                             info->writePath);
144                     }
145 
146                     break;
147                 default:
148                     wi = std::make_unique<ReadOnlyNoExcept>();
149                     break;
150             }
151 
152             auto sensor = std::make_unique<PluggableSensor>(
153                 name, info->timeout, std::move(ri), std::move(wi));
154             mgmr.addSensor(info->type, name, std::move(sensor));
155         }
156         else if (info->type == "temp" || info->type == "margin")
157         {
158             // These sensors are read-only, but only for this application
159             // which only writes to fan sensors.
160             std::cerr << info->type << " readPath: " << info->readPath << "\n";
161 
162             if (IOInterfaceType::EXTERNAL == rtype)
163             {
164                 std::cerr << "Creating HostSensor: " << name
165                           << " path: " << info->readPath << "\n";
166 
167                 /*
168                  * The reason we handle this as a HostSensor is because it's
169                  * not quite pluggable; but maybe it could be.
170                  */
171                 auto sensor = HostSensor::createTemp(
172                     name, info->timeout, hostSensorBus, info->readPath.c_str(),
173                     deferSignals);
174                 mgmr.addSensor(info->type, name, std::move(sensor));
175             }
176             else
177             {
178                 wi = std::make_unique<ReadOnlyNoExcept>();
179                 auto sensor = std::make_unique<PluggableSensor>(
180                     name, info->timeout, std::move(ri), std::move(wi));
181                 mgmr.addSensor(info->type, name, std::move(sensor));
182             }
183         }
184     }
185 
186     return mgmr;
187 }
188 
189 } // namespace pid_control
190