libpldmresponder: bios: Add SetDataTime

Implement the time setting function based on decode requests,
set values and return responses.
It contains the error response.
Unit tests only include tests for numerical conversion.

Tested:
 ~# pldmtool bios SetDateTime -d 20200101080000
 Encode request successfully
 Request Message:
 08 01 80 03 0d 00 00 08 01 01 20 20
 On first recv(),response == request : RC = 0
 Total length: 6
 Shutdown Socket successful :  RC = 0
 Response Message:
 08 01 00 03 0d 00
 Set date time successfully.

 ~# busctl get-property xyz.openbmc_project.Time.Manager\
 /xyz/openbmc_project/time/host\
 xyz.openbmc_project.Time.EpochTime Elapsed

 t 1577865726549597

The value of epochtime matches the time entered.

Signed-off-by: Xiaochao Ma <maxiaochao@inspur.com>
Change-Id: I8d123b993d515bcadba1468974907eb56d7e98b9
diff --git a/libpldmresponder/bios.cpp b/libpldmresponder/bios.cpp
index 8b18333..13b36ab 100644
--- a/libpldmresponder/bios.cpp
+++ b/libpldmresponder/bios.cpp
@@ -3,6 +3,8 @@
 #include "utils.hpp"
 #include "xyz/openbmc_project/Common/error.hpp"
 
+#include <time.h>
+
 #include <array>
 #include <boost/crc.hpp>
 #include <chrono>
@@ -59,6 +61,24 @@
                                      1900); // The number of years since 1900
 }
 
+std::time_t timeToEpoch(uint8_t seconds, uint8_t minutes, uint8_t hours,
+                        uint8_t day, uint8_t month, uint16_t year)
+{
+    struct std::tm stm;
+
+    stm.tm_year = year - 1900;
+    stm.tm_mon = month - 1;
+    stm.tm_mday = day;
+    stm.tm_hour = hours;
+    stm.tm_min = minutes;
+    stm.tm_sec = seconds;
+    stm.tm_isdst = -1;
+
+    // It will get the time in seconds since
+    // Epoch, 1970.1.1 00:00:00 +0000,UTC.
+    return timegm(&stm);
+}
+
 size_t getTableTotalsize(size_t sizeWithoutPad)
 {
     return sizeWithoutPad + pldm_bios_table_pad_checksum_size(sizeWithoutPad);
@@ -93,7 +113,10 @@
     catch (const std::exception& e)
     {
     }
-
+    handlers.emplace(PLDM_SET_DATE_TIME,
+                     [this](const pldm_msg* request, size_t payloadLength) {
+                         return this->setDateTime(request, payloadLength);
+                     });
     handlers.emplace(PLDM_GET_DATE_TIME,
                      [this](const pldm_msg* request, size_t payloadLength) {
                          return this->getDateTime(request, payloadLength);
@@ -155,6 +178,50 @@
     return response;
 }
 
+Response Handler::setDateTime(const pldm_msg* request, size_t payloadLength)
+{
+    uint8_t seconds = 0;
+    uint8_t minutes = 0;
+    uint8_t hours = 0;
+    uint8_t day = 0;
+    uint8_t month = 0;
+    uint16_t year = 0;
+    std::time_t timeSec;
+
+    constexpr auto setTimeInterface = "xyz.openbmc_project.Time.EpochTime";
+    constexpr auto setTimePath = "/xyz/openbmc_project/time/host";
+    constexpr auto timeSetPro = "Elapsed";
+
+    auto rc = decode_set_date_time_req(request, payloadLength, &seconds,
+                                       &minutes, &hours, &day, &month, &year);
+    if (rc != PLDM_SUCCESS)
+    {
+        return ccOnlyResponse(request, rc);
+    }
+    timeSec = pldm::responder::utils::timeToEpoch(seconds, minutes, hours, day,
+                                                  month, year);
+    uint64_t timeUsec = std::chrono::duration_cast<std::chrono::microseconds>(
+                            std::chrono::seconds(timeSec))
+                            .count();
+    std::variant<uint64_t> value{timeUsec};
+    try
+    {
+        pldm::utils::DBusHandler().setDbusProperty(setTimePath, timeSetPro,
+                                                   setTimeInterface, value);
+    }
+    catch (std::exception& e)
+    {
+
+        std::cerr << "Error Setting time,PATH=" << setTimePath
+                  << "TIME INTERFACE=" << setTimeInterface
+                  << "ERROR=" << e.what() << "\n";
+
+        return ccOnlyResponse(request, PLDM_ERROR);
+    }
+
+    return ccOnlyResponse(request, PLDM_SUCCESS);
+}
+
 /** @brief Construct the BIOS string table
  *
  *  @param[in] BIOSStringTable - the string table