|  | /** | 
|  | * Copyright © 2019 IBM Corporation | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  | #include "config.h" | 
|  |  | 
|  | #include "data_interface.hpp" | 
|  |  | 
|  | #include <fstream> | 
|  | #include <xyz/openbmc_project/State/OperatingSystem/Status/server.hpp> | 
|  |  | 
|  | namespace openpower | 
|  | { | 
|  | namespace pels | 
|  | { | 
|  |  | 
|  | namespace service_name | 
|  | { | 
|  | constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper"; | 
|  | } // namespace service_name | 
|  |  | 
|  | namespace object_path | 
|  | { | 
|  | constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper"; | 
|  | constexpr auto systemInv = "/xyz/openbmc_project/inventory/system"; | 
|  | constexpr auto hostState = "/xyz/openbmc_project/state/host0"; | 
|  | constexpr auto pldm = "/xyz/openbmc_project/pldm"; | 
|  | } // namespace object_path | 
|  |  | 
|  | namespace interface | 
|  | { | 
|  | constexpr auto dbusProperty = "org.freedesktop.DBus.Properties"; | 
|  | constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper"; | 
|  | constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset"; | 
|  | constexpr auto osStatus = "xyz.openbmc_project.State.OperatingSystem.Status"; | 
|  | constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester"; | 
|  | } // namespace interface | 
|  |  | 
|  | using namespace sdbusplus::xyz::openbmc_project::State::OperatingSystem::server; | 
|  |  | 
|  | DataInterface::DataInterface(sdbusplus::bus::bus& bus) : _bus(bus) | 
|  | { | 
|  | readMTMS(); | 
|  | readHostState(); | 
|  | readBMCFWVersion(); | 
|  | readServerFWVersion(); | 
|  | } | 
|  |  | 
|  | void DataInterface::readMTMS() | 
|  | { | 
|  | // If this runs when the inventory service isn't running, it will get the | 
|  | // value whenever it starts via the propertiesChanged callback. | 
|  | try | 
|  | { | 
|  | auto inventoryService = | 
|  | getService(object_path::systemInv, interface::invAsset); | 
|  |  | 
|  | if (!inventoryService.empty()) | 
|  | { | 
|  | auto properties = getAllProperties( | 
|  | inventoryService, object_path::systemInv, interface::invAsset); | 
|  |  | 
|  | _machineTypeModel = std::get<std::string>(properties["Model"]); | 
|  |  | 
|  | _machineSerialNumber = | 
|  | std::get<std::string>(properties["SerialNumber"]); | 
|  | } | 
|  | } | 
|  | catch (std::exception& e) | 
|  | { | 
|  | // Inventory must not be running at this moment. | 
|  | } | 
|  |  | 
|  | // Keep up to date by watching for the propertiesChanged signal. | 
|  | _sysInventoryPropMatch = std::make_unique<sdbusplus::bus::match_t>( | 
|  | _bus, | 
|  | sdbusplus::bus::match::rules::propertiesChanged(object_path::systemInv, | 
|  | interface::invAsset), | 
|  | std::bind(std::mem_fn(&DataInterface::sysAssetPropChanged), this, | 
|  | std::placeholders::_1)); | 
|  | } | 
|  |  | 
|  | void DataInterface::sysAssetPropChanged(sdbusplus::message::message& msg) | 
|  | { | 
|  | DBusInterface interface; | 
|  | DBusPropertyMap properties; | 
|  |  | 
|  | msg.read(interface, properties); | 
|  |  | 
|  | auto model = properties.find("Model"); | 
|  | if (model != properties.end()) | 
|  | { | 
|  | _machineTypeModel = std::get<std::string>(model->second); | 
|  | } | 
|  |  | 
|  | auto sn = properties.find("SerialNumber"); | 
|  | if (sn != properties.end()) | 
|  | { | 
|  | _machineSerialNumber = std::get<std::string>(sn->second); | 
|  | } | 
|  | } | 
|  |  | 
|  | DBusPropertyMap DataInterface::getAllProperties(const std::string& service, | 
|  | const std::string& objectPath, | 
|  | const std::string& interface) | 
|  | { | 
|  | DBusPropertyMap properties; | 
|  |  | 
|  | auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(), | 
|  | interface::dbusProperty, "GetAll"); | 
|  | method.append(interface); | 
|  | auto reply = _bus.call(method); | 
|  |  | 
|  | reply.read(properties); | 
|  |  | 
|  | return properties; | 
|  | } | 
|  |  | 
|  | void DataInterface::getProperty(const std::string& service, | 
|  | const std::string& objectPath, | 
|  | const std::string& interface, | 
|  | const std::string& property, DBusValue& value) | 
|  | { | 
|  |  | 
|  | auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(), | 
|  | interface::dbusProperty, "Get"); | 
|  | method.append(interface, property); | 
|  | auto reply = _bus.call(method); | 
|  |  | 
|  | reply.read(value); | 
|  | } | 
|  |  | 
|  | DBusService DataInterface::getService(const std::string& objectPath, | 
|  | const std::string& interface) const | 
|  | { | 
|  | auto method = _bus.new_method_call(service_name::objectMapper, | 
|  | object_path::objectMapper, | 
|  | interface::objectMapper, "GetObject"); | 
|  |  | 
|  | method.append(objectPath, std::vector<std::string>({interface})); | 
|  |  | 
|  | auto reply = _bus.call(method); | 
|  |  | 
|  | std::map<DBusService, DBusInterfaceList> response; | 
|  | reply.read(response); | 
|  |  | 
|  | if (!response.empty()) | 
|  | { | 
|  | return response.begin()->first; | 
|  | } | 
|  |  | 
|  | return std::string{}; | 
|  | } | 
|  |  | 
|  | void DataInterface::readHostState() | 
|  | { | 
|  | _hostUp = false; | 
|  |  | 
|  | try | 
|  | { | 
|  | auto service = getService(object_path::hostState, interface::osStatus); | 
|  | if (!service.empty()) | 
|  | { | 
|  | DBusValue value; | 
|  | getProperty(service, object_path::hostState, interface::osStatus, | 
|  | "OperatingSystemState", value); | 
|  |  | 
|  | auto status = | 
|  | Status::convertOSStatusFromString(std::get<std::string>(value)); | 
|  |  | 
|  | if ((status == Status::OSStatus::BootComplete) || | 
|  | (status == Status::OSStatus::Standby)) | 
|  | { | 
|  | _hostUp = true; | 
|  | } | 
|  | } | 
|  | } | 
|  | catch (std::exception& e) | 
|  | { | 
|  | // Not available yet. | 
|  | } | 
|  |  | 
|  | // Keep up to date by watching for the propertiesChanged signal. | 
|  | _osStateMatch = std::make_unique<sdbusplus::bus::match_t>( | 
|  | _bus, | 
|  | sdbusplus::bus::match::rules::propertiesChanged(object_path::hostState, | 
|  | interface::osStatus), | 
|  | std::bind(std::mem_fn(&DataInterface::osStatePropChanged), this, | 
|  | std::placeholders::_1)); | 
|  | } | 
|  |  | 
|  | void DataInterface::osStatePropChanged(sdbusplus::message::message& msg) | 
|  | { | 
|  | DBusInterface interface; | 
|  | DBusPropertyMap properties; | 
|  |  | 
|  | msg.read(interface, properties); | 
|  |  | 
|  | auto state = properties.find("OperatingSystemState"); | 
|  | if (state != properties.end()) | 
|  | { | 
|  | auto status = Status::convertOSStatusFromString( | 
|  | std::get<std::string>(state->second)); | 
|  |  | 
|  | bool newHostState = false; | 
|  | if ((status == Status::OSStatus::BootComplete) || | 
|  | (status == Status::OSStatus::Standby)) | 
|  | { | 
|  | newHostState = true; | 
|  | } | 
|  |  | 
|  | setHostState(newHostState); | 
|  | } | 
|  | } | 
|  |  | 
|  | uint8_t DataInterface::getPLDMInstanceID(uint8_t eid) const | 
|  | { | 
|  | return 0; | 
|  | // Don't use until PLDM switches to async D-Bus. | 
|  | #if 0 | 
|  | auto service = getService(object_path::pldm, interface::pldmRequester); | 
|  |  | 
|  | auto method = | 
|  | _bus.new_method_call(service.c_str(), object_path::pldm, | 
|  | interface::pldmRequester, "GetInstanceId"); | 
|  | method.append(eid); | 
|  | auto reply = _bus.call(method); | 
|  |  | 
|  | uint8_t instanceID = 0; | 
|  | reply.read(instanceID); | 
|  |  | 
|  | return instanceID; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | void DataInterface::readBMCFWVersion() | 
|  | { | 
|  | std::ifstream versionFile{BMC_VERSION_FILE}; | 
|  | std::string line; | 
|  | static const auto versionID = "VERSION="; | 
|  |  | 
|  | while (std::getline(versionFile, line)) | 
|  | { | 
|  | if (line.find(versionID) != std::string::npos) | 
|  | { | 
|  | auto pos = line.find_first_of('"') + 1; | 
|  | _bmcFWVersion = line.substr(pos, line.find_last_of('"') - pos); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void DataInterface::readServerFWVersion() | 
|  | { | 
|  | // Not available yet | 
|  | } | 
|  |  | 
|  | } // namespace pels | 
|  | } // namespace openpower |