IPMI changes to mark non present as non functional

When marking a unit as functional, both functional state
and presence need to be checked to avoid marking non-present
units as functional.

Change-Id: If7b710c39f1c2590b82378ebdb7014dc924599ff
Signed-off-by: Dhruvaraj Subhashchandran <dhruvaraj@in.ibm.com>
diff --git a/scripts/sensor-example.yaml b/scripts/sensor-example.yaml
index 98e9ff6..c4ff4d5 100755
--- a/scripts/sensor-example.yaml
+++ b/scripts/sensor-example.yaml
@@ -17,13 +17,14 @@
     # One or more interface dict entries
     org.open_power.OCC.Status:
       OccActive:
-        # Sensor type specific offset
-        0x06:
-          # OccActive is a boolean
-          type: "bool"
-          # If offset 0x06 is asserted, set OccActive as false.
-          assert: "false"
-          deassert: "true"
+        Offsets:
+          # Sensor type specific offset
+          0x06:
+            # OccActive is a boolean
+            type: "bool"
+            # If offset 0x06 is asserted, set OccActive as false.
+            assert: "false"
+            deassert: "true"
 
 0x61:
   sensorType: 0x04
@@ -35,14 +36,23 @@
   serviceInterface: xyz.openbmc_project.Inventory.Manager
   readingType: assertion
   interfaces:
-    xyz.openbmc_project.Inventory.Item:
-      Present:
-        0x06:
-          assert: true
-          deassert: false
-          type: bool
     xyz.openbmc_project.State.Decorator.OperationalStatus:
       Functional:
+        #Offsets contain the offsets in the sensor data.
+        Offsets:
+          0x06:
+            assert: true
+            deassert: false
+            type: bool
+        #Prereqs are pre-requisites for this property value to be true.
+        Prereqs:
+          0x04:
+            assert: false
+            deassert: true
+            type: bool
+    xyz.openbmc_project.Inventory.Item:
+      Present:
+        Offsets:
           0x04:
             assert: false
             deassert: true
@@ -52,8 +62,9 @@
   interfaces:
     xyz.openbmc_project.Control.Boot.RebootAttempts:
       AttemptsLeft:
-        0xFF:
-          type: uint32_t
+        Offsets:
+          0xFF:
+            type: uint32_t
   path: /xyz/openbmc_project/state/host0
   # A special case of assertion, where the entire assert bitfield
   # serves as the value, or reading. Hence, the offset above is intentionally
@@ -67,8 +78,9 @@
   interfaces:
     xyz.openbmc_project.Control.Boot.RebootAttempts:
       AttemptsLeft:
-        0xFF:
-          type: uint32_t
+        Offsets:
+          0xFF:
+            type: uint32_t
   path: /xyz/openbmc_project/state/host1
   readingType: readingAssertion
   sensorReadingType: 0x6F
@@ -88,8 +100,9 @@
   interfaces:
     xyz.openbmc_project.Sensor.Value:
       Value:
-        0xFF:
-          type: int64_t
+        Offsets:
+          0xFF:
+            type: int64_t
 
 0x54:
   sensorType: 0x07
@@ -100,12 +113,18 @@
   interfaces:
     xyz.openbmc_project.State.Decorator.OperationalStatus:
       Functional:
+        Offsets:
           0x08:
             assert: false
             deassert: true
             type: bool
+        Prereqs:
+          0x07:
+            assert: true
+            deassert: false
     xyz.openbmc_project.Inventory.Item:
       Present:
+        Offsets:
           0x07:
             assert: true
             deassert: false
diff --git a/scripts/writesensor.mako.cpp b/scripts/writesensor.mako.cpp
index 9cd4e48..c5db13a 100644
--- a/scripts/writesensor.mako.cpp
+++ b/scripts/writesensor.mako.cpp
@@ -51,7 +51,7 @@
        if "readingAssertion" == valueReadingType or "readingData" == valueReadingType:
            for interface,properties in interfaces.items():
                for dbus_property,property_value in properties.items():
-                   for offset,values in property_value.items():
+                   for offset,values in property_value["Offsets"].items():
                        valueType = values["type"]
            updateFunc = "set::" + valueReadingType + "<" + valueType + ">"
            getFunc = "get::" + valueReadingType + "<" + valueType + ">"
@@ -66,7 +66,28 @@
             {"${interface}",{
             % for dbus_property,property_value in properties.items():
                 {"${dbus_property}",{
-                % for offset,values in property_value.items():
+<%
+try:
+    preReq = property_value["Prereqs"]
+except KeyError, e:
+    preReq = dict()
+%>\
+                {
+                    % for preOffset,preValues in preReq.items():
+                    { ${preOffset},{
+                        % for name,value in preValues.items():
+                            % if name == "type":
+<%                              continue %>\
+                            % endif
+<%                          value = str(value).lower() %>\
+                            ${value},
+                        % endfor
+                        }
+                    },
+                    % endfor
+                },
+                {
+                % for offset,values in property_value["Offsets"].items():
                     { ${offset},{
                         % if offset == 0xFF:
                             }},
@@ -102,11 +123,11 @@
                         }
                     },
                 % endfor
-                }},
+                }}},
             % endfor
             }},
     % endfor
-     },
+     }
 }},
    % endif
 % endfor
diff --git a/sensordatahandler.cpp b/sensordatahandler.cpp
index c8d4fbf..8240108 100644
--- a/sensordatahandler.cpp
+++ b/sensordatahandler.cpp
@@ -132,7 +132,7 @@
                                                    interface.first,
                                                    property.first);
 
-            for (const auto& value : property.second)
+            for (const auto& value : std::get<OffsetValueMap>(property.second))
             {
                 if (propValue == value.second.assert)
                 {
@@ -176,7 +176,7 @@
                                                    interface.first,
                                                    property.first);
 
-            for (const auto& value : property.second)
+            for (const auto& value : std::get<OffsetValueMap>(property.second))
             {
                 if (propValue == value.second.assert)
                 {
@@ -230,8 +230,8 @@
     for (const auto& property : interface->second)
     {
         msg.append(property.first);
-        const auto& iter = property.second.find(data);
-        if (iter == property.second.end())
+        const auto& iter = std::get<OffsetValueMap>(property.second).find(data);
+        if (iter == std::get<OffsetValueMap>(property.second).end())
         {
             log<level::ERR>("Invalid event data");
             return IPMI_CC_PARM_OUT_OF_RANGE;
@@ -258,7 +258,7 @@
     for (const auto& property : interface->second)
     {
         msg.append(property.first);
-        for (const auto& value : property.second)
+        for (const auto& value : std::get<OffsetValueMap>(property.second))
         {
             if (assertionSet.test(value.first))
             {
@@ -310,11 +310,14 @@
     ipmi::sensor::InterfaceMap interfaces;
     for (const auto& interface : sensorInfo.propertyInterfaces)
     {
+        //For a property like functional state the result will be
+        //calculated based on the true value of all conditions.
         for (const auto& property : interface.second)
         {
             ipmi::sensor::PropertyMap props;
             bool valid = false;
-            for (const auto& value : property.second)
+            auto result = true;
+            for (const auto& value : std::get<OffsetValueMap>(property.second))
             {
                 if (assertionSet.test(value.first))
                 {
@@ -323,7 +326,7 @@
                     {
                         return IPMI_CC_OK;
                     }
-                    props.emplace(property.first, value.second.assert);
+                    result = result && value.second.assert.get<bool>();
                     valid = true;
                 }
                 else if (deassertionSet.test(value.first))
@@ -333,12 +336,25 @@
                     {
                         return IPMI_CC_OK;
                     }
-                    props.emplace(property.first, value.second.deassert);
+                    result = result && value.second.deassert.get<bool>();
                     valid = true;
                 }
             }
+            for (const auto& value :
+                    std::get<PreReqOffsetValueMap>(property.second))
+            {
+                if (assertionSet.test(value.first))
+                {
+                    result = result && value.second.assert.get<bool>();
+                }
+                else if (deassertionSet.test(value.first))
+                {
+                    result = result && value.second.deassert.get<bool>();
+                }
+            }
             if (valid)
             {
+                props.emplace(property.first, result);
                 interfaces.emplace(interface.first, std::move(props));
             }
         }
diff --git a/types.hpp b/types.hpp
index d3be704..0177c8f 100644
--- a/types.hpp
+++ b/types.hpp
@@ -51,6 +51,18 @@
 };
 
 /**
+ * @enum PreReqValues
+ * Pre-req conditions for a property.
+ */
+struct PreReqValues
+{
+    Value assert; //Value in case of assert.
+    Value deassert; //Value in case of deassert.
+};
+
+using PreReqOffsetValueMap = std::map<Offset, PreReqValues>;
+
+/**
  * @struct SetSensorReadingReq
  *
  * IPMI Request data for Set Sensor Reading and Event Status Command
@@ -88,9 +100,11 @@
 
 using OffsetValueMap = std::map<Offset,Values>;
 
-using DbusPropertyMap = std::map<DbusProperty,OffsetValueMap>;
+using DbusPropertyValues = std::pair<PreReqOffsetValueMap, OffsetValueMap>;
 
-using DbusInterfaceMap = std::map<DbusInterface,DbusPropertyMap>;
+using DbusPropertyMap = std::map<DbusProperty, DbusPropertyValues>;
+
+using DbusInterfaceMap = std::map<DbusInterface, DbusPropertyMap>;
 
 using InstancePath = std::string;
 using Type = uint8_t;