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