Utility functions for download firmware
Added set of utility functions to be used within the classes for
managing the PSU firmware updates. Here is a breakdown of the key
functions:
- getDevicePath():
Construct the PSU device path using I2C bus and address.
- getClassInstance():
Determines the appropriate updater class to use based on PSU model
number.
- getFWFilenamePath():
Searches a directory for a firmware file matching a specified prefix
and file extension (.bin or .hex).
- calculateCRC8():
Computes the CRC-8 checksum for transferred data.
- delay():
Pauses execution for a specified number of milliseconds.
- bigEndianToLittleEndian():
Converts a 32-bit value from big-endian to little-endian.
- validateFWFile():
Checks if a firmware file exists and is non-empty.
- openFirmwareFile():
Opens a firmware file in binary mode, returning a file stream if
successful.
- readFirmwareBytes():
Reads specified number of data bytes from a firmware file into a
buffer. Return data read or null to the caller.
- usePsuJsonFile():
Wrapper to check the existence of the PSU JSON file.
- Class accessors to private data:
getPsuInventoryPath(): Accessor for PSU inventory path.
getDevPath(): Accessor for device path.
getDevName(): Accessor for device name.
getImageDir(): Accessor for image directory.
getI2C(): I2C interface accessor.
Tested every function manually:
- getDevicePath() (using busctl):
- Validate I2C bus and address values through psuInventoryPath
validate expected result
- Modified psuInventoryPath to invalid path
validate returned invalid path.
- getClassInstance():
- Validate with matching model number the function instantiate
appropriate class.
- Validate the default class instantiated.
- getFWFilenamePath():
- Validate return of the correct file name in the PSU FW directory
- Validate null returns when FW files don't exist
- calculaterCRC8():
- Validate single byte 0x0 result 0x0, single byte 0x01 result 0x07
- delay():
- Verified the task suspend execution.
- bigEndianToLittleEndian():
- Verified input 0x12345678 resulted in 0x78563412
- validateFWFile():
- Validate the existence of the file otherwise an error is logged
- Validate the file size is greater than 0 otherwise an error is
logged.
- openFirmwareFile():
- Validate ifstream object is returned and was able to read from.
- Validate error logged if the file name is null
- validate error logged when unable to open the file
- readFirmwareBytes():
- Validate data read from FW file
- Validate number of bytes read.
- usePsuJsonFile():
- Added JSON file to simulator and validated true return.
Change-Id: I0b8b24ae7d37724dab608d2c4977c1b42d4e1632
Signed-off-by: Faisal Awada <faisal@us.ibm.com>
diff --git a/tools/power-utils/updater.hpp b/tools/power-utils/updater.hpp
index 458f651..1732f86 100644
--- a/tools/power-utils/updater.hpp
+++ b/tools/power-utils/updater.hpp
@@ -16,11 +16,15 @@
#pragma once
#include "i2c_interface.hpp"
+#include "version.hpp"
#include <sdbusplus/bus.hpp>
+#include <chrono>
#include <filesystem>
+#include <memory>
#include <string>
+#include <thread>
class TestUpdater;
@@ -32,12 +36,14 @@
/**
* Update PSU firmware
*
+ * @param[in] bus - The sdbusplus DBus bus connection
* @param[in] psuInventoryPath - The inventory path of the PSU
* @param[in] imageDir - The directory containing the PSU image
*
* @return true if successful, otherwise false
*/
-bool update(const std::string& psuInventoryPath, const std::string& imageDir);
+bool update(sdbusplus::bus_t& bus, const std::string& psuInventoryPath,
+ const std::string& imageDir);
class Updater
{
@@ -60,7 +66,7 @@
const std::string& imageDir);
/** @brief Destructor */
- ~Updater() = default;
+ virtual ~Updater() = default;
/** @brief Bind or unbind the driver
*
@@ -84,7 +90,7 @@
*
* @return 0 if success, otherwise non-zero
*/
- int doUpdate();
+ virtual int doUpdate();
/** @brief Create I2C device
*
@@ -93,6 +99,37 @@
*/
void createI2CDevice();
+ protected:
+ /** @brief Accessor for PSU inventory path */
+ const std::string& getPsuInventoryPath() const
+ {
+ return psuInventoryPath;
+ }
+
+ /** @brief Accessor for device path */
+ const std::string& getDevPath() const
+ {
+ return devPath;
+ }
+
+ /** @brief Accessor for device name */
+ const std::string& getDevName() const
+ {
+ return devName;
+ }
+
+ /** @brief Accessor for image directory */
+ const std::string& getImageDir() const
+ {
+ return imageDir;
+ }
+
+ /** @brief I2C interface accessor */
+ i2c::I2CInterface* getI2C()
+ {
+ return i2c.get();
+ }
+
private:
/** @brief The sdbusplus DBus bus connection */
sdbusplus::bus_t bus;
@@ -128,4 +165,122 @@
std::unique_ptr<i2c::I2CInterface> i2c;
};
+namespace internal
+{
+
+/**
+ * @brief Get the device name from the device path
+ *
+ * @param[in] devPath - PSU path
+ *
+ * @return device name e.g. 3-0068
+ */
+std::string getDeviceName(std::string devPath);
+
+/**
+ * @brief Function to get device path using DBus bus and PSU
+ * inventory Path
+ *
+ * @param[in] bus - The sdbusplus DBus bus connection
+ * @param[in] psuInventoryPath - PSU inventory path
+ *
+ * @return device path e.g. /sys/bus/i2c/devices/3-0068
+ */
+std::string getDevicePath(sdbusplus::bus_t& bus,
+ const std::string& psuInventoryPath);
+
+/**
+ * @brief Parse the device name to obtain bus and device address
+ *
+ * @param[in] devName - Device name
+ *
+ * @return bus and device address
+ */
+std::pair<uint8_t, uint8_t> parseDeviceName(const std::string& devName);
+
+/**
+ * @brief Factory function to create an Updater instance based on PSU model
+ * number
+ *
+ * @param[in] model - PSU model number
+ * @param[in] psuInventoryPath - PSU inventory path
+ * @param[in] devPath - Device path
+ * @param[in] imageDir - Image directory
+ *
+ * return pointer class based on the device PSU model.
+ */
+std::unique_ptr<updater::Updater> getClassInstance(
+ const std::string& model, const std::string& psuInventoryPath,
+ const std::string& devPath, const std::string& imageDir);
+
+/**
+ * @brief Retrieve the firmware filename path in the specified directory
+ *
+ * @param[in] directory - Path to FS directory
+ *
+ * @retun filename or null
+ */
+const std::string getFWFilenamePath(const std::string& directory);
+
+/**
+ * @brief Calculate CRC-8 for a data vector
+ *
+ * @param[in] data - Firmware data block
+ *
+ * @return CRC8
+ */
+uint8_t calculateCRC8(const std::vector<uint8_t>& data);
+
+/**
+ * @brief Delay execution in milliseconds
+ *
+ * @param[in] milliseconds - Time in milliseconds
+ */
+void delay(const int& milliseconds);
+
+/**
+ * @brief Convert a big-endian value to little-endian
+ *
+ * @param[in] bigEndianValue - Uint 32 bit value
+ *
+ * @return vector of little endians.
+ */
+std::vector<uint8_t> bigEndianToLittleEndian(const uint32_t bigEndianValue);
+
+/**
+ * @brief Validate the existence and size of a firmware file.
+ *
+ * @param[in] fileName - Firmware file name
+ *
+ * @return true for success or false
+ */
+bool validateFWFile(const std::string& fileName);
+
+/**
+ * @brief Open a firmware file for reading in binary mode.
+ *
+ * @param[in] fileName - Firmware file name
+ *
+ * @return pointer to firmware file stream
+ */
+std::unique_ptr<std::ifstream> openFirmwareFile(const std::string& fileName);
+
+/**
+ * @brief Read firmware bytes from file.
+ *
+ * @param[in] inputFile - Input file stream
+ * @param[in] numberOfBytesToRead - Number of bytes to read from firmware file.
+ *
+ * @return vector of data read
+ */
+std::vector<uint8_t> readFirmwareBytes(std::ifstream& inputFile,
+ const size_t numberOfBytesToRead);
+
+/**
+ * @brief Wrapper to check existence of PSU JSON file
+ *
+ * @return true or false (true if using JSON file)
+ */
+bool usePsuJsonFile();
+} // namespace internal
} // namespace updater