1 #pragma once 2 3 #include "sensorhandler.hpp" 4 #include "types.hpp" 5 #include "utils.hpp" 6 7 #include <ipmid/api.h> 8 9 #include <cmath> 10 #include <sdbusplus/message/types.hpp> 11 12 namespace ipmi 13 { 14 namespace sensor 15 { 16 17 namespace variant_ns = sdbusplus::message::variant_ns; 18 19 using Assertion = uint16_t; 20 using Deassertion = uint16_t; 21 using AssertionSet = std::pair<Assertion, Deassertion>; 22 23 using Service = std::string; 24 using Path = std::string; 25 using Interface = std::string; 26 27 using ServicePath = std::pair<Path, Service>; 28 29 using Interfaces = std::vector<Interface>; 30 31 using MapperResponseType = std::map<Path, std::map<Service, Interfaces>>; 32 33 /** @brief get the D-Bus service and service path 34 * @param[in] bus - The Dbus bus object 35 * @param[in] interface - interface to the service 36 * @param[in] path - interested path in the list of objects 37 * @return pair of service path and service 38 */ 39 ServicePath getServiceAndPath(sdbusplus::bus::bus& bus, 40 const std::string& interface, 41 const std::string& path = std::string()); 42 43 /** @brief Make assertion set from input data 44 * @param[in] cmdData - Input sensor data 45 * @return pair of assertion and deassertion set 46 */ 47 AssertionSet getAssertionSet(const SetSensorReadingReq& cmdData); 48 49 /** @brief send the message to DBus 50 * @param[in] msg - message to send 51 * @return failure status in IPMI error code 52 */ 53 ipmi_ret_t updateToDbus(IpmiUpdateData& msg); 54 55 namespace get 56 { 57 58 /** @brief Populate sensor name from the D-Bus property associated with the 59 * sensor. In the example entry from the yaml, the name of the D-bus 60 * property "AttemptsLeft" is the sensor name. 61 * 62 * 0x07: 63 * sensorType: 195 64 * path: /xyz/openbmc_project/state/host0 65 * sensorReadingType: 0x6F 66 * serviceInterface: org.freedesktop.DBus.Properties 67 * readingType: readingAssertion 68 * sensorNamePattern: nameProperty 69 * interfaces: 70 * xyz.openbmc_project.Control.Boot.RebootAttempts: 71 * AttemptsLeft: 72 * Offsets: 73 * 0xFF: 74 * type: uint32_t 75 * 76 * 77 * @param[in] sensorInfo - Dbus info related to sensor. 78 * 79 * @return On success return the sensor name for the sensor. 80 */ 81 inline SensorName nameProperty(const Info& sensorInfo) 82 { 83 return sensorInfo.propertyInterfaces.begin()->second.begin()->first; 84 } 85 86 /** @brief Populate sensor name from the D-Bus object associated with the 87 * sensor. If the object path is /system/chassis/motherboard/dimm0 then 88 * the leaf dimm0 is considered as the sensor name. 89 * 90 * @param[in] sensorInfo - Dbus info related to sensor. 91 * 92 * @return On success return the sensor name for the sensor. 93 */ 94 inline SensorName nameLeaf(const Info& sensorInfo) 95 { 96 return sensorInfo.sensorPath.substr( 97 sensorInfo.sensorPath.find_last_of('/') + 1, 98 sensorInfo.sensorPath.length()); 99 } 100 101 /** @brief Populate sensor name from the D-Bus object associated with the 102 * sensor. If the object path is /system/chassis/motherboard/cpu0/core0 103 * then the sensor name is cpu0_core0. The leaf and the parent is put 104 * together to get the sensor name. 105 * 106 * @param[in] sensorInfo - Dbus info related to sensor. 107 * 108 * @return On success return the sensor name for the sensor. 109 */ 110 SensorName nameParentLeaf(const Info& sensorInfo); 111 112 /** 113 * @brief Helper function to map the dbus info to sensor's assertion status 114 * for the get sensor reading command. 115 * 116 * @param[in] sensorInfo - Dbus info related to sensor. 117 * @param[in] path - Dbus object path. 118 * @param[in] interface - Dbus interface. 119 * 120 * @return Response for get sensor reading command. 121 */ 122 GetSensorResponse mapDbusToAssertion(const Info& sensorInfo, 123 const InstancePath& path, 124 const DbusInterface& interface); 125 126 /** 127 * @brief Map the Dbus info to sensor's assertion status in the Get sensor 128 * reading command response. 129 * 130 * @param[in] sensorInfo - Dbus info related to sensor. 131 * 132 * @return Response for get sensor reading command. 133 */ 134 GetSensorResponse assertion(const Info& sensorInfo); 135 136 /** 137 * @brief Maps the Dbus info to the reading field in the Get sensor reading 138 * command response. 139 * 140 * @param[in] sensorInfo - Dbus info related to sensor. 141 * 142 * @return Response for get sensor reading command. 143 */ 144 GetSensorResponse eventdata2(const Info& sensorInfo); 145 146 /** 147 * @brief readingAssertion is a case where the entire assertion state field 148 * serves as the sensor value. 149 * 150 * @tparam T - type of the dbus property related to sensor. 151 * @param[in] sensorInfo - Dbus info related to sensor. 152 * 153 * @return Response for get sensor reading command. 154 */ 155 template <typename T> 156 GetSensorResponse readingAssertion(const Info& sensorInfo) 157 { 158 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 159 GetSensorResponse response{}; 160 auto responseData = reinterpret_cast<GetReadingResponse*>(response.data()); 161 162 auto service = ipmi::getService(bus, sensorInfo.sensorInterface, 163 sensorInfo.sensorPath); 164 165 auto propValue = ipmi::getDbusProperty( 166 bus, service, sensorInfo.sensorPath, 167 sensorInfo.propertyInterfaces.begin()->first, 168 sensorInfo.propertyInterfaces.begin()->second.begin()->first); 169 170 setAssertionBytes(static_cast<uint16_t>(variant_ns::get<T>(propValue)), 171 responseData); 172 173 return response; 174 } 175 176 /** @brief Map the Dbus info to the reading field in the Get sensor reading 177 * command response 178 * 179 * @tparam T - type of the dbus property related to sensor. 180 * @param[in] sensorInfo - Dbus info related to sensor. 181 * 182 * @return Response for get sensor reading command. 183 */ 184 template <typename T> 185 GetSensorResponse readingData(const Info& sensorInfo) 186 { 187 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 188 GetSensorResponse response{}; 189 auto responseData = reinterpret_cast<GetReadingResponse*>(response.data()); 190 191 enableScanning(responseData); 192 193 auto service = ipmi::getService(bus, sensorInfo.sensorInterface, 194 sensorInfo.sensorPath); 195 196 auto propValue = ipmi::getDbusProperty( 197 bus, service, sensorInfo.sensorPath, 198 sensorInfo.propertyInterfaces.begin()->first, 199 sensorInfo.propertyInterfaces.begin()->second.begin()->first); 200 201 double value = variant_ns::get<T>(propValue) * 202 std::pow(10, sensorInfo.scale - sensorInfo.exponentR); 203 204 auto rawData = static_cast<uint8_t>((value - sensorInfo.scaledOffset) / 205 sensorInfo.coefficientM); 206 207 setReading(rawData, responseData); 208 209 return response; 210 } 211 212 } // namespace get 213 214 namespace set 215 { 216 217 /** @brief Make a DBus message for a Dbus call 218 * @param[in] updateInterface - Interface name 219 * @param[in] sensorPath - Path of the sensor 220 * @param[in] command - command to be executed 221 * @param[in] sensorInterface - DBus interface of sensor 222 * @return a dbus message 223 */ 224 IpmiUpdateData makeDbusMsg(const std::string& updateInterface, 225 const std::string& sensorPath, 226 const std::string& command, 227 const std::string& sensorInterface); 228 229 /** @brief Update d-bus based on assertion type sensor data 230 * @param[in] cmdData - input sensor data 231 * @param[in] sensorInfo - sensor d-bus info 232 * @return a IPMI error code 233 */ 234 ipmi_ret_t assertion(const SetSensorReadingReq& cmdData, 235 const Info& sensorInfo); 236 237 /** @brief Update d-bus based on a reading assertion 238 * @tparam T - type of d-bus property mapping this sensor 239 * @param[in] cmdData - input sensor data 240 * @param[in] sensorInfo - sensor d-bus info 241 * @return a IPMI error code 242 */ 243 template <typename T> 244 ipmi_ret_t readingAssertion(const SetSensorReadingReq& cmdData, 245 const Info& sensorInfo) 246 { 247 auto msg = 248 makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath, 249 "Set", sensorInfo.sensorInterface); 250 251 const auto& interface = sensorInfo.propertyInterfaces.begin(); 252 msg.append(interface->first); 253 for (const auto& property : interface->second) 254 { 255 msg.append(property.first); 256 sdbusplus::message::variant<T> value = 257 (cmdData.assertOffset8_14 << 8) | cmdData.assertOffset0_7; 258 msg.append(value); 259 } 260 return updateToDbus(msg); 261 } 262 263 /** @brief Update d-bus based on a discrete reading 264 * @param[in] cmdData - input sensor data 265 * @param[in] sensorInfo - sensor d-bus info 266 * @return an IPMI error code 267 */ 268 template <typename T> 269 ipmi_ret_t readingData(const SetSensorReadingReq& cmdData, 270 const Info& sensorInfo) 271 { 272 T raw_value = 273 (sensorInfo.coefficientM * cmdData.reading) + sensorInfo.scaledOffset; 274 275 raw_value *= std::pow(10, sensorInfo.exponentR - sensorInfo.scale); 276 277 auto msg = 278 makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath, 279 "Set", sensorInfo.sensorInterface); 280 281 const auto& interface = sensorInfo.propertyInterfaces.begin(); 282 msg.append(interface->first); 283 284 for (const auto& property : interface->second) 285 { 286 msg.append(property.first); 287 sdbusplus::message::variant<T> value = raw_value; 288 msg.append(value); 289 } 290 return updateToDbus(msg); 291 } 292 293 /** @brief Update d-bus based on eventdata type sensor data 294 * @param[in] cmdData - input sensor data 295 * @param[in] sensorInfo - sensor d-bus info 296 * @return a IPMI error code 297 */ 298 ipmi_ret_t eventdata(const SetSensorReadingReq& cmdData, const Info& sensorInfo, 299 uint8_t data); 300 301 /** @brief Update d-bus based on eventdata1 type sensor data 302 * @param[in] cmdData - input sensor data 303 * @param[in] sensorInfo - sensor d-bus info 304 * @return a IPMI error code 305 */ 306 inline ipmi_ret_t eventdata1(const SetSensorReadingReq& cmdData, 307 const Info& sensorInfo) 308 { 309 return eventdata(cmdData, sensorInfo, cmdData.eventData1); 310 } 311 312 /** @brief Update d-bus based on eventdata2 type sensor data 313 * @param[in] cmdData - input sensor data 314 * @param[in] sensorInfo - sensor d-bus info 315 * @return a IPMI error code 316 */ 317 inline ipmi_ret_t eventdata2(const SetSensorReadingReq& cmdData, 318 const Info& sensorInfo) 319 { 320 return eventdata(cmdData, sensorInfo, cmdData.eventData2); 321 } 322 323 /** @brief Update d-bus based on eventdata3 type sensor data 324 * @param[in] cmdData - input sensor data 325 * @param[in] sensorInfo - sensor d-bus info 326 * @return a IPMI error code 327 */ 328 inline ipmi_ret_t eventdata3(const SetSensorReadingReq& cmdData, 329 const Info& sensorInfo) 330 { 331 return eventdata(cmdData, sensorInfo, cmdData.eventData3); 332 } 333 334 } // namespace set 335 336 namespace notify 337 { 338 339 /** @brief Make a DBus message for a Dbus call 340 * @param[in] updateInterface - Interface name 341 * @param[in] sensorPath - Path of the sensor 342 * @param[in] command - command to be executed 343 * @param[in] sensorInterface - DBus interface of sensor 344 * @return a dbus message 345 */ 346 IpmiUpdateData makeDbusMsg(const std::string& updateInterface, 347 const std::string& sensorPath, 348 const std::string& command, 349 const std::string& sensorInterface); 350 351 /** @brief Update d-bus based on assertion type sensor data 352 * @param[in] interfaceMap - sensor interface 353 * @param[in] cmdData - input sensor data 354 * @param[in] sensorInfo - sensor d-bus info 355 * @return a IPMI error code 356 */ 357 ipmi_ret_t assertion(const SetSensorReadingReq& cmdData, 358 const Info& sensorInfo); 359 360 } // namespace notify 361 362 namespace inventory 363 { 364 365 namespace get 366 { 367 368 /** 369 * @brief Map the Dbus info to sensor's assertion status in the Get sensor 370 * reading command response. 371 * 372 * @param[in] sensorInfo - Dbus info related to sensor. 373 * 374 * @return Response for get sensor reading command. 375 */ 376 GetSensorResponse assertion(const Info& sensorInfo); 377 378 } // namespace get 379 380 } // namespace inventory 381 } // namespace sensor 382 } // namespace ipmi 383