1 #include "manager.hpp" 2 #include "utils.hpp" 3 4 #include <phosphor-logging/log.hpp> 5 6 namespace rules = sdbusplus::bus::match::rules; 7 8 namespace // anonymous 9 { 10 constexpr auto SETTINGS_SERVICE = "org.openbmc.settings.Host"; 11 constexpr auto SETTINGS_PATH = "/org/openbmc/settings/host0"; 12 constexpr auto SETTINGS_INTERFACE = "org.openbmc.settings.Host"; 13 constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"; 14 constexpr auto METHOD_GET = "Get"; 15 16 // TODO: Use new settings in xyz.openbmc_project 17 const 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 23 const 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 30 constexpr auto POWER_SERVICE = "org.openbmc.control.Power"; 31 constexpr auto POWER_PATH = "/org/openbmc/control/power0"; 32 constexpr auto POWER_INTERFACE = POWER_SERVICE; 33 constexpr auto PGOOD_STR = "pgood"; 34 } 35 36 namespace phosphor 37 { 38 namespace time 39 { 40 41 using namespace phosphor::logging; 42 43 const std::set<std::string> 44 Manager::managedProperties = {PROPERTY_TIME_MODE, PROPERTY_TIME_OWNER}; 45 46 const 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 54 Manager::Manager(sdbusplus::bus::bus& bus) 55 : bus(bus), 56 propertyChangeMatch(bus, MATCH_PROPERTY_CHANGE, onPropertyChanged, this), 57 pgoodChangeMatch(bus, MATCH_PGOOD_CHANGE, onPgoodChanged, this) 58 { 59 checkHostOn(); 60 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)); 67 } 68 69 void 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 78 void 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 92 void 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 109 void Manager::onPropertyChanged(const std::string& key, 110 const std::string& value) 111 { 112 // TODO: Check dhcp_ntp 113 114 if (hostOn) 115 { 116 // 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); 119 } 120 else 121 { 122 // If host is off, notify listners 123 if (key == PROPERTY_TIME_MODE) 124 { 125 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 } 138 } 139 } 140 } 141 142 int Manager::onPropertyChanged(sd_bus_message* msg, 143 void* userData, 144 sd_bus_error* retError) 145 { 146 using properties = std::map < std::string, 147 sdbusplus::message::variant<std::string> >; 148 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 { 157 static_cast<Manager*>(userData)->onPropertyChanged( 158 item.first, item.second.get<std::string>()); 159 } 160 } 161 return 0; 162 } 163 164 void 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 183 void Manager::setRequestedMode(const std::string& mode) 184 { 185 requestedMode = mode; 186 } 187 188 void Manager::setRequestedOwner(const std::string& owner) 189 { 190 requestedOwner = owner; 191 } 192 193 void Manager::onPgoodChanged(bool pgood) 194 { 195 hostOn = pgood; 196 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 } 218 } 219 220 int 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 } 241 242 void 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); 247 utils::writeData(modeFile, mode); 248 } 249 250 void 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); 255 utils::writeData(ownerFile, owner); 256 } 257 258 std::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 279 Mode 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 297 Owner 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 } 311