intrusionsensor: Add Rearm property

This patch adds Rearm property to intrusionsensor service, under
"xyz.openbmc_project.Chassis.Intrusion" interface, to specify the method
for rearming the chassis cover and updating the "Status" property.
As defined in Redfish schema specification, this property is optional.
If not set, "Rearm" will default to "Automatic", which will directly
update the raw chassis intrusion status to the "Status" property.
If set to "Manual", after an intrusion event, the "Status" property
will be kept to "HardwareIntrusion" until a reset action happens for it
to be set to "Normal" (manual rearm). The rearm action comes from
Redfish by writing "Normal" to the "IntrusionSensor" property in
/redfish/v1/Chassis/chassis.

Example:
{
     "Class": "Aspeed2600_Hwmon",
     "Name": "Chassis_Intrusion_Status",
     "Rearm": "Manual",
     "Type": "ChassisIntrusionSensor"
}

Tested: This has been tested on Ampere's Mt.Mitchell platform using
hwmon reading method (property values below need to be prefixed with
strings "xyz.openbmc_project.Chassis.Intrusion.Status." and
"xyz.openbmc_project.Chassis.Intrusion.RearmMode." respectively for
Status and Rearm to achieve the real values on DBus).

Automatic mode (default):
1. The chassis cover is closed => the Status property shows "Normal"
2. The chassis cover is open => Status shows "HardwareIntrusion"

Manual mode:
1. The chassis cover is first open from the last rearm action =>
"HardwareIntrusion"
2. The chassis cover is closed => "HardwareIntrusion"
3. The chassis cover is open again => "HardwareIntrusion"
4. The rearm action is taken => "Normal"
5. The chassis cover is closed => "Normal"

Signed-off-by: Chau Ly <chaul@amperecomputing.com>
Change-Id: I8257a5fee9db67a072e7fafc140f6a143028c429
diff --git a/src/ChassisIntrusionSensor.cpp b/src/ChassisIntrusionSensor.cpp
index 3066359..a2b2776 100644
--- a/src/ChassisIntrusionSensor.cpp
+++ b/src/ChassisIntrusionSensor.cpp
@@ -45,8 +45,14 @@
 static constexpr unsigned int defaultPollSec = 1;
 static constexpr unsigned int sensorFailedPollSec = 5;
 static unsigned int intrusionSensorPollSec = defaultPollSec;
-static constexpr const char* hwIntrusionValStr = "HardwareIntrusion";
-static constexpr const char* normalValStr = "Normal";
+static constexpr const char* hwIntrusionValStr =
+    "xyz.openbmc_project.Chassis.Intrusion.Status.HardwareIntrusion";
+static constexpr const char* normalValStr =
+    "xyz.openbmc_project.Chassis.Intrusion.Status.Normal";
+static constexpr const char* manualRearmStr =
+    "xyz.openbmc_project.Chassis.Intrusion.RearmMode.Manual";
+static constexpr const char* autoRearmStr =
+    "xyz.openbmc_project.Chassis.Intrusion.RearmMode.Automatic";
 
 // SMLink Status Register
 const static constexpr size_t pchStatusRegIntrusion = 0x04;
@@ -61,7 +67,7 @@
 {
     std::string newValue = value != 0 ? hwIntrusionValStr : normalValStr;
 
-    // Take no action if value already equal
+    // Take no action if the hardware status does not change
     // Same semantics as Sensor::updateValue(const double&)
     if (newValue == mValue)
     {
@@ -74,27 +80,37 @@
                   << "\n";
     }
 
+    // Automatic Rearm mode allows direct update
+    // Manual Rearm mode requires a rearm action to clear the intrusion
+    // status
+    if (!mAutoRearm)
+    {
+        if (newValue == normalValStr)
+        {
+            // Chassis is first closed from being open. If it has been
+            // rearmed externally, reset the flag, update mValue and
+            // return, without having to write "Normal" to DBus property
+            // (because the rearm action already did).
+            // Otherwise, return with no more action.
+            if (mRearmFlag)
+            {
+                mRearmFlag = false;
+                mValue = newValue;
+            }
+            return;
+        }
+    }
+
+    // Flush the rearm flag everytime it allows an update to Dbus
+    mRearmFlag = false;
+
     // indicate that it is internal set call
+    mOverridenState = false;
     mInternalSet = true;
     mIface->set_property("Status", newValue);
     mInternalSet = false;
 
     mValue = newValue;
-
-    if (mOldValue == normalValStr && mValue != normalValStr)
-    {
-        sd_journal_send("MESSAGE=%s", "Chassis intrusion assert event",
-                        "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
-                        "OpenBMC.0.1.ChassisIntrusionDetected", NULL);
-        mOldValue = mValue;
-    }
-    else if (mOldValue == hwIntrusionValStr && mValue == normalValStr)
-    {
-        sd_journal_send("MESSAGE=%s", "Chassis intrusion de-assert event",
-                        "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
-                        "OpenBMC.0.1.ChassisIntrusionReset", NULL);
-        mOldValue = mValue;
-    }
 }
 
 int ChassisIntrusionPchSensor::readSensor()
@@ -281,13 +297,42 @@
 {
     if (!mInternalSet)
     {
-        propertyValue = req;
-        mOverridenState = true;
+        /*
+           1. Assuming that setting property in Automatic mode causes
+           no effect but only event logs and propertiesChanged signal
+           (because the property will be updated continuously to the
+           current hardware status anyway), only update Status property
+           and raise rearm flag in Manual rearm mode.
+           2. Only accept Normal value from an external call.
+        */
+        if (!mAutoRearm && req == normalValStr)
+        {
+            mRearmFlag = true;
+            propertyValue = req;
+            mOverridenState = true;
+        }
     }
     else if (!mOverridenState)
     {
         propertyValue = req;
     }
+    else
+    {
+        return 1;
+    }
+    // Send intrusion event to Redfish
+    if (mValue == normalValStr && propertyValue != normalValStr)
+    {
+        sd_journal_send("MESSAGE=%s", "Chassis intrusion assert event",
+                        "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
+                        "OpenBMC.0.1.ChassisIntrusionDetected", NULL);
+    }
+    else if (mValue == hwIntrusionValStr && propertyValue == normalValStr)
+    {
+        sd_journal_send("MESSAGE=%s", "Chassis intrusion de-assert event",
+                        "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
+                        "OpenBMC.0.1.ChassisIntrusionReset", NULL);
+    }
     return 1;
 }
 
@@ -298,22 +343,25 @@
         [&](const std::string& req, std::string& propertyValue) {
         return setSensorValue(req, propertyValue);
         });
+    std::string rearmStr = mAutoRearm ? autoRearmStr : manualRearmStr;
+    mIface->register_property("Rearm", rearmStr);
     mIface->initialize();
     pollSensorStatus();
 }
 
 ChassisIntrusionSensor::ChassisIntrusionSensor(
-    sdbusplus::asio::object_server& objServer) :
-    mObjServer(objServer)
+    bool autoRearm, sdbusplus::asio::object_server& objServer) :
+    mValue(normalValStr),
+    mAutoRearm(autoRearm), mObjServer(objServer)
 {
     mIface = mObjServer.add_interface("/xyz/openbmc_project/Chassis/Intrusion",
                                       "xyz.openbmc_project.Chassis.Intrusion");
 }
 
 ChassisIntrusionPchSensor::ChassisIntrusionPchSensor(
-    boost::asio::io_context& io, sdbusplus::asio::object_server& objServer,
-    int busId, int slaveAddr) :
-    ChassisIntrusionSensor(objServer),
+    bool autoRearm, boost::asio::io_context& io,
+    sdbusplus::asio::object_server& objServer, int busId, int slaveAddr) :
+    ChassisIntrusionSensor(autoRearm, objServer),
     mPollTimer(io)
 {
     if (busId < 0 || slaveAddr <= 0)
@@ -355,9 +403,9 @@
 }
 
 ChassisIntrusionGpioSensor::ChassisIntrusionGpioSensor(
-    boost::asio::io_context& io, sdbusplus::asio::object_server& objServer,
-    bool gpioInverted) :
-    ChassisIntrusionSensor(objServer),
+    bool autoRearm, boost::asio::io_context& io,
+    sdbusplus::asio::object_server& objServer, bool gpioInverted) :
+    ChassisIntrusionSensor(autoRearm, objServer),
     mGpioInverted(gpioInverted), mGpioFd(io)
 {
     mGpioLine = gpiod::find_line(mPinName);
@@ -380,9 +428,9 @@
 }
 
 ChassisIntrusionHwmonSensor::ChassisIntrusionHwmonSensor(
-    boost::asio::io_context& io, sdbusplus::asio::object_server& objServer,
-    std::string hwmonName) :
-    ChassisIntrusionSensor(objServer),
+    bool autoRearm, boost::asio::io_context& io,
+    sdbusplus::asio::object_server& objServer, std::string hwmonName) :
+    ChassisIntrusionSensor(autoRearm, objServer),
     mHwmonName(std::move(hwmonName)), mPollTimer(io)
 {
     std::vector<fs::path> paths;
diff --git a/src/ChassisIntrusionSensor.hpp b/src/ChassisIntrusionSensor.hpp
index e3b84cf..d22eaf8 100644
--- a/src/ChassisIntrusionSensor.hpp
+++ b/src/ChassisIntrusionSensor.hpp
@@ -13,7 +13,8 @@
 class ChassisIntrusionSensor
 {
   public:
-    explicit ChassisIntrusionSensor(sdbusplus::asio::object_server& objServer);
+    explicit ChassisIntrusionSensor(bool autoRearm,
+                                    sdbusplus::asio::object_server& objServer);
 
     virtual ~ChassisIntrusionSensor();
 
@@ -25,13 +26,14 @@
     void updateValue(const size_t& value);
 
   private:
-    // intrusion status. 0: not intruded, 1: intruded
-    std::string mValue = "unknown";
-    std::string mOldValue = "Normal";
+    std::string mValue;
+    // If this sensor uses automatic rearm method. Otherwise, manually rearm it
+    bool mAutoRearm;
     std::shared_ptr<sdbusplus::asio::dbus_interface> mIface;
     sdbusplus::asio::object_server& mObjServer;
     bool mOverridenState = false;
     bool mInternalSet = false;
+    bool mRearmFlag = false;
 
     int setSensorValue(const std::string& req, std::string& propertyValue);
 };
@@ -41,7 +43,7 @@
     public std::enable_shared_from_this<ChassisIntrusionPchSensor>
 {
   public:
-    ChassisIntrusionPchSensor(boost::asio::io_context& io,
+    ChassisIntrusionPchSensor(bool autoRearm, boost::asio::io_context& io,
                               sdbusplus::asio::object_server& objServer,
                               int busId, int slaveAddr);
 
@@ -60,7 +62,7 @@
     public std::enable_shared_from_this<ChassisIntrusionGpioSensor>
 {
   public:
-    ChassisIntrusionGpioSensor(boost::asio::io_context& io,
+    ChassisIntrusionGpioSensor(bool autoRearm, boost::asio::io_context& io,
                                sdbusplus::asio::object_server& objServer,
                                bool gpioInverted);
 
@@ -80,7 +82,7 @@
     public std::enable_shared_from_this<ChassisIntrusionHwmonSensor>
 {
   public:
-    ChassisIntrusionHwmonSensor(boost::asio::io_context& io,
+    ChassisIntrusionHwmonSensor(bool autoRearm, boost::asio::io_context& io,
                                 sdbusplus::asio::object_server& objServer,
                                 std::string hwmonName);
 
diff --git a/src/IntrusionSensorMain.cpp b/src/IntrusionSensorMain.cpp
index 3545233..dda9b6f 100644
--- a/src/IntrusionSensorMain.cpp
+++ b/src/IntrusionSensorMain.cpp
@@ -89,6 +89,20 @@
 
         baseConfiguration = &(*sensorBase);
 
+        // Rearm defaults to "Automatic" mode
+        bool autoRearm = true;
+        auto findRearm = baseConfiguration->second.find("Rearm");
+        if (findRearm != baseConfiguration->second.end())
+        {
+            std::string rearmStr = std::get<std::string>(findRearm->second);
+            if (rearmStr != "Automatic" && rearmStr != "Manual")
+            {
+                std::cerr << "Wrong input for Rearm parameter\n";
+                continue;
+            }
+            autoRearm = (rearmStr == "Automatic");
+        }
+
         // judge class, "Gpio", "Hwmon" or "I2C"
         auto findClass = baseConfiguration->second.find("Class");
         if (findClass != baseConfiguration->second.end())
@@ -112,7 +126,7 @@
                         (std::get<std::string>(findGpioPolarity->second) ==
                          "Low");
                     pSensor = std::make_shared<ChassisIntrusionGpioSensor>(
-                        io, objServer, gpioInverted);
+                        autoRearm, io, objServer, gpioInverted);
                     pSensor->start();
                     if (debug)
                     {
@@ -152,7 +166,7 @@
                 try
                 {
                     pSensor = std::make_shared<ChassisIntrusionHwmonSensor>(
-                        io, objServer, hwmonName);
+                        autoRearm, io, objServer, hwmonName);
                     pSensor->start();
                     return;
                 }
@@ -178,7 +192,7 @@
                     int busId = std::get<uint64_t>(findBus->second);
                     int slaveAddr = std::get<uint64_t>(findAddress->second);
                     pSensor = std::make_shared<ChassisIntrusionPchSensor>(
-                        io, objServer, busId, slaveAddr);
+                        autoRearm, io, objServer, busId, slaveAddr);
                     pSensor->start();
                     if (debug)
                     {