blob: ac5e12371628e037fc55b3efdd535bc13c94455f [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
19namespace phosphor
20{
21namespace virtualSensor
22{
23
24void printParams(const VirtualSensor::ParamMap& paramMap)
25{
26 for (const auto& p : paramMap)
27 {
28 const auto& p1 = p.first;
29 const auto& p2 = p.second;
30 auto val = p2->getParamValue();
31 std::cout << p1 << " = " << val << "\n";
32 }
33}
34
35double SensorParam::getParamValue()
36{
37 switch (paramType)
38 {
39 case constParam:
40 return value;
41 break;
Vijay Khemka7452a862020-08-11 16:01:23 -070042 case dbusParam:
43 return dbusSensor->getSensorValue();
44 break;
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070045 default:
46 throw std::invalid_argument("param type not supported");
47 }
48}
49
50void VirtualSensor::initVirtualSensor(const Json& sensorConfig)
51{
52
53 static const Json empty{};
54
55 /* Get threshold values if defined in config */
56 auto threshold = sensorConfig.value("Threshold", empty);
57 if (!threshold.empty())
58 {
59 sensorThreshold.criticalHigh =
60 threshold.value("CriticalHigh", defaultHighThreshold);
61 sensorThreshold.criticalLow =
62 threshold.value("CriticalLow", defaultLowThreshold);
63 sensorThreshold.warningHigh =
64 threshold.value("WarningHigh", defaultHighThreshold);
65 sensorThreshold.warningLow =
66 threshold.value("WarningLow", defaultLowThreshold);
67 }
68
69 /* Set threshold value to dbus */
70 setSensorThreshold();
71
72 /* Get expression string */
73 exprStr = sensorConfig.value("Expression", "");
74
75 /* Get all the parameter listed in configuration */
76 auto params = sensorConfig.value("Params", empty);
77
78 /* Check for constant parameter */
79 const auto& consParams = params.value("ConstParam", empty);
80 if (!consParams.empty())
81 {
82 for (auto& j : consParams)
83 {
84 if (j.find("ParamName") != j.end())
85 {
86 auto paramPtr = std::make_unique<SensorParam>(j["Value"]);
Vijay Khemka3ed9a512020-08-21 16:13:05 -070087 std::string name = j["ParamName"];
88 symbols.create_variable(name);
89 paramMap.emplace(std::move(name), std::move(paramPtr));
Vijay Khemkaabcc94f2020-08-11 15:27:44 -070090 }
91 else
92 {
93 /* Invalid configuration */
94 throw std::invalid_argument(
95 "ParamName not found in configuration");
96 }
97 }
98 }
99
Vijay Khemka7452a862020-08-11 16:01:23 -0700100 /* Check for dbus parameter */
101 auto dbusParams = params.value("DbusParam", empty);
102 if (!dbusParams.empty())
103 {
104 for (auto& j : dbusParams)
105 {
106 /* Get parameter dbus sensor descriptor */
107 auto desc = j.value("Desc", empty);
108 if ((!desc.empty()) && (j.find("ParamName") != j.end()))
109 {
110 std::string sensorType = desc.value("SensorType", "");
111 std::string name = desc.value("Name", "");
112
113 if (!sensorType.empty() && !name.empty())
114 {
115 std::string objPath(sensorDbusPath);
116 objPath += sensorType + "/" + name;
117
118 auto paramPtr = std::make_unique<SensorParam>(bus, objPath);
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700119 std::string name = j["ParamName"];
120 symbols.create_variable(name);
121 paramMap.emplace(std::move(name), std::move(paramPtr));
Vijay Khemka7452a862020-08-11 16:01:23 -0700122 }
123 }
124 }
125 }
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700126
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700127 symbols.add_constants();
128 expression.register_symbol_table(symbols);
129
130 /* parser from exprtk */
131 exprtk::parser<double> parser{};
132 parser.compile(exprStr, expression);
133
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700134 /* Print all parameters for debug purpose only */
135 if (DEBUG)
136 printParams(paramMap);
137}
138
139void VirtualSensor::setSensorValue(double value)
140{
141 ValueIface::value(value);
142}
143
144void VirtualSensor::setSensorThreshold()
145{
146 CriticalInterface::criticalHigh(sensorThreshold.criticalHigh);
147 CriticalInterface::criticalLow(sensorThreshold.criticalLow);
148 WarningInterface::warningHigh(sensorThreshold.warningHigh);
149 WarningInterface::warningLow(sensorThreshold.warningLow);
150}
151
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700152void VirtualSensor::updateVirtualSensor()
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700153{
154 for (auto& param : paramMap)
155 {
156 auto& name = param.first;
157 auto& data = param.second;
158 if (auto var = symbols.get_variable(name))
159 {
160 var->ref() = data->getParamValue();
161 }
162 else
163 {
164 /* Invalid parameter */
165 throw std::invalid_argument("ParamName not found in symbols");
166 }
167 }
168 double val = expression.value();
169 setSensorValue(val);
170 if (DEBUG)
171 std::cout << "Sensor value is " << val << "\n";
172}
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700173
174/** @brief Parsing Virtual Sensor config JSON file */
175Json VirtualSensors::parseConfigFile(const std::string configFile)
176{
177 std::ifstream jsonFile(configFile);
178 if (!jsonFile.is_open())
179 {
180 log<level::ERR>("config JSON file not found",
181 entry("FILENAME = %s", configFile.c_str()));
182 throw std::exception{};
183 }
184
185 auto data = Json::parse(jsonFile, nullptr, false);
186 if (data.is_discarded())
187 {
188 log<level::ERR>("config readings JSON parser failure",
189 entry("FILENAME = %s", configFile.c_str()));
190 throw std::exception{};
191 }
192
193 return data;
194}
195
196void VirtualSensors::createVirtualSensors()
197{
198 static const Json empty{};
199
200 auto data = parseConfigFile(VIRTUAL_SENSOR_CONFIG_FILE);
201 // print values
202 if (DEBUG)
203 std::cout << "Config json data:\n" << data << "\n\n";
204
205 /* Get virtual sensors config data */
206 for (const auto& j : data)
207 {
208 auto desc = j.value("Desc", empty);
209 if (!desc.empty())
210 {
211 std::string sensorType = desc.value("SensorType", "");
212 std::string name = desc.value("Name", "");
213
214 if (!name.empty() && !sensorType.empty())
215 {
216 std::string objPath(sensorDbusPath);
217 objPath += sensorType + "/" + name;
218
219 auto virtualSensorPtr =
220 std::make_unique<VirtualSensor>(bus, objPath.c_str(), j);
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700221
222 log<level::INFO>("Added a new virtual sensor",
223 entry("NAME = %s", name.c_str()));
Vijay Khemka3ed9a512020-08-21 16:13:05 -0700224 virtualSensorPtr->updateVirtualSensor();
225 virtualSensorsMap.emplace(std::move(name),
226 std::move(virtualSensorPtr));
Vijay Khemkaabcc94f2020-08-11 15:27:44 -0700227 }
228 else
229 {
230 log<level::ERR>("Sensor type or name not found in config file");
231 }
232 }
233 else
234 {
235 log<level::ERR>(
236 "Descriptor for new virtual sensor not found in config file");
237 }
238 }
239}
240
241} // namespace virtualSensor
242} // namespace phosphor
243
244/**
245 * @brief Main
246 */
247int main()
248{
249
250 // Get a default event loop
251 auto event = sdeventplus::Event::get_default();
252
253 // Get a handle to system dbus
254 auto bus = sdbusplus::bus::new_default();
255
256 // Create an virtual sensors object
257 phosphor::virtualSensor::VirtualSensors virtualSensors(bus);
258
259 // Request service bus name
260 bus.request_name(busName);
261
262 // Attach the bus to sd_event to service user requests
263 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
264 event.loop();
265
266 return 0;
267}