| #include "include/power_rail/max34451_utility.hpp" |
| |
| #include "include/common_utility.hpp" |
| |
| #include <nlohmann/json.hpp> |
| |
| #include <fstream> |
| #include <iomanip> |
| #include <iostream> |
| #include <optional> |
| #include <string> |
| |
| namespace max34451 |
| { |
| void Max34451Logger::loadConfig(std::string_view configFilePath) |
| { |
| std::ifstream file(configFilePath.data()); |
| json jsonConfig; |
| file >> jsonConfig; |
| |
| auto getValue = [&](const json& source, std::string_view key, auto& dest, |
| auto parseFunc) { |
| if (source.contains(key)) |
| { |
| dest = parseFunc(source[key]); |
| return true; |
| } |
| lg2::info("{KEY} is not defined in the config file", "KEY", key); |
| return false; |
| }; |
| |
| if (!(getValue(jsonConfig, kBus, bus, util::parseDec) && |
| getValue(jsonConfig, kAddress, address, util::parseHexByte) && |
| getValue(jsonConfig, kSource, source, |
| [](const auto& val) { return val; }))) |
| { |
| return; |
| } |
| |
| if (jsonConfig.contains(kIncludeWarnings)) |
| { |
| includeWarnings = jsonConfig[kIncludeWarnings]; |
| } |
| |
| if (jsonConfig.contains(kRegisters)) |
| { |
| const auto& registers = jsonConfig[kRegisters]; |
| getValue(registers, kMfrChannelConfigReg, mfrChannelConfigReg, |
| util::parseHexByte); |
| getValue(registers, kMfrPsenConfigReg, mfrPsenConfigReg, |
| util::parseHexByte); |
| getValue(registers, kMfrPwmConfigReg, mfrPwmConfigReg, |
| util::parseHexByte); |
| getValue(registers, kMfrNvFaultLogReg, mfrNvFaultLogReg, |
| util::parseHexByte); |
| getValue(registers, kMfrNvLogConfigReg, mfrNvLogConfigReg, |
| util::parseHexByte); |
| getValue(registers, kStatusWordReg, statusWordReg, util::parseHexByte); |
| getValue(registers, kStatusCmlReg, statusCmlReg, util::parseHexByte); |
| getValue(registers, kStatusMfrSpecificReg, statusMfrSpecificReg, |
| util::parseHexByte); |
| } |
| |
| if (jsonConfig.contains(kFaultLogConfig)) |
| { |
| const auto& faultLogConfig = jsonConfig[kFaultLogConfig]; |
| getValue(faultLogConfig, kCommand, faultLogCommand, util::parseHexByte); |
| getValue(faultLogConfig, kOffset, faultLogOffset, util::parseDec); |
| } |
| |
| if (jsonConfig.contains(kEnableBits)) |
| { |
| const auto& enableBits = jsonConfig[kEnableBits]; |
| getValue(enableBits, kForceLog, forceLogBit, util::parseDec); |
| if (enableBits.contains(kClearLog)) |
| { |
| for (const auto& bit : enableBits[kClearLog]) |
| { |
| clearLogBits.emplace_back(util::parseDec(bit)); |
| } |
| } |
| } |
| |
| if (jsonConfig.contains(kSequencerRegisters)) |
| { |
| sequencerRegisters = |
| jsonConfig[kSequencerRegisters].get<std::vector<json>>(); |
| } |
| |
| if (jsonConfig.contains(kRailPriority)) |
| { |
| railPriority = |
| jsonConfig[kRailPriority].get<std::vector<std::string>>(); |
| } |
| } |
| |
| std::vector<uint8_t> getMax34451BB(const Max34451Logger& logger) |
| { |
| const uint16_t faultLogSize = 256; |
| std::vector<uint8_t> command; |
| command.push_back(logger.faultLogCommand); |
| |
| std::vector<uint8_t> faultLog = util::i2cWriteRead( |
| logger.bus, logger.address, command, command.size(), faultLogSize); |
| |
| if (faultLog.empty()) |
| { |
| lg2::error("Failed to read fault log from max34451"); |
| return {}; |
| } |
| |
| if (faultLog[faultLogSize - 2] != 0xdd) |
| { |
| lg2::info("max34451 black box is empty!"); |
| return {}; |
| } |
| |
| return faultLog; |
| } |
| |
| void max34451PowerRailParser(const Max34451Logger& logger, |
| const std::vector<uint8_t>& faultLog, |
| std::ostream& logFile) |
| { |
| for (const auto& seqReg : logger.sequencerRegisters) |
| { |
| for (const auto& [page, railName] : seqReg[kPageToPowerRailMap].items()) |
| { |
| uint8_t pageIndex = util::parseDec(page) + logger.faultLogOffset; |
| if (checkPowerRailFault(faultLog[pageIndex], |
| logger.includeWarnings)) |
| { |
| logFile << " " << railName << "\n"; |
| } |
| } |
| } |
| } |
| |
| void setMfrNvLogConfig(const Max34451Logger& logger, const uint8_t enableBit) |
| { |
| try |
| { |
| std::vector<uint8_t> i2cReadBytesResult = util::i2cReadBytes( |
| logger.bus, logger.address, logger.mfrNvLogConfigReg, 1); |
| if (i2cReadBytesResult.empty()) |
| { |
| lg2::error("Failed to read MFR NV Log Config"); |
| return; |
| } |
| uint8_t mfrNvLogConfig = i2cReadBytesResult[0]; |
| mfrNvLogConfig |= (1 << enableBit); |
| util::i2cWriteByte(logger.bus, logger.address, logger.mfrNvLogConfigReg, |
| mfrNvLogConfig); |
| } |
| catch (const std::exception& e) |
| { |
| lg2::error("Failed to set MFR NV Log Config: {ERR}", "ERR", e.what()); |
| } |
| } |
| |
| void forceMax34451Log(const Max34451Logger& logger) |
| { |
| setMfrNvLogConfig(logger, logger.forceLogBit); |
| usleep(500000); |
| } |
| |
| void clearMax34451BB(const Max34451Logger& logger) |
| { |
| for (const auto& bit : logger.clearLogBits) |
| { |
| setMfrNvLogConfig(logger, bit); |
| usleep(500000); |
| } |
| } |
| |
| uint16_t getWordAndLog(std::ostream& logFile, const std::vector<uint8_t>& data, |
| const uint8_t highIndex, const uint8_t lowIndex, |
| const std::string& label) |
| { |
| uint16_t word = (data[highIndex] << 8) | data[lowIndex]; |
| |
| logFile << label << "0x" << std::hex << std::setw(4) << std::setfill('0') |
| << word << '\n'; |
| return word; |
| } |
| |
| } // namespace max34451 |