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