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/dbushelper.hpp"
24 #include "dbus/dbuspassive.hpp"
25 #include "dbus/dbuswrite.hpp"
26 #include "errors/exception.hpp"
27 #include "interfaces.hpp"
28 #include "notimpl/readonly.hpp"
29 #include "notimpl/writeonly.hpp"
30 #include "sensors/build_utils.hpp"
31 #include "sensors/builder.hpp"
32 #include "sensors/host.hpp"
33 #include "sensors/manager.hpp"
34 #include "sensors/pluggable.hpp"
35 #include "sysfs/sysfsread.hpp"
36 #include "sysfs/sysfswrite.hpp"
37 #include "util.hpp"
38 
39 namespace pid_control
40 {
41 
42 static constexpr bool deferSignals = true;
43 static DbusHelper helper;
44 
45 SensorManager
46     buildSensors(const std::map<std::string, struct conf::SensorConfig>& config,
47                  sdbusplus::bus::bus& passive, sdbusplus::bus::bus& 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 struct 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, &helper, info,
85                         redundancy);
86                 }
87                 else
88                 {
89                     ri = DbusPassive::createDbusPassive(passiveListeningBus,
90                                                         info->type, name,
91                                                         &helper, info, nullptr);
92                 }
93                 if (ri == nullptr)
94                 {
95                     throw SensorBuildException(
96                         "Failed to create dbus passive sensor: " + name +
97                         " of type: " + info->type);
98                 }
99                 break;
100             case IOInterfaceType::EXTERNAL:
101                 // These are a special case for read-only.
102                 break;
103             case IOInterfaceType::SYSFS:
104                 ri = std::make_unique<SysFsRead>(info->readPath);
105                 break;
106             default:
107                 ri = std::make_unique<WriteOnly>();
108                 break;
109         }
110 
111         if (info->type == "fan")
112         {
113             switch (wtype)
114             {
115                 case IOInterfaceType::SYSFS:
116                     if (info->max > 0)
117                     {
118                         wi = std::make_unique<SysFsWritePercent>(
119                             info->writePath, info->min, info->max);
120                     }
121                     else
122                     {
123                         wi = std::make_unique<SysFsWrite>(info->writePath,
124                                                           info->min, info->max);
125                     }
126 
127                     break;
128                 case IOInterfaceType::DBUSACTIVE:
129                     if (info->max > 0)
130                     {
131                         wi = DbusWritePercent::createDbusWrite(
132                             info->writePath, info->min, info->max, helper);
133                     }
134                     else
135                     {
136                         wi = DbusWrite::createDbusWrite(
137                             info->writePath, info->min, info->max, helper);
138                     }
139 
140                     if (wi == nullptr)
141                     {
142                         throw SensorBuildException(
143                             "Unable to create write dbus interface for path: " +
144                             info->writePath);
145                     }
146 
147                     break;
148                 default:
149                     wi = std::make_unique<ReadOnlyNoExcept>();
150                     break;
151             }
152 
153             auto sensor = std::make_unique<PluggableSensor>(
154                 name, info->timeout, std::move(ri), std::move(wi));
155             mgmr.addSensor(info->type, name, std::move(sensor));
156         }
157         else if (info->type == "temp" || info->type == "margin")
158         {
159             // These sensors are read-only, but only for this application
160             // which only writes to fan sensors.
161             std::cerr << info->type << " readPath: " << info->readPath << "\n";
162 
163             if (IOInterfaceType::EXTERNAL == rtype)
164             {
165                 std::cerr << "Creating HostSensor: " << name
166                           << " path: " << info->readPath << "\n";
167 
168                 /*
169                  * The reason we handle this as a HostSensor is because it's
170                  * not quite pluggable; but maybe it could be.
171                  */
172                 auto sensor = HostSensor::createTemp(
173                     name, info->timeout, hostSensorBus, info->readPath.c_str(),
174                     deferSignals);
175                 mgmr.addSensor(info->type, name, std::move(sensor));
176             }
177             else
178             {
179                 wi = std::make_unique<ReadOnlyNoExcept>();
180                 auto sensor = std::make_unique<PluggableSensor>(
181                     name, info->timeout, std::move(ri), std::move(wi));
182                 mgmr.addSensor(info->type, name, std::move(sensor));
183             }
184         }
185     }
186 
187     return mgmr;
188 }
189 
190 } // namespace pid_control
191