1 /** 2 * Copyright © 2020 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 17 #include "pmbus_read_sensor_action.hpp" 18 19 #include "action_error.hpp" 20 #include "pmbus_error.hpp" 21 22 #include <sdbusplus/exception.hpp> 23 24 #include <exception> 25 #include <ios> 26 #include <sstream> 27 28 namespace phosphor::power::regulators 29 { 30 31 bool PMBusReadSensorAction::execute(ActionEnvironment& environment) 32 { 33 try 34 { 35 // Get I2C interface to current device 36 i2c::I2CInterface& interface = getI2CInterface(environment); 37 38 // Read two byte value of PMBus command code. I2CInterface method reads 39 // low byte first as required by PMBus. 40 uint16_t value{0x00}; 41 interface.read(command, value); 42 43 // Convert two byte PMBus value into a decimal sensor value 44 double sensorValue{0.0}; 45 switch (format) 46 { 47 case pmbus_utils::SensorDataFormat::linear_11: 48 sensorValue = pmbus_utils::convertFromLinear(value); 49 break; 50 case pmbus_utils::SensorDataFormat::linear_16: 51 int8_t exponentValue = getExponentValue(environment, interface); 52 sensorValue = pmbus_utils::convertFromVoutLinear(value, 53 exponentValue); 54 break; 55 } 56 57 // Publish sensor value using the Sensors service 58 environment.getServices().getSensors().setValue(type, sensorValue); 59 } 60 // Nest the following exception types within an ActionError so the caller 61 // will have both the low level error information and the action information 62 catch (const i2c::I2CException& e) 63 { 64 std::throw_with_nested(ActionError(*this)); 65 } 66 catch (const PMBusError& e) 67 { 68 std::throw_with_nested(ActionError(*this)); 69 } 70 catch (const sdbusplus::exception_t& e) 71 { 72 std::throw_with_nested(ActionError(*this)); 73 } 74 return true; 75 } 76 77 std::string PMBusReadSensorAction::toString() const 78 { 79 std::ostringstream ss; 80 ss << "pmbus_read_sensor: { "; 81 ss << "type: " << sensors::toString(type) << ", " << std::hex 82 << std::uppercase; 83 ss << "command: 0x" << static_cast<uint16_t>(command) << ", " << std::dec 84 << std::nouppercase; 85 ss << "format: " << pmbus_utils::toString(format); 86 87 if (exponent.has_value()) 88 { 89 ss << ", exponent: " << static_cast<int16_t>(exponent.value()); 90 } 91 92 ss << " }"; 93 94 return ss.str(); 95 } 96 97 int8_t PMBusReadSensorAction::getExponentValue(ActionEnvironment& environment, 98 i2c::I2CInterface& interface) 99 { 100 // Check if an exponent value is defined for this action 101 if (exponent.has_value()) 102 { 103 return exponent.value(); 104 } 105 106 // Read value of the VOUT_MODE command 107 uint8_t voutModeValue; 108 interface.read(pmbus_utils::VOUT_MODE, voutModeValue); 109 110 // Parse VOUT_MODE value to get data format and parameter value 111 pmbus_utils::VoutDataFormat format; 112 int8_t parameter; 113 pmbus_utils::parseVoutMode(voutModeValue, format, parameter); 114 115 // Verify format is linear; other formats not currently supported 116 if (format != pmbus_utils::VoutDataFormat::linear) 117 { 118 throw PMBusError("VOUT_MODE contains unsupported data format", 119 environment.getDeviceID(), 120 environment.getDevice().getFRU()); 121 } 122 123 // Return parameter value; it contains the exponent when format is linear 124 return parameter; 125 } 126 127 } // namespace phosphor::power::regulators 128