blob: 10b9de987bb058e64d8c8b0f1c5b6aee521e3ff0 [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 McCarney5b19ea52020-06-02 18:52:56 -0500102void Manager::monitor(bool enable)
Matthew Barth29e9e382020-01-23 13:40:49 -0600103{
104 if (enable)
105 {
Shawn McCarney5b19ea52020-06-02 18:52:56 -0500106 /* Temporarily comment out until monitoring is supported.
107 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));
111 */
Matthew Barth29e9e382020-01-23 13:40:49 -0600112 }
113 else
114 {
Shawn McCarney5b19ea52020-06-02 18:52:56 -0500115 /* Temporarily comment out until monitoring is supported.
116 // Delete all timers to disable monitoring
117 timers.clear();
118 */
119
120 // Verify System object exists; this means config file has been loaded
121 if (system)
122 {
123 // Close the regulator devices in the system. Monitoring is
124 // normally disabled because the system is being powered off. The
125 // devices should be closed in case hardware is removed or replaced
126 // while the system is at standby.
127 system->closeDevices();
128 }
Matthew Barth29e9e382020-01-23 13:40:49 -0600129 }
130}
131
Matthew Barthf2bcf1f2020-01-29 14:42:47 -0600132void Manager::timerExpired()
133{
134 // TODO Analyze, refresh sensor status, and
135 // collect/update telemetry for each regulator
136}
137
Matthew Barth7cbc5532020-01-29 15:13:13 -0600138void Manager::sighupHandler(sdeventplus::source::Signal& /*sigSrc*/,
139 const struct signalfd_siginfo* /*sigInfo*/)
140{
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -0500141 if (!fileName.empty())
142 {
143 loadConfigFile();
144 }
Matthew Barth7cbc5532020-01-29 15:13:13 -0600145}
146
Matthew Barth250d0a92020-02-28 13:04:24 -0600147void Manager::signalHandler(sdbusplus::message::message& msg)
148{
149 if (msg)
150 {
151 sdbusplus::message::object_path op;
152 msg.read(op);
153 if (static_cast<const std::string&>(op) != sysDbusPath)
154 {
155 // Object path does not match the path
156 return;
157 }
158
159 // An interfacesAdded signal returns a dictionary of interface
160 // names to a dictionary of properties and their values
161 // https://dbus.freedesktop.org/doc/dbus-specification.html
162 std::map<std::string, std::map<std::string, std::variant<std::string>>>
163 intfProp;
164 msg.read(intfProp);
165 auto itIntf = intfProp.find(sysDbusIntf);
166 if (itIntf == intfProp.cend())
167 {
168 // Interface not found on the path
169 return;
170 }
171 auto itProp = itIntf->second.find(sysDbusProp);
172 if (itProp == itIntf->second.cend())
173 {
174 // Property not found on the interface
175 return;
176 }
177 // Set fileName and call parse json function
178 setFileName(std::get<std::string>(itProp->second));
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -0500179 if (!fileName.empty())
180 {
181 loadConfigFile();
182 }
Matthew Barth250d0a92020-02-28 13:04:24 -0600183 }
184}
185
Matthew Barthbbc7c582020-02-03 15:55:15 -0600186const std::string Manager::getFileNameDbus()
187{
188 std::string fileName = "";
189 using namespace phosphor::power::util;
190
191 try
192 {
193 // Do not log an error when service or property are not found
194 auto service = getService(sysDbusPath, sysDbusIntf, bus, false);
195 if (!service.empty())
196 {
197 getProperty(sysDbusIntf, sysDbusProp, sysDbusPath, service, bus,
198 fileName);
199 }
200 }
201 catch (const sdbusplus::exception::SdBusError&)
202 {
203 // File name property not available on dbus
204 fileName = "";
205 }
206
207 return fileName;
208}
209
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -0500210fs::path Manager::findConfigFile()
211{
212 // First look in the test directory
213 fs::path pathName{testConfigFileDir / fileName};
214 if (!fs::exists(pathName))
215 {
216 // Look in the standard directory
217 pathName = standardConfigFileDir / fileName;
218 if (!fs::exists(pathName))
219 {
220 throw std::runtime_error{"Configuration file does not exist: " +
221 pathName.string()};
222 }
223 }
224
225 return pathName;
226}
227
228void Manager::loadConfigFile()
229{
230 try
231 {
232 // Find the absolute path to the config file
233 fs::path pathName = findConfigFile();
234
235 // Log info message in journal; config file path is important
236 journal::logInfo("Loading configuration file " + pathName.string());
237
238 // Parse the config file
239 std::vector<std::unique_ptr<Rule>> rules{};
240 std::vector<std::unique_ptr<Chassis>> chassis{};
241 std::tie(rules, chassis) = config_file_parser::parse(pathName);
242
243 // Store config file information in a new System object. The old System
244 // object, if any, is automatically deleted.
245 system = std::make_unique<System>(std::move(rules), std::move(chassis));
246 }
247 catch (const std::exception& e)
248 {
249 // Log error messages in journal
250 exception_utils::log(e);
251 journal::logErr("Unable to load configuration file");
252
253 // TODO: Create error log entry
254 }
255}
256
Shawn McCarney84807b92020-04-30 18:40:03 -0500257} // namespace phosphor::power::regulators