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 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 mgmr.addSensor(info->type, name, std::move(sensor)); 163 } 164 else if (info->type == "temp" || info->type == "margin" || 165 info->type == "power" || info->type == "powersum") 166 { 167 // These sensors are read-only, but only for this application 168 // which only writes to fan sensors. 169 std::cerr << info->type << " readPath: " << info->readPath << "\n"; 170 171 if (IOInterfaceType::EXTERNAL == rtype) 172 { 173 std::cerr << "Creating HostSensor: " << name 174 << " path: " << info->readPath << "\n"; 175 176 /* 177 * The reason we handle this as a HostSensor is because it's 178 * not quite pluggable; but maybe it could be. 179 */ 180 auto sensor = HostSensor::createTemp( 181 name, info->timeout, hostSensorBus, info->readPath.c_str(), 182 deferSignals); 183 mgmr.addSensor(info->type, name, std::move(sensor)); 184 } 185 else 186 { 187 wi = std::make_unique<ReadOnlyNoExcept>(); 188 auto sensor = std::make_unique<PluggableSensor>( 189 name, info->timeout, std::move(ri), std::move(wi)); 190 mgmr.addSensor(info->type, name, std::move(sensor)); 191 } 192 } 193 } 194 195 return mgmr; 196 } 197 198 } // namespace pid_control 199