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(1000);
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("MinPowerSupplies"))
65     {
66         p.minPowerSupplies = sysProps["MinPowerSupplies"];
67     }
68     else
69     {
70         p.minPowerSupplies = 0;
71     }
72 
73     if (sysProps.contains("MaxPowerSupplies"))
74     {
75         p.maxPowerSupplies = sysProps["MaxPowerSupplies"];
76     }
77     else
78     {
79         p.maxPowerSupplies = 0;
80     }
81 
82     for (auto psuJSON : configFileJSON["PowerSupplies"])
83     {
84         if (psuJSON.contains("Inventory") && psuJSON.contains("Bus") &&
85             psuJSON.contains("Address"))
86         {
87             std::string invpath = psuJSON["Inventory"];
88             std::uint8_t i2cbus = psuJSON["Bus"];
89             std::string i2caddr = psuJSON["Address"];
90             auto psu =
91                 std::make_unique<PowerSupply>(bus, invpath, i2cbus, i2caddr);
92             psus.emplace_back(std::move(psu));
93         }
94         else
95         {
96             log<level::ERR>("Insufficient PowerSupply properties");
97         }
98     }
99 
100     if (psus.empty())
101     {
102         throw std::runtime_error("No power supplies to monitor");
103     }
104 }
105 
106 void PSUManager::powerStateChanged(sdbusplus::message::message& msg)
107 {
108     int32_t state = 0;
109     std::string msgSensor;
110     std::map<std::string, std::variant<int32_t>> msgData;
111     msg.read(msgSensor, msgData);
112 
113     // Check if it was the Present property that changed.
114     auto valPropMap = msgData.find("state");
115     if (valPropMap != msgData.end())
116     {
117         state = std::get<int32_t>(valPropMap->second);
118 
119         // Power is on when state=1. Clear faults.
120         if (state)
121         {
122             powerOn = true;
123             clearFaults();
124         }
125         else
126         {
127             powerOn = false;
128         }
129     }
130 }
131 
132 } // namespace manager
133 } // namespace power
134 } // namespace phosphor
135