blob: fb6d456754f7f02e02bba8e17c9fb727af858016 [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 {
Vijay Khemkac62a5542020-09-10 14:45:49 -070084 Threshold sensorThreshold;
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070085 sensorThreshold.criticalHigh =
86 threshold.value("CriticalHigh", defaultHighThreshold);
87 sensorThreshold.criticalLow =
88 threshold.value("CriticalLow", defaultLowThreshold);
89 sensorThreshold.warningHigh =
90 threshold.value("WarningHigh", defaultHighThreshold);
91 sensorThreshold.warningLow =
92 threshold.value("WarningLow", defaultLowThreshold);
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070093
Vijay Khemkac62a5542020-09-10 14:45:49 -070094 /* Set threshold value to dbus */
95 setSensorThreshold(sensorThreshold);
96 }
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070097
98 /* Get expression string */
99 exprStr = sensorConfig.value("Expression", "");
100
101 /* Get all the parameter listed in configuration */
102 auto params = sensorConfig.value("Params", empty);
103
104 /* Check for constant parameter */
105 const auto& consParams = params.value("ConstParam", empty);
106 if (!consParams.empty())
107 {
108 for (auto& j : consParams)
109 {
110 if (j.find("ParamName") != j.end())
111 {
112 auto paramPtr = std::make_unique<SensorParam>(j["Value"]);
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700113 std::string name = j["ParamName"];
114 symbols.create_variable(name);
115 paramMap.emplace(std::move(name), std::move(paramPtr));
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700116 }
117 else
118 {
119 /* Invalid configuration */
120 throw std::invalid_argument(
121 "ParamName not found in configuration");
122 }
123 }
124 }
125
Vijay Khemka7452a862020-08-11 16:01:23 -0700126 /* Check for dbus parameter */
127 auto dbusParams = params.value("DbusParam", empty);
128 if (!dbusParams.empty())
129 {
130 for (auto& j : dbusParams)
131 {
132 /* Get parameter dbus sensor descriptor */
133 auto desc = j.value("Desc", empty);
134 if ((!desc.empty()) && (j.find("ParamName") != j.end()))
135 {
136 std::string sensorType = desc.value("SensorType", "");
137 std::string name = desc.value("Name", "");
138
139 if (!sensorType.empty() && !name.empty())
140 {
141 std::string objPath(sensorDbusPath);
142 objPath += sensorType + "/" + name;
143
Vijay Khemka51f898e2020-09-09 22:24:18 -0700144 auto paramPtr =
145 std::make_unique<SensorParam>(bus, objPath, this);
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700146 std::string name = j["ParamName"];
147 symbols.create_variable(name);
148 paramMap.emplace(std::move(name), std::move(paramPtr));
Vijay Khemka7452a862020-08-11 16:01:23 -0700149 }
150 }
151 }
152 }
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700153
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700154 symbols.add_constants();
155 expression.register_symbol_table(symbols);
156
157 /* parser from exprtk */
158 exprtk::parser<double> parser{};
159 parser.compile(exprStr, expression);
160
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700161 /* Print all parameters for debug purpose only */
162 if (DEBUG)
163 printParams(paramMap);
164}
165
166void VirtualSensor::setSensorValue(double value)
167{
168 ValueIface::value(value);
169}
170
Vijay Khemkac62a5542020-09-10 14:45:49 -0700171void VirtualSensor::setSensorThreshold(Threshold& sensorThreshold)
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700172{
173 CriticalInterface::criticalHigh(sensorThreshold.criticalHigh);
174 CriticalInterface::criticalLow(sensorThreshold.criticalLow);
175 WarningInterface::warningHigh(sensorThreshold.warningHigh);
176 WarningInterface::warningLow(sensorThreshold.warningLow);
177}
178
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700179void VirtualSensor::updateVirtualSensor()
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700180{
181 for (auto& param : paramMap)
182 {
183 auto& name = param.first;
184 auto& data = param.second;
185 if (auto var = symbols.get_variable(name))
186 {
187 var->ref() = data->getParamValue();
188 }
189 else
190 {
191 /* Invalid parameter */
192 throw std::invalid_argument("ParamName not found in symbols");
193 }
194 }
195 double val = expression.value();
196 setSensorValue(val);
197 if (DEBUG)
198 std::cout << "Sensor value is " << val << "\n";
199}
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700200
201/** @brief Parsing Virtual Sensor config JSON file */
202Json VirtualSensors::parseConfigFile(const std::string configFile)
203{
204 std::ifstream jsonFile(configFile);
205 if (!jsonFile.is_open())
206 {
207 log<level::ERR>("config JSON file not found",
208 entry("FILENAME = %s", configFile.c_str()));
209 throw std::exception{};
210 }
211
212 auto data = Json::parse(jsonFile, nullptr, false);
213 if (data.is_discarded())
214 {
215 log<level::ERR>("config readings JSON parser failure",
216 entry("FILENAME = %s", configFile.c_str()));
217 throw std::exception{};
218 }
219
220 return data;
221}
222
223void VirtualSensors::createVirtualSensors()
224{
225 static const Json empty{};
226
227 auto data = parseConfigFile(VIRTUAL_SENSOR_CONFIG_FILE);
228 // print values
229 if (DEBUG)
230 std::cout << "Config json data:\n" << data << "\n\n";
231
232 /* Get virtual sensors config data */
233 for (const auto& j : data)
234 {
235 auto desc = j.value("Desc", empty);
236 if (!desc.empty())
237 {
238 std::string sensorType = desc.value("SensorType", "");
239 std::string name = desc.value("Name", "");
240
241 if (!name.empty() && !sensorType.empty())
242 {
243 std::string objPath(sensorDbusPath);
244 objPath += sensorType + "/" + name;
245
246 auto virtualSensorPtr =
247 std::make_unique<VirtualSensor>(bus, objPath.c_str(), j);
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700248
249 log<level::INFO>("Added a new virtual sensor",
250 entry("NAME = %s", name.c_str()));
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700251 virtualSensorPtr->updateVirtualSensor();
252 virtualSensorsMap.emplace(std::move(name),
253 std::move(virtualSensorPtr));
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700254 }
255 else
256 {
257 log<level::ERR>("Sensor type or name not found in config file");
258 }
259 }
260 else
261 {
262 log<level::ERR>(
263 "Descriptor for new virtual sensor not found in config file");
264 }
265 }
266}
267
268} // namespace virtualSensor
269} // namespace phosphor
270
271/**
272 * @brief Main
273 */
274int main()
275{
276
277 // Get a default event loop
278 auto event = sdeventplus::Event::get_default();
279
280 // Get a handle to system dbus
281 auto bus = sdbusplus::bus::new_default();
282
283 // Create an virtual sensors object
284 phosphor::virtualSensor::VirtualSensors virtualSensors(bus);
285
286 // Request service bus name
287 bus.request_name(busName);
288
289 // Attach the bus to sd_event to service user requests
290 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
291 event.loop();
292
293 return 0;
294}