1 /**
2  * Copyright © 2019 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 "i2c_interface.hpp"
19 
20 #include <sdbusplus/bus.hpp>
21 
22 #include <filesystem>
23 #include <memory>
24 #include <string>
25 
26 class TestUpdater;
27 
28 namespace updater
29 {
30 
31 namespace fs = std::filesystem;
32 
33 /**
34  * Update PSU firmware
35  *
36  * @param[in] bus - The sdbusplus DBus bus connection
37  * @param[in] psuInventoryPath - The inventory path of the PSU
38  * @param[in] imageDir - The directory containing the PSU image
39  *
40  * @return true if successful, otherwise false
41  */
42 bool update(sdbusplus::bus_t& bus, const std::string& psuInventoryPath,
43             const std::string& imageDir);
44 
45 class Updater
46 {
47   public:
48     friend TestUpdater;
49     Updater() = delete;
50     Updater(const Updater&) = delete;
51     Updater& operator=(const Updater&) = delete;
52     Updater(Updater&&) = default;
53     Updater& operator=(Updater&&) = default;
54 
55     /**
56      * @brief Constructor
57      *
58      * @param psuInventoryPath - The PSU inventory path
59      * @param devPath - The PSU device path
60      * @param imageDir - The update image directory
61      */
62     Updater(const std::string& psuInventoryPath, const std::string& devPath,
63             const std::string& imageDir);
64 
65     /** @brief Destructor */
66     virtual ~Updater() = default;
67 
68     /** @brief Bind or unbind the driver
69      *
70      * @param doBind - indicate if it's going to bind or unbind the driver
71      */
72     void bindUnbind(bool doBind);
73 
74     /** @brief Set the PSU inventory present property
75      *
76      * @param present - The present state to set
77      */
78     void setPresent(bool present);
79 
80     /** @brief Check if it's ready to update the PSU
81      *
82      * @return true if it's ready, otherwise false
83      */
84     bool isReadyToUpdate();
85 
86     /** @brief Do the PSU update
87      *
88      * @return 0 if success, otherwise non-zero
89      */
90     virtual int doUpdate();
91 
92     /** @brief Create I2C device
93      *
94      * Creates the I2C device based on the device name.
95      * e.g. It opens busId 3, address 0x68 for "3-0068"
96      */
97     void createI2CDevice();
98 
99   protected:
100     /** @brief Accessor for PSU inventory path */
getPsuInventoryPath() const101     const std::string& getPsuInventoryPath() const
102     {
103         return psuInventoryPath;
104     }
105 
106     /** @brief Accessor for device path */
getDevPath() const107     const std::string& getDevPath() const
108     {
109         return devPath;
110     }
111 
112     /** @brief Accessor for device name */
getDevName() const113     const std::string& getDevName() const
114     {
115         return devName;
116     }
117 
118     /** @brief Accessor for image directory */
getImageDir() const119     const std::string& getImageDir() const
120     {
121         return imageDir;
122     }
123 
124     /** @brief I2C interface accessor */
getI2C()125     i2c::I2CInterface* getI2C()
126     {
127         return i2c.get();
128     }
129 
130   private:
131     /** @brief The sdbusplus DBus bus connection */
132     sdbusplus::bus_t bus;
133 
134     /** @brief The PSU inventory path */
135     std::string psuInventoryPath;
136 
137     /** @brief The PSU device path
138      *
139      * Usually it is a device in i2c subsystem, e.g.
140      *   /sys/bus/i2c/devices/3-0068
141      */
142     std::string devPath;
143 
144     /** @brief The PSU device name
145      *
146      * Usually it is a i2c device name, e.g.
147      *   3-0068
148      */
149     std::string devName;
150 
151     /** @brief The PSU image directory */
152     std::string imageDir;
153 
154     /** @brief The PSU device driver's path
155      *
156      * Usually it is the PSU driver, e.g.
157      *   /sys/bus/i2c/drivers/ibm-cffps
158      */
159     fs::path driverPath;
160 
161     /** @brief The i2c device interface */
162     std::unique_ptr<i2c::I2CInterface> i2c;
163 };
164 
165 namespace internal
166 {
167 
168 /**
169  * @brief Factory function to create an Updater instance based on PSU model
170  * number
171  *
172  * @param[in] model - PSU model number
173  * @param[in] psuInventoryPath - PSU inventory path
174  * @param[in] devPath - Device path
175  * @param[in] imageDir - Image directory
176  *
177  * return pointer class based on the device PSU model.
178  */
179 std::unique_ptr<updater::Updater> getClassInstance(
180     const std::string& model, const std::string& psuInventoryPath,
181     const std::string& devPath, const std::string& imageDir);
182 
183 /**
184  * @brief Retrieve the firmware filename path in the specified directory
185  *
186  * @param[in] directory - Path to FS directory
187  *
188  * @retun filename or null
189  */
190 const std::string getFWFilenamePath(const std::string& directory);
191 
192 /**
193  * @brief Calculate CRC-8 for a data vector
194  *
195  * @param[in] data - Firmware data block
196  *
197  * @return CRC8
198  */
199 uint8_t calculateCRC8(const std::vector<uint8_t>& data);
200 
201 /**
202  * @brief Delay execution in milliseconds
203  *
204  * @param[in] milliseconds - Time in milliseconds
205  */
206 void delay(const int& milliseconds);
207 
208 /**
209  * @brief Convert a big-endian value to little-endian
210  *
211  * @param[in] bigEndianValue - Uint 32 bit value
212  *
213  * @return vector of little endians.
214  */
215 std::vector<uint8_t> bigEndianToLittleEndian(const uint32_t bigEndianValue);
216 
217 /**
218  * @brief Validate the existence and size of a firmware file.
219  *
220  * @param[in] fileName - Firmware file name
221  *
222  * @return true for success or false
223  */
224 bool validateFWFile(const std::string& fileName);
225 
226 /**
227  * @brief Open a firmware file for reading in binary mode.
228  *
229  * @param[in] fileName - Firmware file name
230  *
231  * @return pointer to firmware file stream
232  */
233 std::unique_ptr<std::ifstream> openFirmwareFile(const std::string& fileName);
234 
235 /**
236  * @brief Read firmware bytes from file.
237  *
238  * @param[in] inputFile - Input file stream
239  * @param[in] numberOfBytesToRead - Number of bytes to read from firmware file.
240  *
241  * @return vector of data read
242  */
243 std::vector<uint8_t> readFirmwareBytes(std::ifstream& inputFile,
244                                        const size_t numberOfBytesToRead);
245 
246 } // namespace internal
247 } // namespace updater
248