blob: cbcdec41a48cee3304fec1749ceb9f7c456ba6e4 [file] [log] [blame]
Matthew Barth29e9e382020-01-23 13:40:49 -06001/**
2 * Copyright © 2020 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "manager.hpp"
18
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -050019#include "chassis.hpp"
20#include "config_file_parser.hpp"
21#include "exception_utils.hpp"
22#include "journal.hpp"
23#include "rule.hpp"
Matthew Barthbbc7c582020-02-03 15:55:15 -060024#include "utility.hpp"
25
Matthew Barth29e9e382020-01-23 13:40:49 -060026#include <sdbusplus/bus.hpp>
27
Matthew Barthf2bcf1f2020-01-29 14:42:47 -060028#include <chrono>
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -050029#include <exception>
30#include <stdexcept>
31#include <tuple>
32#include <utility>
Matthew Barth250d0a92020-02-28 13:04:24 -060033#include <variant>
Matthew Barthf2bcf1f2020-01-29 14:42:47 -060034
Shawn McCarney84807b92020-04-30 18:40:03 -050035namespace phosphor::power::regulators
Matthew Barth29e9e382020-01-23 13:40:49 -060036{
37
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -050038namespace fs = std::filesystem;
39
40/**
41 * Standard configuration file directory. This directory is part of the
42 * firmware install image. It contains the standard version of the config file.
43 */
44const fs::path standardConfigFileDir{"/usr/share/phosphor-regulators"};
45
46/**
47 * Test configuration file directory. This directory can contain a test version
48 * of the config file. The test version will override the standard version.
49 */
50const fs::path testConfigFileDir{"/etc/phosphor-regulators"};
51
Matthew Barthf2bcf1f2020-01-29 14:42:47 -060052Manager::Manager(sdbusplus::bus::bus& bus, const sdeventplus::Event& event) :
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -050053 ManagerObject{bus, objPath, true}, bus{bus}, eventLoop{event}
Matthew Barth29e9e382020-01-23 13:40:49 -060054{
Shawn McCarney84807b92020-04-30 18:40:03 -050055 /* Temporarily comment out until D-Bus interface is defined and available.
56 // Subscribe to interfacesAdded signal for filename property
57 std::unique_ptr<sdbusplus::server::match::match> matchPtr =
58 std::make_unique<sdbusplus::server::match::match>(
59 bus,
60 sdbusplus::bus::match::rules::interfacesAdded(sysDbusObj).c_str(),
61 std::bind(std::mem_fn(&Manager::signalHandler), this,
62 std::placeholders::_1));
63 signals.emplace_back(std::move(matchPtr));
Matthew Barth250d0a92020-02-28 13:04:24 -060064
Shawn McCarney84807b92020-04-30 18:40:03 -050065 // Attempt to get the filename property from dbus
66 setFileName(getFileNameDbus());
67 */
68
69 // Temporarily hard-code JSON config file name to first system that will use
70 // this application. Remove this when D-Bus interface is available.
71 fileName = "ibm_rainier.json";
Matthew Barthbbc7c582020-02-03 15:55:15 -060072
Matthew Barthbbc7c582020-02-03 15:55:15 -060073 if (!fileName.empty())
74 {
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -050075 loadConfigFile();
Matthew Barthbbc7c582020-02-03 15:55:15 -060076 }
Matthew Barth29e9e382020-01-23 13:40:49 -060077
78 // Obtain dbus service name
79 bus.request_name(busName);
80}
81
82void Manager::configure()
83{
Shawn McCarney6345c6c2020-05-04 10:35:05 -050084 // Verify System object exists; this means config file has been loaded
85 if (system)
86 {
87 // Configure the regulator devices in the system
88 system->configure();
89 }
90 else
91 {
92 journal::logErr("Unable to configure regulator devices: Configuration "
93 "file not loaded");
94 // TODO: Log error
95 }
96
Matthew Barth29e9e382020-01-23 13:40:49 -060097 // TODO Configuration errors that should halt poweron,
98 // throw InternalFailure exception (or similar) to
99 // fail the call(busctl) to this method
100}
101
Shawn McCarney6345c6c2020-05-04 10:35:05 -0500102void Manager::monitor(bool /*enable*/)
Matthew Barth29e9e382020-01-23 13:40:49 -0600103{
Shawn McCarney6345c6c2020-05-04 10:35:05 -0500104 /* Temporarily comment out until monitoring is supported.
Matthew Barth29e9e382020-01-23 13:40:49 -0600105 if (enable)
106 {
Matthew Barthf2bcf1f2020-01-29 14:42:47 -0600107 Timer timer(eventLoop, std::bind(&Manager::timerExpired, this));
108 // Set timer as a repeating 1sec timer
109 timer.restart(std::chrono::milliseconds(1000));
110 timers.emplace_back(std::move(timer));
Matthew Barth29e9e382020-01-23 13:40:49 -0600111 }
112 else
113 {
Matthew Barthf2bcf1f2020-01-29 14:42:47 -0600114 // Delete all timers to disable monitoring
115 timers.clear();
Matthew Barth29e9e382020-01-23 13:40:49 -0600116 }
Shawn McCarney6345c6c2020-05-04 10:35:05 -0500117 */
Matthew Barth29e9e382020-01-23 13:40:49 -0600118}
119
Matthew Barthf2bcf1f2020-01-29 14:42:47 -0600120void Manager::timerExpired()
121{
122 // TODO Analyze, refresh sensor status, and
123 // collect/update telemetry for each regulator
124}
125
Matthew Barth7cbc5532020-01-29 15:13:13 -0600126void Manager::sighupHandler(sdeventplus::source::Signal& /*sigSrc*/,
127 const struct signalfd_siginfo* /*sigInfo*/)
128{
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -0500129 if (!fileName.empty())
130 {
131 loadConfigFile();
132 }
Matthew Barth7cbc5532020-01-29 15:13:13 -0600133}
134
Matthew Barth250d0a92020-02-28 13:04:24 -0600135void Manager::signalHandler(sdbusplus::message::message& msg)
136{
137 if (msg)
138 {
139 sdbusplus::message::object_path op;
140 msg.read(op);
141 if (static_cast<const std::string&>(op) != sysDbusPath)
142 {
143 // Object path does not match the path
144 return;
145 }
146
147 // An interfacesAdded signal returns a dictionary of interface
148 // names to a dictionary of properties and their values
149 // https://dbus.freedesktop.org/doc/dbus-specification.html
150 std::map<std::string, std::map<std::string, std::variant<std::string>>>
151 intfProp;
152 msg.read(intfProp);
153 auto itIntf = intfProp.find(sysDbusIntf);
154 if (itIntf == intfProp.cend())
155 {
156 // Interface not found on the path
157 return;
158 }
159 auto itProp = itIntf->second.find(sysDbusProp);
160 if (itProp == itIntf->second.cend())
161 {
162 // Property not found on the interface
163 return;
164 }
165 // Set fileName and call parse json function
166 setFileName(std::get<std::string>(itProp->second));
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -0500167 if (!fileName.empty())
168 {
169 loadConfigFile();
170 }
Matthew Barth250d0a92020-02-28 13:04:24 -0600171 }
172}
173
Matthew Barthbbc7c582020-02-03 15:55:15 -0600174const std::string Manager::getFileNameDbus()
175{
176 std::string fileName = "";
177 using namespace phosphor::power::util;
178
179 try
180 {
181 // Do not log an error when service or property are not found
182 auto service = getService(sysDbusPath, sysDbusIntf, bus, false);
183 if (!service.empty())
184 {
185 getProperty(sysDbusIntf, sysDbusProp, sysDbusPath, service, bus,
186 fileName);
187 }
188 }
189 catch (const sdbusplus::exception::SdBusError&)
190 {
191 // File name property not available on dbus
192 fileName = "";
193 }
194
195 return fileName;
196}
197
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -0500198fs::path Manager::findConfigFile()
199{
200 // First look in the test directory
201 fs::path pathName{testConfigFileDir / fileName};
202 if (!fs::exists(pathName))
203 {
204 // Look in the standard directory
205 pathName = standardConfigFileDir / fileName;
206 if (!fs::exists(pathName))
207 {
208 throw std::runtime_error{"Configuration file does not exist: " +
209 pathName.string()};
210 }
211 }
212
213 return pathName;
214}
215
216void Manager::loadConfigFile()
217{
218 try
219 {
220 // Find the absolute path to the config file
221 fs::path pathName = findConfigFile();
222
223 // Log info message in journal; config file path is important
224 journal::logInfo("Loading configuration file " + pathName.string());
225
226 // Parse the config file
227 std::vector<std::unique_ptr<Rule>> rules{};
228 std::vector<std::unique_ptr<Chassis>> chassis{};
229 std::tie(rules, chassis) = config_file_parser::parse(pathName);
230
231 // Store config file information in a new System object. The old System
232 // object, if any, is automatically deleted.
233 system = std::make_unique<System>(std::move(rules), std::move(chassis));
234 }
235 catch (const std::exception& e)
236 {
237 // Log error messages in journal
238 exception_utils::log(e);
239 journal::logErr("Unable to load configuration file");
240
241 // TODO: Create error log entry
242 }
243}
244
Shawn McCarney84807b92020-04-30 18:40:03 -0500245} // namespace phosphor::power::regulators