blob: 9810e1493c8e21c9c741a7a14e1bfebcf36157f5 [file] [log] [blame]
Lei YU415b9642017-02-09 11:37:26 +08001#include "manager.hpp"
Lei YU7f4fca52017-02-23 15:15:51 +08002#include "utils.hpp"
Lei YU415b9642017-02-09 11:37:26 +08003
4#include <phosphor-logging/log.hpp>
5
6namespace rules = sdbusplus::bus::match::rules;
7
8namespace // anonymous
9{
10constexpr auto SETTINGS_SERVICE = "org.openbmc.settings.Host";
11constexpr auto SETTINGS_PATH = "/org/openbmc/settings/host0";
12constexpr auto SETTINGS_INTERFACE = "org.openbmc.settings.Host";
13constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
14constexpr auto METHOD_GET = "Get";
15
Lei YU415b9642017-02-09 11:37:26 +080016// TODO: Use new settings in xyz.openbmc_project
17const auto MATCH_PROPERTY_CHANGE =
18 rules::type::signal() +
19 rules::member("PropertiesChanged") +
20 rules::path("/org/openbmc/settings/host0") +
21 rules::interface("org.freedesktop.DBus.Properties");
22
Lei YUc6fe8692017-02-23 15:12:07 +080023const auto MATCH_PGOOD_CHANGE =
24 rules::type::signal() +
25 rules::member("PropertiesChanged") +
26 rules::path("/org/openbmc/control/power0") +
27 rules::interface("org.freedesktop.DBus.Properties");
28
29// TODO: consider put the get properties related functions into a common place
30constexpr auto POWER_SERVICE = "org.openbmc.control.Power";
31constexpr auto POWER_PATH = "/org/openbmc/control/power0";
32constexpr auto POWER_INTERFACE = POWER_SERVICE;
33constexpr auto PGOOD_STR = "pgood";
Lei YU415b9642017-02-09 11:37:26 +080034}
35
36namespace phosphor
37{
38namespace time
39{
40
41using namespace phosphor::logging;
42
43const std::set<std::string>
44Manager::managedProperties = {PROPERTY_TIME_MODE, PROPERTY_TIME_OWNER};
45
46const std::map<std::string, Owner> Manager::ownerMap =
47{
48 { "BMC", Owner::BMC },
49 { "HOST", Owner::HOST },
50 { "SPLIT", Owner::SPLIT },
51 { "BOTH", Owner::BOTH },
52};
53
54Manager::Manager(sdbusplus::bus::bus& bus)
55 : bus(bus),
Lei YUc6fe8692017-02-23 15:12:07 +080056 propertyChangeMatch(bus, MATCH_PROPERTY_CHANGE, onPropertyChanged, this),
57 pgoodChangeMatch(bus, MATCH_PGOOD_CHANGE, onPgoodChanged, this)
Lei YU415b9642017-02-09 11:37:26 +080058{
Lei YUc6fe8692017-02-23 15:12:07 +080059 checkHostOn();
Lei YU7f4fca52017-02-23 15:15:51 +080060
61 // Restore settings from persistent storage
62 restoreSettings();
63
64 // Check the settings daemon to process the new settings
65 onPropertyChanged(PROPERTY_TIME_MODE, getSettings(PROPERTY_TIME_MODE));
66 onPropertyChanged(PROPERTY_TIME_OWNER, getSettings(PROPERTY_TIME_OWNER));
Lei YU415b9642017-02-09 11:37:26 +080067}
68
69void Manager::addListener(PropertyChangeListner* listener)
70{
71 // Notify listener about the initial value
72 listener->onModeChanged(timeMode);
73 listener->onOwnerChanged(timeOwner);
74
75 listeners.insert(listener);
76}
77
Lei YU7f4fca52017-02-23 15:15:51 +080078void Manager::restoreSettings()
79{
80 auto mode = utils::readData<std::string>(modeFile);
81 if (!mode.empty())
82 {
83 timeMode = convertToMode(mode);
84 }
85 auto owner = utils::readData<std::string>(ownerFile);
86 if (!owner.empty())
87 {
88 timeOwner = convertToOwner(owner);
89 }
90}
91
Lei YUc6fe8692017-02-23 15:12:07 +080092void Manager::checkHostOn()
93{
94 sdbusplus::message::variant<int> pgood = 0;
95 auto method = bus.new_method_call(POWER_SERVICE,
96 POWER_PATH,
97 PROPERTY_INTERFACE,
98 METHOD_GET);
99 method.append(PROPERTY_INTERFACE, PGOOD_STR);
100 auto reply = bus.call(method);
101 if (reply)
102 {
103 reply.read(pgood);
104 }
105
106 hostOn = static_cast<bool>(pgood.get<int>());
107}
108
Lei YU415b9642017-02-09 11:37:26 +0800109void Manager::onPropertyChanged(const std::string& key,
110 const std::string& value)
111{
Lei YU415b9642017-02-09 11:37:26 +0800112 // TODO: Check dhcp_ntp
113
Lei YU7f4fca52017-02-23 15:15:51 +0800114 if (hostOn)
Lei YU415b9642017-02-09 11:37:26 +0800115 {
Lei YU7f4fca52017-02-23 15:15:51 +0800116 // If host is on, set the values as requested time mode/owner.
117 // And when host becomes off, notify the listners.
118 setPropertyAsRequested(key, value);
Lei YU415b9642017-02-09 11:37:26 +0800119 }
Lei YU7f4fca52017-02-23 15:15:51 +0800120 else
Lei YU415b9642017-02-09 11:37:26 +0800121 {
Lei YU7f4fca52017-02-23 15:15:51 +0800122 // If host is off, notify listners
123 if (key == PROPERTY_TIME_MODE)
Lei YU415b9642017-02-09 11:37:26 +0800124 {
Lei YU7f4fca52017-02-23 15:15:51 +0800125 setCurrentTimeMode(value);
126 for (const auto listener : listeners)
127 {
128 listener->onModeChanged(timeMode);
129 }
130 }
131 else if (key == PROPERTY_TIME_OWNER)
132 {
133 setCurrentTimeOwner(value);
134 for (const auto listener : listeners)
135 {
136 listener->onOwnerChanged(timeOwner);
137 }
Lei YU415b9642017-02-09 11:37:26 +0800138 }
139 }
140}
141
142int Manager::onPropertyChanged(sd_bus_message* msg,
143 void* userData,
144 sd_bus_error* retError)
145{
146 using properties = std::map < std::string,
Lei YUc6fe8692017-02-23 15:12:07 +0800147 sdbusplus::message::variant<std::string> >;
Lei YU415b9642017-02-09 11:37:26 +0800148 auto m = sdbusplus::message::message(msg);
149 // message type: sa{sv}as
150 std::string ignore;
151 properties props;
152 m.read(ignore, props);
153 for (const auto& item : props)
154 {
155 if (managedProperties.find(item.first) != managedProperties.end())
156 {
Lei YU7f4fca52017-02-23 15:15:51 +0800157 static_cast<Manager*>(userData)->onPropertyChanged(
158 item.first, item.second.get<std::string>());
Lei YU415b9642017-02-09 11:37:26 +0800159 }
160 }
161 return 0;
162}
163
Lei YU7f4fca52017-02-23 15:15:51 +0800164void Manager::setPropertyAsRequested(const std::string& key,
165 const std::string& value)
166{
167 if (key == PROPERTY_TIME_MODE)
168 {
169 setRequestedMode(value);
170 }
171 else if (key == PROPERTY_TIME_OWNER)
172 {
173 setRequestedOwner(value);
174 }
175 else
176 {
177 // The key shall be already the supported one
178 // TODO: use elog API
179 assert(false);
180 }
181}
182
183void Manager::setRequestedMode(const std::string& mode)
184{
185 requestedMode = mode;
186}
187
188void Manager::setRequestedOwner(const std::string& owner)
189{
190 requestedOwner = owner;
191}
192
Lei YUc6fe8692017-02-23 15:12:07 +0800193void Manager::onPgoodChanged(bool pgood)
194{
195 hostOn = pgood;
Lei YU7f4fca52017-02-23 15:15:51 +0800196 if (hostOn)
197 {
198 return;
199 }
200 if (!requestedMode.empty())
201 {
202 setCurrentTimeMode(requestedMode);
203 for (const auto& listener : listeners)
204 {
205 listener->onModeChanged(timeMode);
206 }
207 setRequestedMode({}); // Clear requested mode
208 }
209 if (!requestedOwner.empty())
210 {
211 setCurrentTimeOwner(requestedOwner);
212 for (const auto& listener : listeners)
213 {
214 listener->onOwnerChanged(timeOwner);
215 }
216 setRequestedOwner({}); // Clear requested owner
217 }
Lei YUc6fe8692017-02-23 15:12:07 +0800218}
219
220int Manager::onPgoodChanged(sd_bus_message* msg,
221 void* userData,
222 sd_bus_error* retError)
223{
224 using properties = std::map < std::string,
225 sdbusplus::message::variant<int> >;
226 auto m = sdbusplus::message::message(msg);
227 // message type: sa{sv}as
228 std::string ignore;
229 properties props;
230 m.read(ignore, props);
231 for (const auto& item : props)
232 {
233 if (item.first == PGOOD_STR)
234 {
235 static_cast<Manager*>(userData)
236 ->onPgoodChanged(static_cast<bool>(item.second.get<int>()));
237 }
238 }
239 return 0;
240}
Lei YU415b9642017-02-09 11:37:26 +0800241
242void Manager::setCurrentTimeMode(const std::string& mode)
243{
244 log<level::INFO>("Time mode is changed",
245 entry("MODE=%s", mode.c_str()));
246 timeMode = convertToMode(mode);
Lei YU7f4fca52017-02-23 15:15:51 +0800247 utils::writeData(modeFile, mode);
Lei YU415b9642017-02-09 11:37:26 +0800248}
249
250void Manager::setCurrentTimeOwner(const std::string& owner)
251{
252 log<level::INFO>("Time owner is changed",
253 entry("OWNER=%s", owner.c_str()));
254 timeOwner = convertToOwner(owner);
Lei YU7f4fca52017-02-23 15:15:51 +0800255 utils::writeData(ownerFile, owner);
Lei YU415b9642017-02-09 11:37:26 +0800256}
257
258std::string Manager::getSettings(const char* value) const
259{
260 sdbusplus::message::variant<std::string> mode;
261 auto method = bus.new_method_call(SETTINGS_SERVICE,
262 SETTINGS_PATH,
263 PROPERTY_INTERFACE,
264 METHOD_GET);
265 method.append(SETTINGS_INTERFACE, value);
266 auto reply = bus.call(method);
267 if (reply)
268 {
269 reply.read(mode);
270 }
271 else
272 {
273 log<level::ERR>("Failed to get settings");
274 }
275
276 return mode.get<std::string>();
277}
278
279Mode Manager::convertToMode(const std::string& mode)
280{
281 if (mode == "NTP")
282 {
283 return Mode::NTP;
284 }
285 else if (mode == "MANUAL")
286 {
287 return Mode::MANUAL;
288 }
289 else
290 {
291 log<level::ERR>("Unrecognized mode",
292 entry("%s", mode.c_str()));
293 return Mode::NTP;
294 }
295}
296
297Owner Manager::convertToOwner(const std::string& owner)
298{
299 auto it = ownerMap.find(owner);
300 if (it == ownerMap.end())
301 {
302 log<level::ERR>("Unrecognized owner",
303 entry("%s", owner.c_str()));
304 return Owner::BMC;
305 }
306 return it->second;
307}
308
309}
310}