1 /** 2 * Copyright © 2024 IBM Corporation 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 #include "utils.hpp" 17 18 #include "utility.hpp" 19 20 #include <phosphor-logging/log.hpp> 21 #include <xyz/openbmc_project/Common/Device/error.hpp> 22 23 #include <exception> 24 #include <iostream> 25 #include <regex> 26 #include <stdexcept> 27 28 using namespace phosphor::logging; 29 using namespace phosphor::power::util; 30 using namespace sdbusplus::xyz::openbmc_project::Common::Device::Error; 31 32 namespace utils 33 { 34 35 constexpr auto IBMCFFPSInterface = 36 "xyz.openbmc_project.Configuration.IBMCFFPSConnector"; 37 constexpr auto i2cBusProp = "I2CBus"; 38 constexpr auto i2cAddressProp = "I2CAddress"; 39 40 PsuI2cInfo getPsuI2c(sdbusplus::bus_t& bus, const std::string& psuInventoryPath) 41 { 42 auto depth = 0; 43 auto objects = getSubTree(bus, "/", IBMCFFPSInterface, depth); 44 if (objects.empty()) 45 { 46 throw std::runtime_error("Supported Configuration Not Found"); 47 } 48 49 std::optional<std::uint64_t> i2cbus; 50 std::optional<std::uint64_t> i2caddr; 51 52 // GET a map of objects back. 53 // Each object will have a path, a service, and an interface. 54 for (const auto& [path, services] : objects) 55 { 56 auto service = services.begin()->first; 57 58 if (path.empty() || service.empty()) 59 { 60 continue; 61 } 62 63 // Match the PSU identifier in the path with the passed PSU inventory 64 // path. Compare the last character of both paths to find the PSU bus 65 // and address. example: PSU path: 66 // /xyz/openbmc_project/inventory/system/board/Nisqually_Backplane/Power_Supply_Slot_0 67 // PSU inventory path: 68 // /xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0 69 if (path.back() == psuInventoryPath.back()) 70 { 71 // Retrieve i2cBus and i2cAddress from array of properties. 72 auto properties = 73 getAllProperties(bus, path, IBMCFFPSInterface, service); 74 for (const auto& property : properties) 75 { 76 try 77 { 78 if (property.first == i2cBusProp) 79 { 80 i2cbus = std::get<uint64_t>(properties.at(i2cBusProp)); 81 } 82 else if (property.first == i2cAddressProp) 83 { 84 i2caddr = 85 std::get<uint64_t>(properties.at(i2cAddressProp)); 86 } 87 } 88 catch (const std::exception& e) 89 { 90 log<level::WARNING>( 91 std::format("Error reading property {}: {}", 92 property.first, e.what()) 93 .c_str()); 94 } 95 } 96 97 if (i2cbus.has_value() && i2caddr.has_value()) 98 { 99 break; 100 } 101 } 102 } 103 104 if (!i2cbus.has_value() || !i2caddr.has_value()) 105 { 106 throw std::runtime_error("Failed to get I2C bus or address"); 107 } 108 109 return std::make_tuple(*i2cbus, *i2caddr); 110 } 111 112 std::unique_ptr<phosphor::pmbus::PMBusBase> 113 getPmbusIntf(std::uint64_t i2cBus, std::uint64_t i2cAddr) 114 { 115 std::stringstream ss; 116 ss << std::hex << std::setw(4) << std::setfill('0') << i2cAddr; 117 return phosphor::pmbus::createPMBus(i2cBus, ss.str()); 118 } 119 120 std::string readVPDValue(phosphor::pmbus::PMBusBase& pmbusIntf, 121 const std::string& vpdName, 122 const phosphor::pmbus::Type& type, 123 const std::size_t& vpdSize) 124 { 125 std::string vpdValue; 126 const std::regex illegalVPDRegex = 127 std::regex("[^[:alnum:]]", std::regex::basic); 128 129 try 130 { 131 vpdValue = pmbusIntf.readString(vpdName, type); 132 } 133 catch (const ReadFailure& e) 134 { 135 // Ignore the read failure, let pmbus code indicate failure. 136 } 137 138 if (vpdValue.size() != vpdSize) 139 { 140 log<level::INFO>( 141 std::format(" {} resize needed. size: {}", vpdName, vpdValue.size()) 142 .c_str()); 143 vpdValue.resize(vpdSize, ' '); 144 } 145 146 // Replace any illegal values with space(s). 147 std::regex_replace(vpdValue.begin(), vpdValue.begin(), vpdValue.end(), 148 illegalVPDRegex, " "); 149 150 return vpdValue; 151 } 152 153 bool checkFileExists(const std::string& filePath) 154 { 155 try 156 { 157 return std::filesystem::exists(filePath); 158 } 159 catch (const std::exception& e) 160 { 161 log<level::ERR>(std::format("Unable to check for existence of {}: {}", 162 filePath, e.what()) 163 .c_str()); 164 } 165 return false; 166 } 167 168 } // namespace utils 169