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 
21 #include <cstdint>
22 #include <stdexcept>
23 #include <string>
24 #include <vector>
25 
26 namespace phosphor::power::regulators
27 {
28 
29 /**
30  * @class I2CWriteBytesAction
31  *
32  * Writes bytes to a device register.  Communicates with the device directly
33  * using the I2C interface.
34  *
35  * Implements the i2c_write_bytes action in the JSON config file.
36  */
37 class I2CWriteBytesAction : public I2CAction
38 {
39   public:
40     // Specify which compiler-generated methods we want
41     I2CWriteBytesAction() = delete;
42     I2CWriteBytesAction(const I2CWriteBytesAction&) = delete;
43     I2CWriteBytesAction(I2CWriteBytesAction&&) = delete;
44     I2CWriteBytesAction& operator=(const I2CWriteBytesAction&) = delete;
45     I2CWriteBytesAction& operator=(I2CWriteBytesAction&&) = delete;
46     virtual ~I2CWriteBytesAction() = default;
47 
48     /**
49      * Constructor.
50      *
51      * Throws an exception if any of the input parameters are invalid.
52      *
53      * @param reg Device register address.  Note: named 'reg' because 'register'
54      *            is a reserved keyword.
55      * @param values One or more byte values to write.  The bytes must be
56      *               specified in the order required by the device (e.g. in
57      *               little-endian order).
58      */
I2CWriteBytesAction(uint8_t reg,const std::vector<uint8_t> & values)59     explicit I2CWriteBytesAction(uint8_t reg,
60                                  const std::vector<uint8_t>& values) :
61         reg{reg},
62         values{values}, masks{}
63     {
64         // Values vector must not be empty
65         if (values.size() < 1)
66         {
67             throw std::invalid_argument{"Values vector is empty"};
68         }
69     }
70 
71     /**
72      * Constructor.
73      *
74      * Throws an exception if any of the input parameters are invalid.
75      *
76      * @param reg Device register address.  Note: named 'reg' because 'register'
77      *            is a reserved keyword.
78      * @param values One or more byte values to write.  The bytes must be
79      *               specified in the order required by the device (e.g. in
80      *               little-endian order).
81      * @param masks One or more bit masks.  The number of bit masks must match
82      *              the number of byte values to write.  Each mask specifies
83      *              which bits to write within the corresponding byte value.
84      *              Only the bits with a value of 1 in the mask will be written.
85      */
I2CWriteBytesAction(uint8_t reg,const std::vector<uint8_t> & values,const std::vector<uint8_t> & masks)86     explicit I2CWriteBytesAction(uint8_t reg,
87                                  const std::vector<uint8_t>& values,
88                                  const std::vector<uint8_t>& masks) :
89         reg{reg},
90         values{values}, masks{masks}
91     {
92         // Values vector must not be empty
93         if (values.size() < 1)
94         {
95             throw std::invalid_argument{"Values vector is empty"};
96         }
97 
98         // Masks vector must have same size as values vector
99         if (masks.size() != values.size())
100         {
101             throw std::invalid_argument{"Masks vector has invalid size"};
102         }
103     }
104 
105     /**
106      * Executes this action.
107      *
108      * Writes bytes to a device register using the I2C interface.
109      *
110      * All of the bytes will be written in a single I2C operation.
111      *
112      * The device register, byte values, and bit masks (if any) were specified
113      * in the constructor.
114      *
115      * The device is obtained from the specified action environment.
116      *
117      * Throws an exception if an error occurs.
118      *
119      * @param environment action execution environment
120      * @return true
121      */
122     virtual bool execute(ActionEnvironment& environment) override;
123 
124     /**
125      * Returns the device register address.
126      *
127      * @return register address
128      */
getRegister() const129     uint8_t getRegister() const
130     {
131         return reg;
132     }
133 
134     /**
135      * Returns the byte values to write.
136      *
137      * @return values to write
138      */
getValues() const139     const std::vector<uint8_t>& getValues() const
140     {
141         return values;
142     }
143 
144     /**
145      * Returns the bit masks.
146      *
147      * Each mask specifies which bits to write within the corresponding byte
148      * value.  Only the bits with a value of 1 in the mask will be written.
149      *
150      * @return bit masks
151      */
getMasks() const152     const std::vector<uint8_t>& getMasks() const
153     {
154         return masks;
155     }
156 
157     /**
158      * Returns a string description of this action.
159      *
160      * @return description of action
161      */
162     virtual std::string toString() const override;
163 
164   private:
165     /**
166      * Device register address.  Note: named 'reg' because 'register' is a
167      * reserved keyword.
168      */
169     const uint8_t reg{0x00};
170 
171     /**
172      * Byte values to write.
173      */
174     const std::vector<uint8_t> values{};
175 
176     /**
177      * Bit masks.  Each mask specifies which bits to write within the
178      * corresponding byte value.  Only the bits with a value of 1 in the mask
179      * will be written.
180      */
181     const std::vector<uint8_t> masks{};
182 };
183 
184 } // namespace phosphor::power::regulators
185