1 #include "manager.hpp"
2 
3 #include <phosphor-logging/log.hpp>
4 
5 namespace rules = sdbusplus::bus::match::rules;
6 
7 namespace // anonymous
8 {
9 constexpr auto SETTINGS_SERVICE = "org.openbmc.settings.Host";
10 constexpr auto SETTINGS_PATH = "/org/openbmc/settings/host0";
11 constexpr auto SETTINGS_INTERFACE = "org.openbmc.settings.Host";
12 constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
13 constexpr auto METHOD_GET = "Get";
14 
15 constexpr auto PROPERTY_TIME_MODE = "time_mode";
16 constexpr auto PROPERTY_TIME_OWNER = "time_owner";
17 
18 // TODO: Use new settings in xyz.openbmc_project
19 const auto MATCH_PROPERTY_CHANGE =
20     rules::type::signal() +
21     rules::member("PropertiesChanged") +
22     rules::path("/org/openbmc/settings/host0") +
23     rules::interface("org.freedesktop.DBus.Properties");
24 
25 }
26 
27 namespace phosphor
28 {
29 namespace time
30 {
31 
32 using namespace phosphor::logging;
33 
34 const std::set<std::string>
35 Manager::managedProperties = {PROPERTY_TIME_MODE, PROPERTY_TIME_OWNER};
36 
37 const std::map<std::string, Owner> Manager::ownerMap =
38 {
39     { "BMC", Owner::BMC },
40     { "HOST", Owner::HOST },
41     { "SPLIT", Owner::SPLIT },
42     { "BOTH", Owner::BOTH },
43 };
44 
45 Manager::Manager(sdbusplus::bus::bus& bus)
46     : bus(bus),
47       propertyChangeMatch(bus, MATCH_PROPERTY_CHANGE, onPropertyChanged, this)
48 {
49     setCurrentTimeMode(getSettings(PROPERTY_TIME_MODE));
50     setCurrentTimeOwner(getSettings(PROPERTY_TIME_OWNER));
51 }
52 
53 void Manager::addListener(PropertyChangeListner* listener)
54 {
55     // Notify listener about the initial value
56     listener->onModeChanged(timeMode);
57     listener->onOwnerChanged(timeOwner);
58 
59     listeners.insert(listener);
60 }
61 
62 void Manager::onPropertyChanged(const std::string& key,
63                                 const std::string& value)
64 {
65     // TODO: Check pgood
66     // If it's off, notify listners;
67     // If it's on, hold the values and store in persistent storage.
68     // And when pgood turns back to off, notify the listners.
69 
70     // TODO: Check dhcp_ntp
71 
72     if (key == PROPERTY_TIME_MODE)
73     {
74         setCurrentTimeMode(value);
75         for (const auto& listener : listeners)
76         {
77             listener->onModeChanged(timeMode);
78         }
79     }
80     else if (key == PROPERTY_TIME_OWNER)
81     {
82         setCurrentTimeOwner(value);
83         for (const auto& listener : listeners)
84         {
85             listener->onOwnerChanged(timeOwner);
86         }
87     }
88 }
89 
90 int Manager::onPropertyChanged(sd_bus_message* msg,
91                                void* userData,
92                                sd_bus_error* retError)
93 {
94     using properties = std::map < std::string,
95           sdbusplus::message::variant<int, std::string >>;
96     auto m = sdbusplus::message::message(msg);
97     // message type: sa{sv}as
98     std::string ignore;
99     properties props;
100     m.read(ignore, props);
101     for (const auto& item : props)
102     {
103         if (managedProperties.find(item.first) != managedProperties.end())
104         {
105             static_cast<Manager*>(userData)
106                 ->onPropertyChanged(item.first, item.second.get<std::string>());
107         }
108     }
109     return 0;
110 }
111 
112 
113 void Manager::setCurrentTimeMode(const std::string& mode)
114 {
115     log<level::INFO>("Time mode is changed",
116                      entry("MODE=%s", mode.c_str()));
117     timeMode = convertToMode(mode);
118 }
119 
120 void Manager::setCurrentTimeOwner(const std::string& owner)
121 {
122     log<level::INFO>("Time owner is changed",
123                      entry("OWNER=%s", owner.c_str()));
124     timeOwner = convertToOwner(owner);
125 }
126 
127 std::string Manager::getSettings(const char* value) const
128 {
129     sdbusplus::message::variant<std::string> mode;
130     auto method = bus.new_method_call(SETTINGS_SERVICE,
131                                       SETTINGS_PATH,
132                                       PROPERTY_INTERFACE,
133                                       METHOD_GET);
134     method.append(SETTINGS_INTERFACE, value);
135     auto reply = bus.call(method);
136     if (reply)
137     {
138         reply.read(mode);
139     }
140     else
141     {
142         log<level::ERR>("Failed to get settings");
143     }
144 
145     return mode.get<std::string>();
146 }
147 
148 Mode Manager::convertToMode(const std::string& mode)
149 {
150     if (mode == "NTP")
151     {
152         return Mode::NTP;
153     }
154     else if (mode == "MANUAL")
155     {
156         return Mode::MANUAL;
157     }
158     else
159     {
160         log<level::ERR>("Unrecognized mode",
161                         entry("%s", mode.c_str()));
162         return Mode::NTP;
163     }
164 }
165 
166 Owner Manager::convertToOwner(const std::string& owner)
167 {
168     auto it = ownerMap.find(owner);
169     if (it == ownerMap.end())
170     {
171         log<level::ERR>("Unrecognized owner",
172                         entry("%s", owner.c_str()));
173         return Owner::BMC;
174     }
175     return it->second;
176 }
177 
178 }
179 }
180