blob: c8b70abd8fe220683fef8456765c6ac226e84507 [file] [log] [blame]
Vijay Khemkaabcc94f2020-08-11 15:27:44 -07001#include "virtualSensor.hpp"
2
3#include "config.hpp"
4
5#include <phosphor-logging/log.hpp>
6#include <sdeventplus/event.hpp>
7
8#include <fstream>
9#include <iostream>
10
11static constexpr bool DEBUG = false;
12static constexpr auto busName = "xyz.openbmc_project.VirtualSensor";
13static constexpr auto sensorDbusPath = "/xyz/openbmc_project/sensors/";
14static constexpr uint8_t defaultHighThreshold = 100;
15static constexpr uint8_t defaultLowThreshold = 0;
16
17using namespace phosphor::logging;
18
Vijay Khemka51f898e2020-09-09 22:24:18 -070019int handleDbusSignal(sd_bus_message* msg, void* usrData, sd_bus_error*)
20{
21 if (usrData == nullptr)
22 {
23 throw std::runtime_error("Invalid match");
24 }
25
26 auto sdbpMsg = sdbusplus::message::message(msg);
27 std::string msgIfce;
28 std::map<std::string, std::variant<int64_t, double, bool>> msgData;
29
30 sdbpMsg.read(msgIfce, msgData);
31
32 if (msgData.find("Value") != msgData.end())
33 {
34 using namespace phosphor::virtualSensor;
35 VirtualSensor* obj = static_cast<VirtualSensor*>(usrData);
36 // TODO(openbmc/phosphor-virtual-sensor#1): updateVirtualSensor should
37 // be changed to take the information we got from the signal, to avoid
38 // having to do numerous dbus queries.
39 obj->updateVirtualSensor();
40 }
41 return 0;
42}
43
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070044namespace phosphor
45{
46namespace virtualSensor
47{
48
49void printParams(const VirtualSensor::ParamMap& paramMap)
50{
51 for (const auto& p : paramMap)
52 {
53 const auto& p1 = p.first;
54 const auto& p2 = p.second;
55 auto val = p2->getParamValue();
56 std::cout << p1 << " = " << val << "\n";
57 }
58}
59
60double SensorParam::getParamValue()
61{
62 switch (paramType)
63 {
64 case constParam:
65 return value;
66 break;
Vijay Khemka7452a862020-08-11 16:01:23 -070067 case dbusParam:
68 return dbusSensor->getSensorValue();
69 break;
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070070 default:
71 throw std::invalid_argument("param type not supported");
72 }
73}
74
75void VirtualSensor::initVirtualSensor(const Json& sensorConfig)
76{
77
78 static const Json empty{};
79
80 /* Get threshold values if defined in config */
81 auto threshold = sensorConfig.value("Threshold", empty);
82 if (!threshold.empty())
83 {
84 sensorThreshold.criticalHigh =
85 threshold.value("CriticalHigh", defaultHighThreshold);
86 sensorThreshold.criticalLow =
87 threshold.value("CriticalLow", defaultLowThreshold);
88 sensorThreshold.warningHigh =
89 threshold.value("WarningHigh", defaultHighThreshold);
90 sensorThreshold.warningLow =
91 threshold.value("WarningLow", defaultLowThreshold);
92 }
93
94 /* Set threshold value to dbus */
95 setSensorThreshold();
96
97 /* Get expression string */
98 exprStr = sensorConfig.value("Expression", "");
99
100 /* Get all the parameter listed in configuration */
101 auto params = sensorConfig.value("Params", empty);
102
103 /* Check for constant parameter */
104 const auto& consParams = params.value("ConstParam", empty);
105 if (!consParams.empty())
106 {
107 for (auto& j : consParams)
108 {
109 if (j.find("ParamName") != j.end())
110 {
111 auto paramPtr = std::make_unique<SensorParam>(j["Value"]);
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700112 std::string name = j["ParamName"];
113 symbols.create_variable(name);
114 paramMap.emplace(std::move(name), std::move(paramPtr));
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700115 }
116 else
117 {
118 /* Invalid configuration */
119 throw std::invalid_argument(
120 "ParamName not found in configuration");
121 }
122 }
123 }
124
Vijay Khemka7452a862020-08-11 16:01:23 -0700125 /* Check for dbus parameter */
126 auto dbusParams = params.value("DbusParam", empty);
127 if (!dbusParams.empty())
128 {
129 for (auto& j : dbusParams)
130 {
131 /* Get parameter dbus sensor descriptor */
132 auto desc = j.value("Desc", empty);
133 if ((!desc.empty()) && (j.find("ParamName") != j.end()))
134 {
135 std::string sensorType = desc.value("SensorType", "");
136 std::string name = desc.value("Name", "");
137
138 if (!sensorType.empty() && !name.empty())
139 {
140 std::string objPath(sensorDbusPath);
141 objPath += sensorType + "/" + name;
142
Vijay Khemka51f898e2020-09-09 22:24:18 -0700143 auto paramPtr =
144 std::make_unique<SensorParam>(bus, objPath, this);
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700145 std::string name = j["ParamName"];
146 symbols.create_variable(name);
147 paramMap.emplace(std::move(name), std::move(paramPtr));
Vijay Khemka7452a862020-08-11 16:01:23 -0700148 }
149 }
150 }
151 }
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700152
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700153 symbols.add_constants();
154 expression.register_symbol_table(symbols);
155
156 /* parser from exprtk */
157 exprtk::parser<double> parser{};
158 parser.compile(exprStr, expression);
159
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700160 /* Print all parameters for debug purpose only */
161 if (DEBUG)
162 printParams(paramMap);
163}
164
165void VirtualSensor::setSensorValue(double value)
166{
167 ValueIface::value(value);
168}
169
170void VirtualSensor::setSensorThreshold()
171{
172 CriticalInterface::criticalHigh(sensorThreshold.criticalHigh);
173 CriticalInterface::criticalLow(sensorThreshold.criticalLow);
174 WarningInterface::warningHigh(sensorThreshold.warningHigh);
175 WarningInterface::warningLow(sensorThreshold.warningLow);
176}
177
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700178void VirtualSensor::updateVirtualSensor()
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700179{
180 for (auto& param : paramMap)
181 {
182 auto& name = param.first;
183 auto& data = param.second;
184 if (auto var = symbols.get_variable(name))
185 {
186 var->ref() = data->getParamValue();
187 }
188 else
189 {
190 /* Invalid parameter */
191 throw std::invalid_argument("ParamName not found in symbols");
192 }
193 }
194 double val = expression.value();
195 setSensorValue(val);
196 if (DEBUG)
197 std::cout << "Sensor value is " << val << "\n";
198}
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700199
200/** @brief Parsing Virtual Sensor config JSON file */
201Json VirtualSensors::parseConfigFile(const std::string configFile)
202{
203 std::ifstream jsonFile(configFile);
204 if (!jsonFile.is_open())
205 {
206 log<level::ERR>("config JSON file not found",
207 entry("FILENAME = %s", configFile.c_str()));
208 throw std::exception{};
209 }
210
211 auto data = Json::parse(jsonFile, nullptr, false);
212 if (data.is_discarded())
213 {
214 log<level::ERR>("config readings JSON parser failure",
215 entry("FILENAME = %s", configFile.c_str()));
216 throw std::exception{};
217 }
218
219 return data;
220}
221
222void VirtualSensors::createVirtualSensors()
223{
224 static const Json empty{};
225
226 auto data = parseConfigFile(VIRTUAL_SENSOR_CONFIG_FILE);
227 // print values
228 if (DEBUG)
229 std::cout << "Config json data:\n" << data << "\n\n";
230
231 /* Get virtual sensors config data */
232 for (const auto& j : data)
233 {
234 auto desc = j.value("Desc", empty);
235 if (!desc.empty())
236 {
237 std::string sensorType = desc.value("SensorType", "");
238 std::string name = desc.value("Name", "");
239
240 if (!name.empty() && !sensorType.empty())
241 {
242 std::string objPath(sensorDbusPath);
243 objPath += sensorType + "/" + name;
244
245 auto virtualSensorPtr =
246 std::make_unique<VirtualSensor>(bus, objPath.c_str(), j);
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700247
248 log<level::INFO>("Added a new virtual sensor",
249 entry("NAME = %s", name.c_str()));
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700250 virtualSensorPtr->updateVirtualSensor();
251 virtualSensorsMap.emplace(std::move(name),
252 std::move(virtualSensorPtr));
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700253 }
254 else
255 {
256 log<level::ERR>("Sensor type or name not found in config file");
257 }
258 }
259 else
260 {
261 log<level::ERR>(
262 "Descriptor for new virtual sensor not found in config file");
263 }
264 }
265}
266
267} // namespace virtualSensor
268} // namespace phosphor
269
270/**
271 * @brief Main
272 */
273int main()
274{
275
276 // Get a default event loop
277 auto event = sdeventplus::Event::get_default();
278
279 // Get a handle to system dbus
280 auto bus = sdbusplus::bus::new_default();
281
282 // Create an virtual sensors object
283 phosphor::virtualSensor::VirtualSensors virtualSensors(bus);
284
285 // Request service bus name
286 bus.request_name(busName);
287
288 // Attach the bus to sd_event to service user requests
289 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
290 event.loop();
291
292 return 0;
293}