129e9e385SMatthew Barth /**
229e9e385SMatthew Barth  * Copyright © 2020 IBM Corporation
329e9e385SMatthew Barth  *
429e9e385SMatthew Barth  * Licensed under the Apache License, Version 2.0 (the "License");
529e9e385SMatthew Barth  * you may not use this file except in compliance with the License.
629e9e385SMatthew Barth  * You may obtain a copy of the License at
729e9e385SMatthew Barth  *
829e9e385SMatthew Barth  *     http://www.apache.org/licenses/LICENSE-2.0
929e9e385SMatthew Barth  *
1029e9e385SMatthew Barth  * Unless required by applicable law or agreed to in writing, software
1129e9e385SMatthew Barth  * distributed under the License is distributed on an "AS IS" BASIS,
1229e9e385SMatthew Barth  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1329e9e385SMatthew Barth  * See the License for the specific language governing permissions and
1429e9e385SMatthew Barth  * limitations under the License.
1529e9e385SMatthew Barth  */
1629e9e385SMatthew Barth 
1729e9e385SMatthew Barth #include "manager.hpp"
1829e9e385SMatthew Barth 
19e0c6a2d9SShawn McCarney #include "chassis.hpp"
20e0c6a2d9SShawn McCarney #include "config_file_parser.hpp"
21e0c6a2d9SShawn McCarney #include "exception_utils.hpp"
22e0c6a2d9SShawn McCarney #include "rule.hpp"
23bbc7c583SMatthew Barth #include "utility.hpp"
24bbc7c583SMatthew Barth 
25415094c1SShawn McCarney #include <xyz/openbmc_project/Common/error.hpp>
26d9c8be57SShawn McCarney #include <xyz/openbmc_project/State/Chassis/server.hpp>
27415094c1SShawn McCarney 
28589c181aSShawn McCarney #include <algorithm>
29f2bcf1f9SMatthew Barth #include <chrono>
30e0c6a2d9SShawn McCarney #include <exception>
31589c181aSShawn McCarney #include <functional>
32589c181aSShawn McCarney #include <map>
338acaf547SShawn McCarney #include <thread>
34e0c6a2d9SShawn McCarney #include <tuple>
35e0c6a2d9SShawn McCarney #include <utility>
36250d0a98SMatthew Barth #include <variant>
37f2bcf1f9SMatthew Barth 
3884807b96SShawn McCarney namespace phosphor::power::regulators
3929e9e385SMatthew Barth {
4029e9e385SMatthew Barth 
41e0c6a2d9SShawn McCarney namespace fs = std::filesystem;
42e0c6a2d9SShawn McCarney 
43589c181aSShawn McCarney constexpr auto busName = "xyz.openbmc_project.Power.Regulators";
44589c181aSShawn McCarney constexpr auto managerObjPath = "/xyz/openbmc_project/power/regulators/manager";
45589c181aSShawn McCarney constexpr auto compatibleIntf =
46589c181aSShawn McCarney     "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
47589c181aSShawn McCarney constexpr auto compatibleNamesProp = "Names";
48d9c8be57SShawn McCarney constexpr auto chassisStatePath = "/xyz/openbmc_project/state/chassis0";
49d9c8be57SShawn McCarney constexpr auto chassisStateIntf = "xyz.openbmc_project.State.Chassis";
50d9c8be57SShawn McCarney constexpr auto chassisStateProp = "CurrentPowerState";
518acaf547SShawn McCarney constexpr std::chrono::minutes maxTimeToWaitForCompatTypes{5};
52589c181aSShawn McCarney 
53d9c8be57SShawn McCarney using PowerState =
54d9c8be57SShawn McCarney     sdbusplus::xyz::openbmc_project::State::server::Chassis::PowerState;
55d9c8be57SShawn McCarney 
56589c181aSShawn McCarney /**
57589c181aSShawn McCarney  * Default configuration file name.  This is used when the system does not
58589c181aSShawn McCarney  * implement the D-Bus compatible interface.
59589c181aSShawn McCarney  */
60589c181aSShawn McCarney constexpr auto defaultConfigFileName = "config.json";
61589c181aSShawn McCarney 
62e0c6a2d9SShawn McCarney /**
63e0c6a2d9SShawn McCarney  * Standard configuration file directory.  This directory is part of the
64e0c6a2d9SShawn McCarney  * firmware install image.  It contains the standard version of the config file.
65e0c6a2d9SShawn McCarney  */
66e0c6a2d9SShawn McCarney const fs::path standardConfigFileDir{"/usr/share/phosphor-regulators"};
67e0c6a2d9SShawn McCarney 
68e0c6a2d9SShawn McCarney /**
69e0c6a2d9SShawn McCarney  * Test configuration file directory.  This directory can contain a test version
70e0c6a2d9SShawn McCarney  * of the config file.  The test version will override the standard version.
71e0c6a2d9SShawn McCarney  */
72e0c6a2d9SShawn McCarney const fs::path testConfigFileDir{"/etc/phosphor-regulators"};
73e0c6a2d9SShawn McCarney 
74f2bcf1f9SMatthew Barth Manager::Manager(sdbusplus::bus::bus& bus, const sdeventplus::Event& event) :
75*d1307294SZev Weiss     ManagerObject{bus, managerObjPath}, bus{bus}, eventLoop{event},
76*d1307294SZev Weiss     services{bus}, phaseFaultTimer{event,
77*d1307294SZev Weiss                                    std::bind(&Manager::phaseFaultTimerExpired,
78*d1307294SZev Weiss                                              this)},
79c8cbeac2SShawn McCarney     sensorTimer{event, std::bind(&Manager::sensorTimerExpired, this)}
8029e9e385SMatthew Barth {
81589c181aSShawn McCarney     // Subscribe to D-Bus interfacesAdded signal from Entity Manager.  This
82589c181aSShawn McCarney     // notifies us if the compatible interface becomes available later.
83589c181aSShawn McCarney     std::string matchStr = sdbusplus::bus::match::rules::interfacesAdded() +
84589c181aSShawn McCarney                            sdbusplus::bus::match::rules::sender(
85589c181aSShawn McCarney                                "xyz.openbmc_project.EntityManager");
86a61c1aa0SPatrick Williams     std::unique_ptr<sdbusplus::bus::match_t> matchPtr =
87a61c1aa0SPatrick Williams         std::make_unique<sdbusplus::bus::match_t>(
88589c181aSShawn McCarney             bus, matchStr,
89589c181aSShawn McCarney             std::bind(&Manager::interfacesAddedHandler, this,
90250d0a98SMatthew Barth                       std::placeholders::_1));
91250d0a98SMatthew Barth     signals.emplace_back(std::move(matchPtr));
92250d0a98SMatthew Barth 
93589c181aSShawn McCarney     // Try to find compatible system types using D-Bus compatible interface.
94589c181aSShawn McCarney     // Note that it might not be supported on this system, or the service that
95589c181aSShawn McCarney     // provides the interface might not be running yet.
96589c181aSShawn McCarney     findCompatibleSystemTypes();
9784807b96SShawn McCarney 
98589c181aSShawn McCarney     // Try to find and load the JSON configuration file
99e0c6a2d9SShawn McCarney     loadConfigFile();
10029e9e385SMatthew Barth 
101d9c8be57SShawn McCarney     // Obtain D-Bus service name
10229e9e385SMatthew Barth     bus.request_name(busName);
103d9c8be57SShawn McCarney 
104d9c8be57SShawn McCarney     // If system is already powered on, enable monitoring
105d9c8be57SShawn McCarney     if (isSystemPoweredOn())
106d9c8be57SShawn McCarney     {
107d9c8be57SShawn McCarney         monitor(true);
108d9c8be57SShawn McCarney     }
10929e9e385SMatthew Barth }
11029e9e385SMatthew Barth 
11129e9e385SMatthew Barth void Manager::configure()
11229e9e385SMatthew Barth {
1139bd94d36SShawn McCarney     // Clear any cached data or error history related to hardware devices
1149bd94d36SShawn McCarney     clearHardwareData();
1159bd94d36SShawn McCarney 
1168acaf547SShawn McCarney     // Wait until the config file has been loaded or hit max wait time
1178acaf547SShawn McCarney     waitUntilConfigFileLoaded();
1188acaf547SShawn McCarney 
1198acaf547SShawn McCarney     // Verify config file has been loaded and System object is valid
1208acaf547SShawn McCarney     if (isConfigFileLoaded())
1216345c6c5SShawn McCarney     {
1226345c6c5SShawn McCarney         // Configure the regulator devices in the system
12323243f84SBob King         system->configure(services);
1246345c6c5SShawn McCarney     }
1256345c6c5SShawn McCarney     else
1266345c6c5SShawn McCarney     {
127415094c1SShawn McCarney         // Write error message to journal
128b464c8bdSShawn McCarney         services.getJournal().logError("Unable to configure regulator devices: "
129b464c8bdSShawn McCarney                                        "Configuration file not loaded");
1306345c6c5SShawn McCarney 
131415094c1SShawn McCarney         // Log critical error since regulators could not be configured.  Could
132415094c1SShawn McCarney         // cause hardware damage if default regulator settings are very wrong.
133415094c1SShawn McCarney         services.getErrorLogging().logConfigFileError(Entry::Level::Critical,
134415094c1SShawn McCarney                                                       services.getJournal());
135415094c1SShawn McCarney 
136415094c1SShawn McCarney         // Throw InternalFailure to propogate error status to D-Bus client
137415094c1SShawn McCarney         throw sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure{};
138415094c1SShawn McCarney     }
13929e9e385SMatthew Barth }
14029e9e385SMatthew Barth 
141589c181aSShawn McCarney void Manager::interfacesAddedHandler(sdbusplus::message::message& msg)
142589c181aSShawn McCarney {
143589c181aSShawn McCarney     // Verify message is valid
144589c181aSShawn McCarney     if (!msg)
145589c181aSShawn McCarney     {
146589c181aSShawn McCarney         return;
147589c181aSShawn McCarney     }
148589c181aSShawn McCarney 
149589c181aSShawn McCarney     try
150589c181aSShawn McCarney     {
151589c181aSShawn McCarney         // Read object path for object that was created or had interface added
152589c181aSShawn McCarney         sdbusplus::message::object_path objPath;
153589c181aSShawn McCarney         msg.read(objPath);
154589c181aSShawn McCarney 
155589c181aSShawn McCarney         // Read the dictionary whose keys are interface names and whose values
156589c181aSShawn McCarney         // are dictionaries containing the interface property names and values
157589c181aSShawn McCarney         std::map<std::string,
158589c181aSShawn McCarney                  std::map<std::string, std::variant<std::vector<std::string>>>>
159589c181aSShawn McCarney             intfProp;
160589c181aSShawn McCarney         msg.read(intfProp);
161589c181aSShawn McCarney 
162589c181aSShawn McCarney         // Find the compatible interface, if present
163589c181aSShawn McCarney         auto itIntf = intfProp.find(compatibleIntf);
164589c181aSShawn McCarney         if (itIntf != intfProp.cend())
165589c181aSShawn McCarney         {
166589c181aSShawn McCarney             // Find the Names property of the compatible interface, if present
167589c181aSShawn McCarney             auto itProp = itIntf->second.find(compatibleNamesProp);
168589c181aSShawn McCarney             if (itProp != itIntf->second.cend())
169589c181aSShawn McCarney             {
170589c181aSShawn McCarney                 // Get value of Names property
171589c181aSShawn McCarney                 auto propValue = std::get<0>(itProp->second);
172589c181aSShawn McCarney                 if (!propValue.empty())
173589c181aSShawn McCarney                 {
174589c181aSShawn McCarney                     // Store list of compatible system types
175589c181aSShawn McCarney                     compatibleSystemTypes = propValue;
176589c181aSShawn McCarney 
177589c181aSShawn McCarney                     // Find and load JSON config file based on system types
178589c181aSShawn McCarney                     loadConfigFile();
179589c181aSShawn McCarney                 }
180589c181aSShawn McCarney             }
181589c181aSShawn McCarney         }
182589c181aSShawn McCarney     }
183589c181aSShawn McCarney     catch (const std::exception&)
184589c181aSShawn McCarney     {
185589c181aSShawn McCarney         // Error trying to read interfacesAdded message.  One possible cause
186589c181aSShawn McCarney         // could be a property whose value is not a std::vector<std::string>.
187589c181aSShawn McCarney     }
188589c181aSShawn McCarney }
189589c181aSShawn McCarney 
1905b19ea51SShawn McCarney void Manager::monitor(bool enable)
19129e9e385SMatthew Barth {
192d9c8be57SShawn McCarney     // Check whether already in the requested monitoring state
193d9c8be57SShawn McCarney     if (enable == isMonitoringEnabled)
19429e9e385SMatthew Barth     {
195d9c8be57SShawn McCarney         return;
196d9c8be57SShawn McCarney     }
197d9c8be57SShawn McCarney 
198d9c8be57SShawn McCarney     isMonitoringEnabled = enable;
199d9c8be57SShawn McCarney     if (isMonitoringEnabled)
200d9c8be57SShawn McCarney     {
201d9c8be57SShawn McCarney         services.getJournal().logDebug("Monitoring enabled");
202d9c8be57SShawn McCarney 
203c8cbeac2SShawn McCarney         // Restart phase fault detection timer with repeating 15 second interval
204c8cbeac2SShawn McCarney         phaseFaultTimer.restart(std::chrono::seconds(15));
205c8cbeac2SShawn McCarney 
206c8cbeac2SShawn McCarney         // Restart sensor monitoring timer with repeating 1 second interval
207c8cbeac2SShawn McCarney         sensorTimer.restart(std::chrono::seconds(1));
208d9c8be57SShawn McCarney 
209d9c8be57SShawn McCarney         // Enable sensors service; put all sensors in an active state
210d9c8be57SShawn McCarney         services.getSensors().enable();
21129e9e385SMatthew Barth     }
21229e9e385SMatthew Barth     else
21329e9e385SMatthew Barth     {
214d9c8be57SShawn McCarney         services.getJournal().logDebug("Monitoring disabled");
215d9c8be57SShawn McCarney 
216c8cbeac2SShawn McCarney         // Disable timers
217c8cbeac2SShawn McCarney         phaseFaultTimer.setEnabled(false);
218c8cbeac2SShawn McCarney         sensorTimer.setEnabled(false);
219d9c8be57SShawn McCarney 
220d9c8be57SShawn McCarney         // Disable sensors service; put all sensors in an inactive state
221d9c8be57SShawn McCarney         services.getSensors().disable();
2225b19ea51SShawn McCarney 
2238acaf547SShawn McCarney         // Verify config file has been loaded and System object is valid
2248acaf547SShawn McCarney         if (isConfigFileLoaded())
2255b19ea51SShawn McCarney         {
2265b19ea51SShawn McCarney             // Close the regulator devices in the system.  Monitoring is
2275b19ea51SShawn McCarney             // normally disabled because the system is being powered off.  The
2285b19ea51SShawn McCarney             // devices should be closed in case hardware is removed or replaced
2299bd94d36SShawn McCarney             // while the system is powered off.
230d692d6dfSBob King             system->closeDevices(services);
2315b19ea51SShawn McCarney         }
2325b19ea51SShawn McCarney     }
23329e9e385SMatthew Barth }
23429e9e385SMatthew Barth 
235c8cbeac2SShawn McCarney void Manager::phaseFaultTimerExpired()
236589c181aSShawn McCarney {
237c8cbeac2SShawn McCarney     // Verify config file has been loaded and System object is valid
238c8cbeac2SShawn McCarney     if (isConfigFileLoaded())
239c8cbeac2SShawn McCarney     {
240c8cbeac2SShawn McCarney         // Detect redundant phase faults in regulator devices in the system
241c8cbeac2SShawn McCarney         system->detectPhaseFaults(services);
242c8cbeac2SShawn McCarney     }
243589c181aSShawn McCarney }
244589c181aSShawn McCarney 
245c8cbeac2SShawn McCarney void Manager::sensorTimerExpired()
246f2bcf1f9SMatthew Barth {
247d9c8be57SShawn McCarney     // Notify sensors service that a sensor monitoring cycle is starting
248d9c8be57SShawn McCarney     services.getSensors().startCycle();
249d9c8be57SShawn McCarney 
250d9c8be57SShawn McCarney     // Verify config file has been loaded and System object is valid
251d9c8be57SShawn McCarney     if (isConfigFileLoaded())
252d9c8be57SShawn McCarney     {
253d9c8be57SShawn McCarney         // Monitor sensors for the voltage rails in the system
254d9c8be57SShawn McCarney         system->monitorSensors(services);
255d9c8be57SShawn McCarney     }
256d9c8be57SShawn McCarney 
257d9c8be57SShawn McCarney     // Notify sensors service that current sensor monitoring cycle has ended
258d9c8be57SShawn McCarney     services.getSensors().endCycle();
259f2bcf1f9SMatthew Barth }
260f2bcf1f9SMatthew Barth 
261c8cbeac2SShawn McCarney void Manager::sighupHandler(sdeventplus::source::Signal& /*sigSrc*/,
262c8cbeac2SShawn McCarney                             const struct signalfd_siginfo* /*sigInfo*/)
263c8cbeac2SShawn McCarney {
264c8cbeac2SShawn McCarney     // Reload the JSON configuration file
265c8cbeac2SShawn McCarney     loadConfigFile();
266c8cbeac2SShawn McCarney }
267c8cbeac2SShawn McCarney 
2689bd94d36SShawn McCarney void Manager::clearHardwareData()
2699bd94d36SShawn McCarney {
2704e0402cbSShawn McCarney     // Clear any cached hardware presence data and VPD values
2719bd94d36SShawn McCarney     services.getPresenceService().clearCache();
2724e0402cbSShawn McCarney     services.getVPD().clearCache();
2739bd94d36SShawn McCarney 
2748acaf547SShawn McCarney     // Verify config file has been loaded and System object is valid
2758acaf547SShawn McCarney     if (isConfigFileLoaded())
2769bd94d36SShawn McCarney     {
2779bd94d36SShawn McCarney         // Clear any cached hardware data in the System object
2789bd94d36SShawn McCarney         system->clearCache();
2799bd94d36SShawn McCarney 
280ce540f3cSShawn McCarney         // Clear error history related to hardware devices in the System object
281ce540f3cSShawn McCarney         system->clearErrorHistory();
282ce540f3cSShawn McCarney     }
2839bd94d36SShawn McCarney }
2849bd94d36SShawn McCarney 
285589c181aSShawn McCarney void Manager::findCompatibleSystemTypes()
2867cbc5536SMatthew Barth {
287bbc7c583SMatthew Barth     using namespace phosphor::power::util;
288bbc7c583SMatthew Barth 
289bbc7c583SMatthew Barth     try
290bbc7c583SMatthew Barth     {
291589c181aSShawn McCarney         // Query object mapper for object paths that implement the compatible
292589c181aSShawn McCarney         // interface.  Returns a map of object paths to a map of services names
293589c181aSShawn McCarney         // to their interfaces.
294589c181aSShawn McCarney         DbusSubtree subTree = getSubTree(bus, "/xyz/openbmc_project/inventory",
295589c181aSShawn McCarney                                          compatibleIntf, 0);
296589c181aSShawn McCarney 
297589c181aSShawn McCarney         // Get the first object path
298589c181aSShawn McCarney         auto objectIt = subTree.cbegin();
299589c181aSShawn McCarney         if (objectIt != subTree.cend())
300589c181aSShawn McCarney         {
301589c181aSShawn McCarney             std::string objPath = objectIt->first;
302589c181aSShawn McCarney 
303589c181aSShawn McCarney             // Get the first service name
304589c181aSShawn McCarney             auto serviceIt = objectIt->second.cbegin();
305589c181aSShawn McCarney             if (serviceIt != objectIt->second.cend())
306589c181aSShawn McCarney             {
307589c181aSShawn McCarney                 std::string service = serviceIt->first;
308bbc7c583SMatthew Barth                 if (!service.empty())
309bbc7c583SMatthew Barth                 {
310589c181aSShawn McCarney                     // Get compatible system types property value
311589c181aSShawn McCarney                     getProperty(compatibleIntf, compatibleNamesProp, objPath,
312589c181aSShawn McCarney                                 service, bus, compatibleSystemTypes);
313bbc7c583SMatthew Barth                 }
314bbc7c583SMatthew Barth             }
315589c181aSShawn McCarney         }
316589c181aSShawn McCarney     }
317589c181aSShawn McCarney     catch (const std::exception&)
318bbc7c583SMatthew Barth     {
319589c181aSShawn McCarney         // Compatible system types information is not available.  The current
320589c181aSShawn McCarney         // system might not support the interface, or the service that
321589c181aSShawn McCarney         // implements the interface might not be running yet.
322bbc7c583SMatthew Barth     }
323bbc7c583SMatthew Barth }
324bbc7c583SMatthew Barth 
325e0c6a2d9SShawn McCarney fs::path Manager::findConfigFile()
326e0c6a2d9SShawn McCarney {
327589c181aSShawn McCarney     // Build list of possible base file names
328589c181aSShawn McCarney     std::vector<std::string> fileNames{};
329589c181aSShawn McCarney 
330589c181aSShawn McCarney     // Add possible file names based on compatible system types (if any)
331589c181aSShawn McCarney     for (const std::string& systemType : compatibleSystemTypes)
332589c181aSShawn McCarney     {
333589c181aSShawn McCarney         // Replace all spaces and commas in system type name with underscores
334589c181aSShawn McCarney         std::string fileName{systemType};
335589c181aSShawn McCarney         std::replace(fileName.begin(), fileName.end(), ' ', '_');
336589c181aSShawn McCarney         std::replace(fileName.begin(), fileName.end(), ',', '_');
337589c181aSShawn McCarney 
338589c181aSShawn McCarney         // Append .json suffix and add to list
339589c181aSShawn McCarney         fileName.append(".json");
340589c181aSShawn McCarney         fileNames.emplace_back(fileName);
341589c181aSShawn McCarney     }
342589c181aSShawn McCarney 
343589c181aSShawn McCarney     // Add default file name for systems that don't use compatible interface
344589c181aSShawn McCarney     fileNames.emplace_back(defaultConfigFileName);
345589c181aSShawn McCarney 
346589c181aSShawn McCarney     // Look for a config file with one of the possible base names
347589c181aSShawn McCarney     for (const std::string& fileName : fileNames)
348589c181aSShawn McCarney     {
349589c181aSShawn McCarney         // Check if file exists in test directory
350e0c6a2d9SShawn McCarney         fs::path pathName{testConfigFileDir / fileName};
351589c181aSShawn McCarney         if (fs::exists(pathName))
352e0c6a2d9SShawn McCarney         {
353589c181aSShawn McCarney             return pathName;
354589c181aSShawn McCarney         }
355589c181aSShawn McCarney 
356589c181aSShawn McCarney         // Check if file exists in standard directory
357e0c6a2d9SShawn McCarney         pathName = standardConfigFileDir / fileName;
358589c181aSShawn McCarney         if (fs::exists(pathName))
359e0c6a2d9SShawn McCarney         {
360589c181aSShawn McCarney             return pathName;
361e0c6a2d9SShawn McCarney         }
362e0c6a2d9SShawn McCarney     }
363e0c6a2d9SShawn McCarney 
364589c181aSShawn McCarney     // No config file found; return empty path
365589c181aSShawn McCarney     return fs::path{};
366e0c6a2d9SShawn McCarney }
367e0c6a2d9SShawn McCarney 
368d9c8be57SShawn McCarney bool Manager::isSystemPoweredOn()
369d9c8be57SShawn McCarney {
370d9c8be57SShawn McCarney     bool isOn{false};
371d9c8be57SShawn McCarney 
372d9c8be57SShawn McCarney     try
373d9c8be57SShawn McCarney     {
374d9c8be57SShawn McCarney         // Get D-Bus property that contains the current power state for
375d9c8be57SShawn McCarney         // chassis0, which represents the entire system (all chassis)
376d9c8be57SShawn McCarney         using namespace phosphor::power::util;
377d9c8be57SShawn McCarney         auto service = getService(chassisStatePath, chassisStateIntf, bus);
378d9c8be57SShawn McCarney         if (!service.empty())
379d9c8be57SShawn McCarney         {
380d9c8be57SShawn McCarney             PowerState currentPowerState;
381d9c8be57SShawn McCarney             getProperty(chassisStateIntf, chassisStateProp, chassisStatePath,
382d9c8be57SShawn McCarney                         service, bus, currentPowerState);
383d9c8be57SShawn McCarney             if (currentPowerState == PowerState::On)
384d9c8be57SShawn McCarney             {
385d9c8be57SShawn McCarney                 isOn = true;
386d9c8be57SShawn McCarney             }
387d9c8be57SShawn McCarney         }
388d9c8be57SShawn McCarney     }
389d9c8be57SShawn McCarney     catch (const std::exception& e)
390d9c8be57SShawn McCarney     {
391d9c8be57SShawn McCarney         // Current power state might not be available yet.  The regulators
392d9c8be57SShawn McCarney         // application can start before the power state is published on D-Bus.
393d9c8be57SShawn McCarney     }
394d9c8be57SShawn McCarney 
395d9c8be57SShawn McCarney     return isOn;
396d9c8be57SShawn McCarney }
397d9c8be57SShawn McCarney 
398e0c6a2d9SShawn McCarney void Manager::loadConfigFile()
399e0c6a2d9SShawn McCarney {
400e0c6a2d9SShawn McCarney     try
401e0c6a2d9SShawn McCarney     {
402e0c6a2d9SShawn McCarney         // Find the absolute path to the config file
403e0c6a2d9SShawn McCarney         fs::path pathName = findConfigFile();
404589c181aSShawn McCarney         if (!pathName.empty())
405589c181aSShawn McCarney         {
406e0c6a2d9SShawn McCarney             // Log info message in journal; config file path is important
407b464c8bdSShawn McCarney             services.getJournal().logInfo("Loading configuration file " +
408b464c8bdSShawn McCarney                                           pathName.string());
409e0c6a2d9SShawn McCarney 
410e0c6a2d9SShawn McCarney             // Parse the config file
411e0c6a2d9SShawn McCarney             std::vector<std::unique_ptr<Rule>> rules{};
412e0c6a2d9SShawn McCarney             std::vector<std::unique_ptr<Chassis>> chassis{};
413e0c6a2d9SShawn McCarney             std::tie(rules, chassis) = config_file_parser::parse(pathName);
414e0c6a2d9SShawn McCarney 
415589c181aSShawn McCarney             // Store config file information in a new System object.  The old
416589c181aSShawn McCarney             // System object, if any, is automatically deleted.
417589c181aSShawn McCarney             system =
418589c181aSShawn McCarney                 std::make_unique<System>(std::move(rules), std::move(chassis));
419589c181aSShawn McCarney         }
420e0c6a2d9SShawn McCarney     }
421e0c6a2d9SShawn McCarney     catch (const std::exception& e)
422e0c6a2d9SShawn McCarney     {
423e0c6a2d9SShawn McCarney         // Log error messages in journal
424b464c8bdSShawn McCarney         services.getJournal().logError(exception_utils::getMessages(e));
425b464c8bdSShawn McCarney         services.getJournal().logError("Unable to load configuration file");
426e0c6a2d9SShawn McCarney 
427415094c1SShawn McCarney         // Log error
428415094c1SShawn McCarney         services.getErrorLogging().logConfigFileError(Entry::Level::Error,
429415094c1SShawn McCarney                                                       services.getJournal());
430e0c6a2d9SShawn McCarney     }
431e0c6a2d9SShawn McCarney }
432e0c6a2d9SShawn McCarney 
4338acaf547SShawn McCarney void Manager::waitUntilConfigFileLoaded()
4348acaf547SShawn McCarney {
4358acaf547SShawn McCarney     // If config file not loaded and list of compatible system types is empty
4368acaf547SShawn McCarney     if (!isConfigFileLoaded() && compatibleSystemTypes.empty())
4378acaf547SShawn McCarney     {
4388acaf547SShawn McCarney         // Loop until compatible system types found or waited max amount of time
4398acaf547SShawn McCarney         auto start = std::chrono::system_clock::now();
4408acaf547SShawn McCarney         std::chrono::system_clock::duration timeWaited{0};
4418acaf547SShawn McCarney         while (compatibleSystemTypes.empty() &&
4428acaf547SShawn McCarney                (timeWaited <= maxTimeToWaitForCompatTypes))
4438acaf547SShawn McCarney         {
4448acaf547SShawn McCarney             // Try to find list of compatible system types
4458acaf547SShawn McCarney             findCompatibleSystemTypes();
4468acaf547SShawn McCarney             if (!compatibleSystemTypes.empty())
4478acaf547SShawn McCarney             {
4488acaf547SShawn McCarney                 // Compatible system types found; try to load config file
4498acaf547SShawn McCarney                 loadConfigFile();
4508acaf547SShawn McCarney             }
4518acaf547SShawn McCarney             else
4528acaf547SShawn McCarney             {
4538acaf547SShawn McCarney                 // Sleep 5 seconds
4548acaf547SShawn McCarney                 using namespace std::chrono_literals;
4558acaf547SShawn McCarney                 std::this_thread::sleep_for(5s);
4568acaf547SShawn McCarney             }
4578acaf547SShawn McCarney             timeWaited = std::chrono::system_clock::now() - start;
4588acaf547SShawn McCarney         }
4598acaf547SShawn McCarney     }
4608acaf547SShawn McCarney }
4618acaf547SShawn McCarney 
46284807b96SShawn McCarney } // namespace phosphor::power::regulators
463