Support event multi targets

Description:
- Support event multi targets.

Design:
- The origin multi-gpio-monitor doesn't detect the comming events are
  rising or falling and it can only start one service after events
  triggered.

- We need to do corresponding actions when gpio pin rising or falling.
  So we modify multi-gpio-monitor config json and read the rising
  actions and falling actions in it.

- When service monitored one gpio status is changed,
  service will detect that it is a rising or falling event and then
  call systemd startUnit to start services that set in config json.

- For example with config json below:
  When PowerGood is falling, "PowerGoodFalling.service"
  and "PowerOff.service" will start.
[
  {
	"Name": "PowerGood",
	"ChipId": "0",
	"GpioNum": 14,
	"EventMon": "BOTH",
	"Targets": {
	  "FALLING": ["PowerGoodFalling.service", "PowerOff.service"],
	  "RISING": ["PowerGoodRising.service", "PowerOn.service"]
	},
	"Continue": true
  }
]

Test Case:
Check that corresponding targets start or not - pass

Signed-off-by: Delphine CC Chiu <Delphine_CC_Chiu@wiwynn.com>
Change-Id: I043d4385b91a04d360a4d50048320db15e63ac74
diff --git a/README.md b/README.md
index 695cdf8..7851995 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,10 @@
 6. Target: This is an optional systemd service which will get started after
    triggering event. A journal entry will be added for every event occurs
    irrespective of this definition.
-7. Continue: This is a optional flag and if it is defined as true then this gpio
+7. Targets: This is an optional systemd service which will get started after
+   triggering corresponding event(RASING or FALLING). A journal entry will be
+   added for every event occurs irrespective of this definition.
+8. Continue: This is a optional flag and if it is defined as true then this gpio
    will be monitored continously. If not defined then monitoring of this gpio
    will stop after first event.
 
@@ -53,13 +56,18 @@
     "LineName": "POWER_BUTTON",
     "GpioNum": 34,
     "ChipId": "gpiochip0",
-    "EventMon": "BOTH",
+    "EventMon": "FALLING",
+    "Target": "PowerButtonDown.service",
     "Continue": true
   },
   {
     "Name": "PowerGood",
     "LineName": "PS_PWROK",
-    "EventMon": "FALLING",
+    "EventMon": "BOTH",
+    "Targets": {
+      "FALLING": ["PowerGoodFalling.service", "PowerOff.service"],
+      "RISING": ["PowerGoodRising.service", "PowerOn.service"]
+    },
     "Continue": false
   },
   { "Name": "SystemReset", "GpioNum": 46, "ChipId": "0" }
diff --git a/gpioMon.cpp b/gpioMon.cpp
index 2ab079a..fcdf8f5 100644
--- a/gpioMon.cpp
+++ b/gpioMon.cpp
@@ -29,6 +29,9 @@
 constexpr auto SYSTEMD_ROOT = "/org/freedesktop/systemd1";
 constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
 
+constexpr auto falling = "FALLING";
+constexpr auto rising = "RISING";
+
 using namespace phosphor::logging;
 
 void GpioMonitor::scheduleEventHandler()
@@ -79,6 +82,37 @@
         bus.call_noreply(method);
     }
 
+    std::vector<std::string> targetsToStart;
+    if (gpioLineEvent.event_type == GPIOD_LINE_EVENT_RISING_EDGE)
+    {
+        auto risingFind = targets.find(rising);
+        if (risingFind != targets.end())
+        {
+            targetsToStart = risingFind->second;
+        }
+    }
+    else
+    {
+        auto fallingFind = targets.find(falling);
+        if (fallingFind != targets.end())
+        {
+            targetsToStart = fallingFind->second;
+        }
+    }
+
+    /* Execute the multi targets if it is defined. */
+    if (!targetsToStart.empty())
+    {
+        auto bus = sdbusplus::bus::new_default();
+        for (auto& tar : targetsToStart)
+        {
+            auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT,
+                                              SYSTEMD_INTERFACE, "StartUnit");
+            method.append(tar, "replace");
+            bus.call_noreply(method);
+        }
+    }
+
     /* if not required to continue monitoring then return */
     if (!continueAfterEvent)
     {
diff --git a/gpioMon.hpp b/gpioMon.hpp
index 51772ab..5750d39 100644
--- a/gpioMon.hpp
+++ b/gpioMon.hpp
@@ -4,6 +4,8 @@
 
 #include <boost/asio/io_context.hpp>
 #include <boost/asio/posix/stream_descriptor.hpp>
+#include <map>
+#include <vector>
 
 namespace phosphor
 {
@@ -31,15 +33,18 @@
      *  @param[in] io          - io service
      *  @param[in] target      - systemd unit to be started on GPIO
      *                           value change
+     *  @param[in] targets     - systemd units to be started on GPIO
+     *                           value change
      *  @param[in] lineMsg     - GPIO line message to be used for log
      *  @param[in] continueRun - Whether to continue after event occur
      */
     GpioMonitor(gpiod_line* line, gpiod_line_request_config& config,
                 boost::asio::io_context& io, const std::string& target,
+                const std::map<std::string, std::vector<std::string>>& targets,
                 const std::string& lineMsg, bool continueRun) :
         gpioLine(line),
         gpioConfig(config), gpioEventDescriptor(io), target(target),
-        gpioLineMsg(lineMsg), continueAfterEvent(continueRun)
+        targets(targets), gpioLineMsg(lineMsg), continueAfterEvent(continueRun)
     {
         requestGPIOEvents();
     };
@@ -57,6 +62,9 @@
     /** @brief Systemd unit to be started when the condition is met */
     const std::string target;
 
+    /** @brief Multi systemd units to be started when the condition is met */
+    std::map<std::string, std::vector<std::string>> targets;
+
     /** @brief GPIO line name message */
     std::string gpioLineMsg;
 
diff --git a/gpioMonMain.cpp b/gpioMonMain.cpp
index bb30a8e..8530ffc 100644
--- a/gpioMonMain.cpp
+++ b/gpioMonMain.cpp
@@ -103,6 +103,9 @@
         /* target to start */
         std::string target;
 
+        /* multi targets to start */
+        std::map<std::string, std::vector<std::string>> targets;
+
         if (obj.find("LineName") == obj.end())
         {
             /* If there is no line Name defined then gpio num nd chip
@@ -173,9 +176,15 @@
             target = obj["Target"];
         }
 
+        /* Parse out the targets argument if multi-targets are needed.*/
+        if (obj.find("Targets") != obj.end())
+        {
+            obj.at("Targets").get_to(targets);
+        }
+
         /* Create a monitor object and let it do all the rest */
         gpios.push_back(std::make_unique<phosphor::gpio::GpioMonitor>(
-            line, config, io, target, lineMsg, flag));
+            line, config, io, target, targets, lineMsg, flag));
     }
     io.run();