1 #include "psu_manager.hpp"
2 
3 #include "utility.hpp"
4 
5 using namespace phosphor::logging;
6 
7 namespace phosphor
8 {
9 namespace power
10 {
11 namespace manager
12 {
13 
14 PSUManager::PSUManager(sdbusplus::bus::bus& bus, const sdeventplus::Event& e,
15                        const std::string& configfile) :
16     bus(bus)
17 {
18     // Parse out the JSON properties
19     sys_properties properties;
20     getJSONProperties(configfile, bus, properties, psus);
21 
22     using namespace sdeventplus;
23     auto interval = std::chrono::milliseconds(properties.pollInterval);
24     timer = std::make_unique<utility::Timer<ClockId::Monotonic>>(
25         e, std::bind(&PSUManager::analyze, this), interval);
26 
27     minPSUs = {properties.minPowerSupplies};
28     maxPSUs = {properties.maxPowerSupplies};
29 
30     // Subscribe to power state changes
31     powerService = util::getService(POWER_OBJ_PATH, POWER_IFACE, bus);
32     powerOnMatch = std::make_unique<sdbusplus::bus::match_t>(
33         bus,
34         sdbusplus::bus::match::rules::propertiesChanged(POWER_OBJ_PATH,
35                                                         POWER_IFACE),
36         [this](auto& msg) { this->powerStateChanged(msg); });
37 
38     initialize();
39 }
40 
41 void PSUManager::getJSONProperties(
42     const std::string& path, sdbusplus::bus::bus& bus, sys_properties& p,
43     std::vector<std::unique_ptr<PowerSupply>>& psus)
44 {
45     nlohmann::json configFileJSON = util::loadJSONFromFile(path.c_str());
46 
47     if (configFileJSON == nullptr)
48     {
49         throw std::runtime_error("Failed to load JSON configuration file");
50     }
51 
52     if (!configFileJSON.contains("SystemProperties"))
53     {
54         throw std::runtime_error("Missing required SystemProperties");
55     }
56 
57     if (!configFileJSON.contains("PowerSupplies"))
58     {
59         throw std::runtime_error("Missing required PowerSupplies");
60     }
61 
62     auto sysProps = configFileJSON["SystemProperties"];
63 
64     if (!sysProps.contains("pollInterval"))
65     {
66         throw std::runtime_error("Missing required pollInterval property");
67     }
68 
69     p.pollInterval = sysProps["pollInterval"];
70 
71     if (sysProps.contains("MinPowerSupplies"))
72     {
73         p.minPowerSupplies = sysProps["MinPowerSupplies"];
74     }
75     else
76     {
77         p.minPowerSupplies = 0;
78     }
79 
80     if (sysProps.contains("MaxPowerSupplies"))
81     {
82         p.maxPowerSupplies = sysProps["MaxPowerSupplies"];
83     }
84     else
85     {
86         p.maxPowerSupplies = 0;
87     }
88 
89     for (auto psuJSON : configFileJSON["PowerSupplies"])
90     {
91         if (psuJSON.contains("Inventory") && psuJSON.contains("Bus") &&
92             psuJSON.contains("Address"))
93         {
94             std::string invpath = psuJSON["Inventory"];
95             std::uint8_t i2cbus = psuJSON["Bus"];
96             std::string i2caddr = psuJSON["Address"];
97             auto psu =
98                 std::make_unique<PowerSupply>(bus, invpath, i2cbus, i2caddr);
99             psus.emplace_back(std::move(psu));
100         }
101         else
102         {
103             log<level::ERR>("Insufficient PowerSupply properties");
104         }
105     }
106 
107     if (psus.empty())
108     {
109         throw std::runtime_error("No power supplies to monitor");
110     }
111 }
112 
113 void PSUManager::powerStateChanged(sdbusplus::message::message& msg)
114 {
115     int32_t state = 0;
116     std::string msgSensor;
117     std::map<std::string, sdbusplus::message::variant<int32_t>> msgData;
118     msg.read(msgSensor, msgData);
119 
120     // Check if it was the Present property that changed.
121     auto valPropMap = msgData.find("state");
122     if (valPropMap != msgData.end())
123     {
124         state = std::get<int32_t>(valPropMap->second);
125 
126         // Power is on when state=1. Clear faults.
127         if (state)
128         {
129             powerOn = true;
130             clearFaults();
131         }
132         else
133         {
134             powerOn = false;
135         }
136     }
137 }
138 
139 } // namespace manager
140 } // namespace power
141 } // namespace phosphor
142