1 #include "occ_dbus.hpp" 2 3 #include "utils.hpp" 4 5 #include <fmt/core.h> 6 7 #include <phosphor-logging/log.hpp> 8 9 #include <iostream> 10 11 namespace open_power 12 { 13 namespace occ 14 { 15 namespace dbus 16 { 17 18 using namespace phosphor::logging; 19 using namespace std::string_literals; 20 const auto defaultChassisPath = 21 "/xyz/openbmc_project/inventory/system/chassis"s; 22 const auto chassisInterface = "xyz.openbmc_project.Inventory.Item.Chassis"s; 23 24 bool OccDBusSensors::setMaxValue(const std::string& path, double value) 25 { 26 if (path.empty()) 27 { 28 return false; 29 } 30 31 if (sensors.find(path) == sensors.end()) 32 { 33 sensors.emplace( 34 path, std::make_unique<SensorIntf>(utils::getBus(), path.c_str())); 35 } 36 37 sensors.at(path)->maxValue(value); 38 return true; 39 } 40 41 double OccDBusSensors::getMaxValue(const std::string& path) const 42 { 43 if (sensors.find(path) != sensors.end()) 44 { 45 return sensors.at(path)->maxValue(); 46 } 47 48 throw std::invalid_argument("Failed to get MaxValue property."); 49 } 50 51 bool OccDBusSensors::setMinValue(const std::string& path, double value) 52 { 53 if (path.empty()) 54 { 55 return false; 56 } 57 58 if (sensors.find(path) == sensors.end()) 59 { 60 sensors.emplace( 61 path, std::make_unique<SensorIntf>(utils::getBus(), path.c_str())); 62 } 63 64 sensors.at(path)->minValue(value); 65 return true; 66 } 67 68 double OccDBusSensors::getMinValue(const std::string& path) const 69 { 70 if (sensors.find(path) != sensors.end()) 71 { 72 return sensors.at(path)->minValue(); 73 } 74 75 throw std::invalid_argument("Failed to get MinValue property."); 76 } 77 78 bool OccDBusSensors::setValue(const std::string& path, double value) 79 { 80 if (path.empty()) 81 { 82 return false; 83 } 84 85 if (sensors.find(path) == sensors.end()) 86 { 87 sensors.emplace( 88 path, std::make_unique<SensorIntf>(utils::getBus(), path.c_str())); 89 } 90 91 sensors.at(path)->value(value); 92 return true; 93 } 94 95 double OccDBusSensors::getValue(const std::string& path) const 96 { 97 if (sensors.find(path) != sensors.end()) 98 { 99 return sensors.at(path)->value(); 100 } 101 102 throw std::invalid_argument("Failed to get Value property."); 103 } 104 105 bool OccDBusSensors::setUnit(const std::string& path, const std::string& value) 106 { 107 if (path.empty()) 108 { 109 return false; 110 } 111 112 if (sensors.find(path) == sensors.end()) 113 { 114 sensors.emplace( 115 path, std::make_unique<SensorIntf>(utils::getBus(), path.c_str())); 116 } 117 118 try 119 { 120 sensors.at(path)->unit(SensorIntf::convertUnitFromString(value)); 121 } 122 catch (const std::exception& e) 123 { 124 log<level::ERR>("set Unit propety failed", entry("ERROR=%s", e.what())); 125 return false; 126 } 127 128 return true; 129 } 130 131 std::string OccDBusSensors::getUnit(const std::string& path) const 132 { 133 if (sensors.find(path) != sensors.end()) 134 { 135 try 136 { 137 return SensorIntf::convertUnitToString(sensors.at(path)->unit()); 138 } 139 catch (const std::exception& e) 140 { 141 log<level::ERR>("get Unit propety failed", 142 entry("ERROR=%s", e.what())); 143 } 144 } 145 146 throw std::invalid_argument("Failed to get Unit property."); 147 } 148 149 bool OccDBusSensors::setOperationalStatus(const std::string& path, bool value) 150 { 151 if (path.empty()) 152 { 153 return false; 154 } 155 156 if (operationalStatus.find(path) == operationalStatus.end()) 157 { 158 operationalStatus.emplace(path, std::make_unique<OperationalStatusIntf>( 159 utils::getBus(), path.c_str())); 160 } 161 162 operationalStatus.at(path)->functional(value); 163 return true; 164 } 165 166 bool OccDBusSensors::getOperationalStatus(const std::string& path) const 167 { 168 if (operationalStatus.find(path) != operationalStatus.end()) 169 { 170 return operationalStatus.at(path)->functional(); 171 } 172 173 throw std::invalid_argument("Failed to get OperationalStatus property."); 174 } 175 176 void OccDBusSensors::setChassisAssociation(const std::string& path) 177 { 178 using AssociationsEntry = std::tuple<std::string, std::string, std::string>; 179 using AssociationsProperty = std::vector<AssociationsEntry>; 180 using PropVariant = sdbusplus::xyz::openbmc_project::Association::server:: 181 Definitions::PropertiesVariant; 182 183 if (chassisPath.empty()) 184 { 185 chassisPath = getChassisPath(); 186 } 187 188 AssociationsProperty associations{ 189 AssociationsEntry{"chassis", "all_sensors", chassisPath}}; 190 PropVariant value{std::move(associations)}; 191 192 std::map<std::string, PropVariant> properties; 193 properties.emplace("Associations", std::move(value)); 194 195 chassisAssociations.emplace( 196 path, std::make_unique<AssociationIntf>(utils::getBus(), path.c_str(), 197 properties)); 198 } 199 200 std::string OccDBusSensors::getChassisPath() 201 { 202 try 203 { 204 auto paths = utils::getSubtreePaths(std::vector{chassisInterface}); 205 206 // For now, support either 1 chassis, or multiple as long as one 207 // of them has the standard name, which we will use. If this ever 208 // fails, then someone would have to figure out how to identify the 209 // chassis the OCCs are on. 210 if (paths.size() == 1) 211 { 212 return paths[0]; 213 } 214 else if (std::find(paths.begin(), paths.end(), defaultChassisPath) == 215 paths.end()) 216 { 217 log<level::ERR>( 218 fmt::format( 219 "Could not find a chassis out of {} chassis objects", 220 paths.size()) 221 .c_str()); 222 // Can't throw an exception here, the sdeventplus timer 223 // just catches it. 224 abort(); 225 } 226 } 227 catch (const std::exception& e) 228 { 229 log<level::ERR>( 230 fmt::format("Error looking up chassis objects: {}", e.what()) 231 .c_str()); 232 abort(); 233 } 234 235 return defaultChassisPath; 236 } 237 238 } // namespace dbus 239 } // namespace occ 240 } // namespace open_power 241