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