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