blob: d12847c80193507ec264688cd481b5f820183591 [file] [log] [blame] [edit]
extern "C"
{
#include <i2c/smbus.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
}
#include "include/common_utility.hpp"
namespace util
{
std::vector<fs::path> findFiles(const fs::path& dirPath,
const std::string& matchString)
{
std::vector<fs::path> foundPaths;
if (!fs::exists(dirPath))
{
lg2::error("Directory {PATH} does not exist", "PATH", dirPath);
return foundPaths;
}
std::regex search(matchString);
std::smatch match;
for (const auto& p : fs::directory_iterator(dirPath))
{
std::string path = p.path().string();
if (std::regex_search(path, match, search))
{
foundPaths.emplace_back(p.path());
}
}
if (foundPaths.empty())
{
lg2::error("No file found in {PATH} with {STRING}", "PATH", dirPath,
"STRING", matchString);
}
return foundPaths;
}
bool checkPartNumber(std::string_view fileName, const json& configuration)
{
auto [boardName,
partNumberPrefixes] = getBoardAndPartNumberPrefixes(configuration);
if (boardName.empty() || partNumberPrefixes.empty())
{
lg2::error("Board or PartNumberPrefix is empty in {NAME}", "NAME",
fileName);
return false;
}
const std::string fruService = "xyz.openbmc_project.FruDevice";
const std::string fruObject = "/xyz/openbmc_project/FruDevice/" + boardName;
const std::string fruInterface = "xyz.openbmc_project.FruDevice";
const std::string property = "BOARD_PART_NUMBER";
auto [success, value] = getProperty(fruService, fruObject, fruInterface,
property);
if (!success)
{
lg2::info("{FILENAME} PartNumber is not available", "FILENAME",
fileName);
return false;
}
const auto* strVal = std::get_if<std::string>(&value);
if (strVal != nullptr)
{
const std::string dbusPartNumberPrefix = strVal->substr(0, 7);
auto it = std::find(partNumberPrefixes.begin(),
partNumberPrefixes.end(), dbusPartNumberPrefix);
if (it == partNumberPrefixes.end())
{
lg2::error("{FILENAME} PartNumberPrefix is not match", "FILENAME",
fileName);
return false;
}
}
else
{
lg2::error("{FILENAME} PartNumber is not a string", "FILENAME",
fileName);
}
std::vector<std::string> properties = {
"BOARD_INFO_AM1", "BOARD_INFO_AM2", "BOARD_INFO_AM3",
"PRODUCT_INFO_AM1", "PRODUCT_INFO_AM2", "PRODUCT_INFO_AM3"};
for (const auto& property : properties)
{
if (configuration.contains(property))
{
std::string jsonValue = configuration[property];
auto [success, dbusValue] = getProperty(fruService, fruObject,
fruInterface, property);
if (!success)
{
continue;
}
auto* strVal = std::get_if<std::string>(&dbusValue);
if (strVal != nullptr)
{
std::string dbusProperty = strVal->substr();
if (jsonValue != dbusProperty)
{
lg2::error("{PROPERTY} does not match", "PROPERTY",
property);
return false;
}
}
else
{
lg2::error("{FILENAME} {PROPERTY} is not a string", "FILENAME",
fileName, "PROPERTY", property);
return false;
}
}
}
lg2::info("Vr config Added: {FILENAME}", "FILENAME", fileName);
return true;
}
std::string getBoodID()
{
const std::string bootIdPath = "/proc/sys/kernel/random/boot_id";
std::ifstream bootIdFile(bootIdPath);
if (!bootIdFile.is_open())
{
lg2::error("Unable to open boot_id file");
return "";
}
std::string bootId;
std::getline(bootIdFile, bootId);
bootIdFile.close();
lg2::info("Boot ID: {ID}", "ID", bootId);
return bootId;
}
void summarizeLog(DbusUtil* dbusUtil, std::string_view msg,
const fs::path& logDirPath, const std::string_view filename)
{
std::time_t currentTime =
std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
const std::string kCurrentBoot = "currentBoot";
const std::string kPreviousBoot = "previousBoot";
const std::string kBootIdFile = "boot_id.log";
const fs::path logDirPathCurrent = logDirPath / kCurrentBoot;
const fs::path logDirPathPrevious = logDirPath / kPreviousBoot;
if (!fs::exists(logDirPathCurrent))
{
fs::create_directories(logDirPathCurrent);
std::ofstream ofsCurrent(logDirPathCurrent / kBootIdFile);
ofsCurrent << getBoodID();
ofsCurrent.close();
}
else
{
std::ifstream ifsCurrent(logDirPathCurrent / kBootIdFile);
std::string bootIdCurrent;
ifsCurrent >> bootIdCurrent;
ifsCurrent.close();
std::string bootId = getBoodID();
if (bootIdCurrent != bootId)
{
fs::remove_all(logDirPathPrevious);
fs::rename(logDirPathCurrent, logDirPathPrevious);
fs::create_directories(logDirPathCurrent);
std::ofstream ofsCurrent(logDirPathCurrent / kBootIdFile);
ofsCurrent << bootId;
ofsCurrent.close();
}
}
size_t fileCount = 0;
for (const auto& entry : fs::directory_iterator(logDirPathCurrent))
{
if (entry.is_regular_file() &&
entry.path().filename().string().starts_with(filename))
{
fileCount++;
}
}
if (fileCount > 100)
{
return;
}
std::string filenameStr = std::string(filename) + "_" +
std::to_string(fileCount);
fs::path logFilePath = logDirPathCurrent / filenameStr;
std::ofstream ofs(logFilePath, std::ios::binary | std::ios::app);
if (!ofs.is_open())
{
lg2::error("Error: Unable to open file.");
return;
}
ofs.seekp(0, std::ios::end);
uint64_t fileSize = ofs.tellp();
uint64_t msgSize =
msg.size() +
25; // 25 for timestamp length: "Www Mmm dd hh:mm:ss yyyy\n"
std::string now = std::ctime(&currentTime);
std::replace(now.begin(), now.end(), '\n', ':');
if (msgSize > kMaxLogSize)
{
std::string_view truncatedMsg = msg.substr(0, kMaxLogSize - 25);
ofs.close();
ofs.open(logFilePath, std::ios::binary | std::ios::trunc);
ofs << now << "\n" << truncatedMsg << '\n';
}
else
{
if (fileSize + msgSize > kMaxLogSize)
{
ofs.close();
uint64_t bytesToKeep = kMaxLogSize - msgSize;
if (bytesToKeep > fileSize)
{
bytesToKeep = fileSize;
}
std::ifstream ifs(logFilePath, std::ios::binary);
ifs.seekg(static_cast<int64_t>(fileSize - bytesToKeep),
std::ios::beg);
std::vector<char> buffer(bytesToKeep);
ifs.read(buffer.data(), static_cast<int64_t>(buffer.size()));
ifs.close();
ofs.open(logFilePath, std::ios::binary | std::ios::trunc);
ofs.write(buffer.data(), static_cast<int64_t>(buffer.size()));
}
ofs << now << "\n" << msg << '\n';
}
ofs.close();
lg2::info("{TIME}", "TIME", now);
lg2::info("{MSG}", "MSG", msg);
lg2::info("Stored log file: {FILE}", "FILE", logFilePath);
std::cerr << logFilePath << "<logFilePath\n";
dbusUtil->dbusAddStoredLog(filenameStr);
}
std::pair<bool, PropertyValue> getProperty(const std::string& serviceName,
const std::string& objectPath,
const std::string& interface,
const std::string& propertyName)
{
try
{
auto bus = sdbusplus::bus::new_default();
auto method =
bus.new_method_call(serviceName.c_str(), objectPath.c_str(),
"org.freedesktop.DBus.Properties", "Get");
method.append(interface, propertyName);
auto reply = bus.call(method);
PropertyValue value;
reply.read(value);
return {true, value};
}
catch (const sdbusplus::exception_t& e)
{
lg2::error("Unable to get property: {ERR}", "ERR", e);
return {false, {}};
}
}
int i2cOpenDevice(const uint16_t bus, const uint16_t address)
{
std::string i2cDev = "/dev/i2c-" + std::to_string(bus);
int fd = open(i2cDev.c_str(), O_RDWR);
if (fd < 0)
{
lg2::error("Unable to open i2c device.");
return -1;
}
if (ioctl(fd, I2C_SLAVE_FORCE, address) < 0)
{
close(fd);
lg2::error("Unable to set i2c slave address.");
return -1;
}
return fd;
}
void i2cWriteByte(const uint8_t bus, const uint8_t address,
const uint8_t command, const uint8_t value)
{
int fd = i2cOpenDevice(bus, address);
if (fd < 0)
{
lg2::error("i2cWriteByte failed");
return;
}
i2c_smbus_write_byte_data(fd, command, value);
close(fd);
}
std::vector<uint8_t> i2cWriteRead(const uint8_t bus, const uint8_t address,
const std::vector<uint8_t>& writeBuf,
const uint16_t writeLen,
const uint16_t recvLen)
{
std::vector<uint8_t> recvData;
int fd = i2cOpenDevice(bus, address);
if (fd < 0)
{
lg2::error("i2cWriteRead failed");
close(fd);
return {};
}
struct i2c_rdwr_ioctl_data data
{};
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays)
struct i2c_msg messages[2];
messages[0].addr = address;
messages[0].flags = 0;
messages[0].len = writeLen;
messages[0].buf = const_cast<uint8_t*>(writeBuf.data()); // NOLINT
recvData.resize(recvLen);
messages[1].addr = address;
messages[1].flags = I2C_M_RD;
messages[1].len = recvLen;
messages[1].buf = recvData.data();
data.msgs = static_cast<i2c_msg*>(messages);
data.nmsgs = 2;
if (ioctl(fd, I2C_RDWR, &data) < 0)
{
lg2::error("Unable to write and read data from i2c device.");
}
close(fd);
return recvData;
}
std::uint8_t i2cReadByte(const uint8_t bus, const uint8_t address,
const uint8_t reg)
{
int fd = i2cOpenDevice(bus, address);
if (fd < 0)
{
lg2::error("i2cReadByte failed");
return 0;
}
uint8_t value = 0;
uint8_t buf = reg;
struct i2c_rdwr_ioctl_data data
{};
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays)
struct i2c_msg messages[2];
messages[0].addr = address;
messages[0].flags = 0;
messages[0].len = 1;
messages[0].buf = &buf;
messages[1].addr = address;
messages[1].flags = I2C_M_RD;
messages[1].len = 1;
messages[1].buf = &value;
data.msgs = static_cast<i2c_msg*>(messages);
data.nmsgs = 2;
if (ioctl(fd, I2C_RDWR, &data) < 0)
{
lg2::error("Unable to read byte from i2c device.");
}
close(fd);
return 0;
}
std::vector<uint8_t> i2cReadBytes(const uint8_t bus, const uint8_t address,
const uint8_t reg, const uint16_t length)
{
int fd = i2cOpenDevice(bus, address);
if (fd < 0)
{
lg2::error("i2cReadBytes failed");
return {};
}
std::vector<uint8_t> buffer(length);
uint8_t buf = reg;
struct i2c_rdwr_ioctl_data data
{};
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays)
struct i2c_msg messages[2];
messages[0].addr = address;
messages[0].flags = 0;
messages[0].len = 1;
messages[0].buf = &buf;
messages[1].addr = address;
messages[1].flags = I2C_M_RD;
messages[1].len = length;
messages[1].buf = buffer.data();
data.msgs = static_cast<i2c_msg*>(messages);
data.nmsgs = 2;
if (ioctl(fd, I2C_RDWR, &data) < 0)
{
lg2::error("Unable to read bytes from i2c device.");
}
close(fd);
return {};
}
double convertFromLinear(const uint16_t value)
{
uint8_t exponentField = value >> 11;
uint16_t mantissaField = value & 0x7FFU;
bool negativeExp = exponentField > 0x0FU;
if (negativeExp)
{
exponentField = 32 - exponentField;
}
if (mantissaField > 0x03FFU)
{
mantissaField = 2048 - mantissaField;
}
int8_t exponent = static_cast<int8_t>(exponentField);
int16_t mantissa = static_cast<int16_t>(mantissaField);
return negativeExp ? mantissa / std::pow(2.0, exponent)
: mantissa * std::pow(2.0, exponent);
}
double convertFromVoutLinear(const uint16_t value, const int8_t exponent)
{
return value * std::pow(2.0, exponent);
}
double convertFromDirect(const uint16_t value, const int16_t m, const int16_t b,
const int8_t r)
{
if (m == 0)
{
lg2::error("Error: Divided by zero");
return 0;
}
return (value * std::pow(10.0, -r) - b) / m;
}
uint16_t parseDec(const json& element)
{
if (!element.is_string())
{
lg2::error("Element is not a string");
return 0;
}
std::string value = element.get<std::string>();
std::regex decimalRegex("^-?[0-9]+$");
if (!std::regex_match(value, decimalRegex))
{
lg2::error("Element is not decimal string");
return 0;
}
return static_cast<uint16_t>(std::stoul(value, nullptr, 0));
}
std::vector<uint8_t> parseHexByteArray(const json& element)
{
if (!element.is_array())
{
return {};
}
std::vector<uint8_t> values;
for (const auto& valueElement : element)
{
values.emplace_back(parseHexByte(valueElement));
}
return values;
}
uint8_t parseHexByte(const json& element)
{
if (!element.is_string())
{
lg2::error("Element is not a string");
return 0;
}
std::string value = element.get<std::string>();
std::regex hexPattern("^0x[0-9a-fA-F]{1,3}$");
if (!std::regex_match(value, hexPattern))
{
lg2::error("Element is not hexadecimal string");
return 0;
}
return static_cast<uint8_t>(std::stoul(value, nullptr, 16));
}
uint16_t bytesIntoWord(std::string_view upperByte, std::string_view lowerByte)
{
return (parseHexByte(upperByte) << 8) | parseHexByte(lowerByte);
}
std::string byteArrayToHexString(uint8_t* buf, const uint16_t len)
{
std::stringstream result;
for (uint16_t i = 0; i < len; ++i)
{
result << "0x" << std::setw(2) << std::setfill('0') << std::hex
<< static_cast<int>(buf[i]) << std::dec << " "; // NOLINT
}
return result.str();
}
std::string getCurrentTimestamp()
{
std::time_t currentTime =
std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::tm* gmTime = std::gmtime(&currentTime);
gmTime->tm_hour -= 8;
std::mktime(gmTime);
std::ostringstream oss;
oss << std::put_time(gmTime, "%Y-%m-%d %H:%M:%S");
return oss.str();
}
} // namespace util