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 #pragma once
17 
18 #include "action_environment.hpp"
19 #include "i2c_action.hpp"
20 #include "i2c_interface.hpp"
21 #include "pmbus_utils.hpp"
22 #include "sensors.hpp"
23 
24 #include <cstdint>
25 #include <optional>
26 #include <string>
27 
28 namespace phosphor::power::regulators
29 {
30 
31 /**
32  * @class PMBusReadSensorAction
33  *
34  * Reads one sensor for a PMBus regulator rail. Communicates with the device
35  * directly using the I2C interface.
36  *
37  * Implements the pmbus_read_sensor action in the JSON config file.
38  *
39  * Currently supports the linear_11 and linear_16 sensor data formats.
40  *
41  * The linear_16 data format requires an exponent value.  The exponent value
42  * can be specified in the constructor.  Otherwise the exponent value will be
43  * obtained from the PMBus VOUT_MODE command.  Note that some PMBus devices do
44  * not support the VOUT_MODE command.  The exponent value for a device is often
45  * found in the device documentation (data sheet).
46  */
47 class PMBusReadSensorAction : public I2CAction
48 {
49   public:
50     // Specify which compiler-generated methods we want
51     PMBusReadSensorAction() = delete;
52     PMBusReadSensorAction(const PMBusReadSensorAction&) = delete;
53     PMBusReadSensorAction(PMBusReadSensorAction&&) = delete;
54     PMBusReadSensorAction& operator=(const PMBusReadSensorAction&) = delete;
55     PMBusReadSensorAction& operator=(PMBusReadSensorAction&&) = delete;
56     virtual ~PMBusReadSensorAction() = default;
57 
58     /**
59      * Constructor.
60      *
61      * @param type Sensor type.
62      * @param command PMBus command code.
63      * @param format Data format of the sensor value returned by the device.
64      * @param exponent Exponent value for linear_16 data format.
65      *                 Can be positive or negative. If not specified, the
66      *                 exponent value will be read from VOUT_MODE.
67      *                 Should not be specified if the data format is linear_11.
68      */
69     explicit PMBusReadSensorAction(SensorType type, uint8_t command,
70                                    pmbus_utils::SensorDataFormat format,
71                                    std::optional<int8_t> exponent) :
72         type{type},
73         command{command}, format{format}, exponent{exponent}
74     {}
75 
76     /**
77      * Executes this action.
78      *
79      * Reads one sensor using the I2C interface.
80      *
81      * The sensor type is specified in the constructor.
82      *
83      * The PMBus command code is specified in the constructor.
84      * It is the register to read on the device.
85      *
86      * The sensor data format is specified in the constructor. Currently
87      * the linear_11 and linear_16 formats are supported.
88      *
89      * The linear_16 data format requires an exponent value.
90      * If an exponent value was specified in the constructor, that
91      * value will be used.  Otherwise the exponent value will be obtained from
92      * the VOUT_MODE command.
93      *
94      * The device is obtained from the ActionEnvironment.
95      *
96      * Throws an exception if an error occurs.
97      *
98      * @param environment Action execution environment.
99      * @return true
100      */
101     virtual bool execute(ActionEnvironment& environment) override;
102 
103     /**
104      * Returns the PMBus command code.
105      *
106      * @return command
107      */
108     uint8_t getCommand() const
109     {
110         return command;
111     }
112 
113     /**
114      * Returns the optional exponent value for linear_16 data format.
115      *
116      * @return optional exponent value
117      */
118     std::optional<int8_t> getExponent() const
119     {
120         return exponent;
121     }
122 
123     /**
124      * Returns the data format of the sensor value returned by the device.
125      *
126      * @return data format
127      */
128     pmbus_utils::SensorDataFormat getFormat() const
129     {
130         return format;
131     }
132 
133     /**
134      * Returns the sensor type.
135      *
136      * @return sensor type.
137      */
138     SensorType getType() const
139     {
140         return type;
141     }
142 
143     /**
144      * Returns a string description of this action.
145      *
146      * @return description of action
147      */
148     virtual std::string toString() const override;
149 
150   private:
151     /**
152      * Gets the exponent value to use to convert a linear_16 format value to a
153      * decimal volts value.
154      *
155      * If an exponent value is defined for this action, that value is returned.
156      * Otherwise VOUT_MODE is read from the current device to obtain the
157      * exponent value.
158      *
159      * Throws an exception if an error occurs.
160      *
161      * @param environment action execution environment
162      * @param interface I2C interface to the current device
163      * @return exponent value
164      */
165     int8_t getExponentValue(ActionEnvironment& environment,
166                             i2c::I2CInterface& interface);
167 
168     /**
169      * Sensor type.
170      */
171     const SensorType type{};
172 
173     /**
174      * PMBus command code.
175      */
176     const uint8_t command{};
177 
178     /**
179      * Data format of the sensor value returned by the device.
180      */
181     const pmbus_utils::SensorDataFormat format{};
182 
183     /**
184      * Optional exponent value for linear_16 data format.
185      */
186     const std::optional<int8_t> exponent{};
187 };
188 
189 } // namespace phosphor::power::regulators
190