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