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