Modify set sensor reading command

The Set Sensor handling code is modified to use generated code
for CPU, Core & DIMM sensors with Presence & Functional
offset.

Change-Id: I3b7fa4da870b745873da4732d457d793f5549ada
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/sensorhandler.cpp b/sensorhandler.cpp
index a40196c..53bb412 100644
--- a/sensorhandler.cpp
+++ b/sensorhandler.cpp
@@ -1,14 +1,19 @@
-#include "sensorhandler.h"
-#include "host-ipmid/ipmid-api.h"
 #include <mapper.h>
 #include <stdio.h>
 #include <string.h>
-#include <stdint.h>
+#include <bitset>
 #include <systemd/sd-bus.h>
+#include "host-ipmid/ipmid-api.h"
+#include <phosphor-logging/log.hpp>
 #include "ipmid.hpp"
+#include "sensorhandler.h"
+#include "types.hpp"
+#include "utils.hpp"
 
 extern int updateSensorRecordFromSSRAESC(const void *);
 extern sd_bus *bus;
+extern const ipmi::sensor::IdInfoMap sensors;
+using namespace phosphor::logging;
 
 void register_netfn_sen_functions()   __attribute__((constructor));
 
@@ -343,22 +348,120 @@
     return rc;
 }
 
+ipmi_ret_t setSensorReading(void *request)
+{
+    auto cmdData = static_cast<SetSensorReadingReq *>(request);
 
+    auto assertionStates =
+            (static_cast<uint16_t>(cmdData->assertOffset8_14)) << 8 |
+            cmdData->assertOffset0_7;
+
+    auto deassertionStates =
+            (static_cast<uint16_t>(cmdData->deassertOffset8_14)) << 8 |
+            cmdData->deassertOffset0_7;
+
+    std::bitset<16> assertionSet(assertionStates);
+    std::bitset<16> deassertionSet(deassertionStates);
+
+    // Check if the Sensor Number is present
+    auto iter = sensors.find(cmdData->number);
+    if (iter == sensors.end())
+    {
+        return IPMI_CC_SENSOR_INVALID;
+    }
+
+    auto& interfaceList = iter->second.sensorInterfaces;
+    if (interfaceList.empty())
+    {
+        log<level::ERR>("Interface List empty for the sensor",
+                entry("Sensor Number = %d", cmdData->number));
+        return IPMI_CC_UNSPECIFIED_ERROR;
+    }
+
+    ipmi::sensor::ObjectMap objects;
+    ipmi::sensor::InterfaceMap interfaces;
+    for (const auto& interface : interfaceList)
+    {
+        for (const auto& property : interface.second)
+        {
+            ipmi::sensor::PropertyMap props;
+            bool valid = false;
+            for (const auto& value : property.second)
+            {
+                if (assertionSet.test(value.first))
+                {
+                    props.emplace(property.first, value.second.assert);
+                    valid = true;
+                }
+                else if (deassertionSet.test(value.first))
+                {
+                    props.emplace(property.first, value.second.deassert);
+                    valid = true;
+                }
+            }
+            if (valid)
+            {
+                interfaces.emplace(interface.first, std::move(props));
+            }
+        }
+    }
+    objects.emplace(iter->second.sensorPath, std::move(interfaces));
+
+    auto bus = sdbusplus::bus::new_default();
+    using namespace std::string_literals;
+    static const auto intf = "xyz.openbmc_project.Inventory.Manager"s;
+    static const auto path = "/xyz/openbmc_project/inventory"s;
+    std::string service;
+
+    try
+    {
+        service = ipmi::getService(bus, intf, path);
+
+        // Update the inventory manager
+        auto pimMsg = bus.new_method_call(service.c_str(),
+                                          path.c_str(),
+                                          intf.c_str(),
+                                          "Notify");
+        pimMsg.append(std::move(objects));
+        auto inventoryMgrResponseMsg = bus.call(pimMsg);
+        if (inventoryMgrResponseMsg.is_method_error())
+        {
+            log<level::ERR>("Error in notify call");
+            return IPMI_CC_UNSPECIFIED_ERROR;
+        }
+    }
+    catch (const std::runtime_error& e)
+    {
+        log<level::ERR>(e.what());
+        return IPMI_CC_UNSPECIFIED_ERROR;
+    }
+
+    return IPMI_CC_OK;
+}
 
 ipmi_ret_t ipmi_sen_set_sensor(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
                              ipmi_request_t request, ipmi_response_t response,
                              ipmi_data_len_t data_len, ipmi_context_t context)
 {
     sensor_data_t *reqptr = (sensor_data_t*)request;
-    ipmi_ret_t rc = IPMI_CC_OK;
 
     printf("IPMI SET_SENSOR [0x%02x]\n",reqptr->sennum);
 
-    updateSensorRecordFromSSRAESC(reqptr);
+    /*
+     * This would support the Set Sensor Reading command for the presence
+     * and functional state of Processor, Core & DIMM. For the remaining
+     * sensors the existing support is invoked.
+     */
+    auto ipmiRC = setSensorReading(request);
+
+    if(ipmiRC == IPMI_CC_SENSOR_INVALID)
+    {
+        updateSensorRecordFromSSRAESC(reqptr);
+        ipmiRC = IPMI_CC_OK;
+    }
 
     *data_len=0;
-
-    return rc;
+    return ipmiRC;
 }