Basic initial implementation
This is a base implementation which does following
1. create a daemon,
2. parse config file and create a virtual sensor object
3. create list of virtual sensors for given config.
4. Creates a systemd unit file
It currently supports constant params only and dbus params will be in
follow up patch.
Signed-off-by: Vijay Khemka <vijaykhemka@fb.com>
Change-Id: I89b2ffb8bff67bdbb3033071cba9f6e565a9af6e
diff --git a/virtualSensor.cpp b/virtualSensor.cpp
new file mode 100644
index 0000000..ef8543f
--- /dev/null
+++ b/virtualSensor.cpp
@@ -0,0 +1,210 @@
+#include "virtualSensor.hpp"
+
+#include "config.hpp"
+
+#include <phosphor-logging/log.hpp>
+#include <sdeventplus/event.hpp>
+
+#include <fstream>
+#include <iostream>
+
+static constexpr bool DEBUG = false;
+static constexpr auto busName = "xyz.openbmc_project.VirtualSensor";
+static constexpr auto sensorDbusPath = "/xyz/openbmc_project/sensors/";
+static constexpr uint8_t defaultHighThreshold = 100;
+static constexpr uint8_t defaultLowThreshold = 0;
+
+using namespace phosphor::logging;
+
+namespace phosphor
+{
+namespace virtualSensor
+{
+
+void printParams(const VirtualSensor::ParamMap& paramMap)
+{
+ for (const auto& p : paramMap)
+ {
+ const auto& p1 = p.first;
+ const auto& p2 = p.second;
+ auto val = p2->getParamValue();
+ std::cout << p1 << " = " << val << "\n";
+ }
+}
+
+double SensorParam::getParamValue()
+{
+ switch (paramType)
+ {
+ case constParam:
+ return value;
+ break;
+ default:
+ throw std::invalid_argument("param type not supported");
+ }
+}
+
+void VirtualSensor::initVirtualSensor(const Json& sensorConfig)
+{
+
+ static const Json empty{};
+
+ /* Get threshold values if defined in config */
+ auto threshold = sensorConfig.value("Threshold", empty);
+ if (!threshold.empty())
+ {
+ sensorThreshold.criticalHigh =
+ threshold.value("CriticalHigh", defaultHighThreshold);
+ sensorThreshold.criticalLow =
+ threshold.value("CriticalLow", defaultLowThreshold);
+ sensorThreshold.warningHigh =
+ threshold.value("WarningHigh", defaultHighThreshold);
+ sensorThreshold.warningLow =
+ threshold.value("WarningLow", defaultLowThreshold);
+ }
+
+ /* Set threshold value to dbus */
+ setSensorThreshold();
+
+ /* Get expression string */
+ exprStr = sensorConfig.value("Expression", "");
+
+ /* Get all the parameter listed in configuration */
+ auto params = sensorConfig.value("Params", empty);
+
+ /* Check for constant parameter */
+ const auto& consParams = params.value("ConstParam", empty);
+ if (!consParams.empty())
+ {
+ for (auto& j : consParams)
+ {
+ if (j.find("ParamName") != j.end())
+ {
+ auto paramPtr = std::make_unique<SensorParam>(j["Value"]);
+ paramMap.emplace(j["ParamName"], std::move(paramPtr));
+ }
+ else
+ {
+ /* Invalid configuration */
+ throw std::invalid_argument(
+ "ParamName not found in configuration");
+ }
+ }
+ }
+
+ /* TODO: Check for dbus parameter */
+
+ /* Print all parameters for debug purpose only */
+ if (DEBUG)
+ printParams(paramMap);
+}
+
+void VirtualSensor::setSensorValue(double value)
+{
+ ValueIface::value(value);
+}
+
+void VirtualSensor::setSensorThreshold()
+{
+ CriticalInterface::criticalHigh(sensorThreshold.criticalHigh);
+ CriticalInterface::criticalLow(sensorThreshold.criticalLow);
+ WarningInterface::warningHigh(sensorThreshold.warningHigh);
+ WarningInterface::warningLow(sensorThreshold.warningLow);
+}
+
+/* TBD */
+void VirtualSensor::updateVirtualSensor()
+{}
+
+/** @brief Parsing Virtual Sensor config JSON file */
+Json VirtualSensors::parseConfigFile(const std::string configFile)
+{
+ std::ifstream jsonFile(configFile);
+ if (!jsonFile.is_open())
+ {
+ log<level::ERR>("config JSON file not found",
+ entry("FILENAME = %s", configFile.c_str()));
+ throw std::exception{};
+ }
+
+ auto data = Json::parse(jsonFile, nullptr, false);
+ if (data.is_discarded())
+ {
+ log<level::ERR>("config readings JSON parser failure",
+ entry("FILENAME = %s", configFile.c_str()));
+ throw std::exception{};
+ }
+
+ return data;
+}
+
+void VirtualSensors::createVirtualSensors()
+{
+ static const Json empty{};
+
+ auto data = parseConfigFile(VIRTUAL_SENSOR_CONFIG_FILE);
+ // print values
+ if (DEBUG)
+ std::cout << "Config json data:\n" << data << "\n\n";
+
+ /* Get virtual sensors config data */
+ for (const auto& j : data)
+ {
+ auto desc = j.value("Desc", empty);
+ if (!desc.empty())
+ {
+ std::string sensorType = desc.value("SensorType", "");
+ std::string name = desc.value("Name", "");
+
+ if (!name.empty() && !sensorType.empty())
+ {
+ std::string objPath(sensorDbusPath);
+ objPath += sensorType + "/" + name;
+
+ auto virtualSensorPtr =
+ std::make_unique<VirtualSensor>(bus, objPath.c_str(), j);
+ virtualSensorsMap.emplace(name, std::move(virtualSensorPtr));
+
+ log<level::INFO>("Added a new virtual sensor",
+ entry("NAME = %s", name.c_str()));
+ }
+ else
+ {
+ log<level::ERR>("Sensor type or name not found in config file");
+ }
+ }
+ else
+ {
+ log<level::ERR>(
+ "Descriptor for new virtual sensor not found in config file");
+ }
+ }
+}
+
+} // namespace virtualSensor
+} // namespace phosphor
+
+/**
+ * @brief Main
+ */
+int main()
+{
+
+ // Get a default event loop
+ auto event = sdeventplus::Event::get_default();
+
+ // Get a handle to system dbus
+ auto bus = sdbusplus::bus::new_default();
+
+ // Create an virtual sensors object
+ phosphor::virtualSensor::VirtualSensors virtualSensors(bus);
+
+ // Request service bus name
+ bus.request_name(busName);
+
+ // Attach the bus to sd_event to service user requests
+ bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
+ event.loop();
+
+ return 0;
+}