blob: 5bfa1e488ad7f1997d68c1549b711402172ffc90 [file] [log] [blame]
Cheng C Yang58b2b532019-05-31 00:19:45 +08001/*
2// Copyright (c) 2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#include <PSUEvent.hpp>
18#include <iostream>
19#include <sdbusplus/asio/connection.hpp>
20#include <sdbusplus/asio/object_server.hpp>
21
22PSUCombineEvent::PSUCombineEvent(
23 sdbusplus::asio::object_server& objectServer, boost::asio::io_service& io,
24 const std::string& psuName,
25 boost::container::flat_map<std::string, std::vector<std::string>>&
26 eventPathList,
27 const std::string& combineEventName) :
28 objServer(objectServer)
29{
30 eventInterface = objServer.add_interface(
31 "/xyz/openbmc_project/State/Decorator/" + psuName + "_" +
32 combineEventName,
33 "xyz.openbmc_project.State.Decorator.OperationalStatus");
34 eventInterface->register_property("functional", bool(true));
35
36 if (!eventInterface->initialize())
37 {
38 std::cerr << "error initializing event interface\n";
39 }
40
41 std::shared_ptr<std::set<std::string>> combineEvent =
42 std::make_shared<std::set<std::string>>();
43 for (const auto& pathList : eventPathList)
44 {
45 const std::string& eventName = pathList.first;
46 std::string eventPSUName = eventName + psuName;
47 for (const auto& path : pathList.second)
48 {
49 std::shared_ptr<std::set<std::string>> assert =
50 std::make_shared<std::set<std::string>>();
51 std::shared_ptr<bool> state = std::make_shared<bool>(false);
52 events[eventPSUName].emplace_back(std::make_unique<PSUSubEvent>(
53 eventInterface, path, io, eventName, assert, combineEvent,
54 state));
55 asserts.emplace_back(assert);
56 states.emplace_back(state);
57 }
58 }
59}
60
61PSUCombineEvent::~PSUCombineEvent()
62{
63 events.clear();
64 objServer.remove_interface(eventInterface);
65}
66
67PSUSubEvent::PSUSubEvent(
68 std::shared_ptr<sdbusplus::asio::dbus_interface> eventInterface,
69 const std::string& path, boost::asio::io_service& io,
70 const std::string& eventName,
71 std::shared_ptr<std::set<std::string>> asserts,
72 std::shared_ptr<std::set<std::string>> combineEvent,
73 std::shared_ptr<bool> state) :
74 eventInterface(eventInterface),
75 inputDev(io, open(path.c_str(), O_RDONLY)), waitTimer(io), errCount(0),
76 path(path), eventName(eventName), assertState(state), asserts(asserts),
77 combineEvent(combineEvent)
78{
79 setupRead();
80}
81
82void PSUSubEvent::setupRead(void)
83{
84 boost::asio::async_read_until(
85 inputDev, readBuf, '\n',
86 [&](const boost::system::error_code& ec,
87 std::size_t /*bytes_transfered*/) { handleResponse(ec); });
88}
89
90PSUSubEvent::~PSUSubEvent()
91{
92 inputDev.close();
93 waitTimer.cancel();
94}
95
96void PSUSubEvent::handleResponse(const boost::system::error_code& err)
97{
98 if (err == boost::system::errc::bad_file_descriptor)
99 {
100 return;
101 }
102 std::istream responseStream(&readBuf);
103 if (!err)
104 {
105 std::string response;
106 try
107 {
108 std::getline(responseStream, response);
109 int nvalue = std::stof(response);
110 responseStream.clear();
111 if (nvalue != value)
112 {
113 updateValue(nvalue);
114 }
115 errCount = 0;
116 }
117 catch (const std::invalid_argument&)
118 {
119 errCount++;
120 }
121 }
122 else
123 {
124 errCount++;
125 }
126 if (errCount >= warnAfterErrorCount)
127 {
128 if (errCount == warnAfterErrorCount)
129 {
130 std::cerr << "Failure to read event at " << path << "\n";
131 }
132 updateValue(0);
133 errCount++;
134 }
135 responseStream.clear();
136 inputDev.close();
137 int fd = open(path.c_str(), O_RDONLY);
138 if (fd <= 0)
139 {
140 return;
141 }
142 inputDev.assign(fd);
143 waitTimer.expires_from_now(boost::posix_time::milliseconds(eventPollMs));
144 waitTimer.async_wait([&](const boost::system::error_code& ec) {
145 if (ec == boost::asio::error::operation_aborted)
146 {
147 return;
148 }
149 setupRead();
150 });
151}
152
153// Any of the sub events of one event is asserted, then the event will be
154// asserted. Only if none of the sub events are asserted, the event will be
155// deasserted.
156void PSUSubEvent::updateValue(const int& newValue)
157{
158 if (newValue == 0)
159 {
160 auto found = (*asserts).find(path);
161 if (found == (*asserts).end())
162 {
163 return;
164 }
165 (*asserts).erase(found);
166
167 if (!(*asserts).empty())
168 {
169 return;
170 }
171 if (*assertState == true)
172 {
173 *assertState = false;
174 auto foundCombine = (*combineEvent).find(eventName);
175 if (foundCombine != (*combineEvent).end())
176 {
177 return;
178 }
179 (*combineEvent).erase(eventName);
180 if ((*combineEvent).empty())
181 {
182 eventInterface->set_property("functional", true);
183 }
184 }
185 }
186 else
187 {
188 (*asserts).emplace(path);
189 if (*assertState == false)
190 {
191 *assertState = true;
192 if ((*combineEvent).empty())
193 {
194 eventInterface->set_property("functional", false);
195 }
196 (*combineEvent).emplace(eventName);
197 }
198 }
199 value = newValue;
200}