Implement command GetDateTime
This commit implements the GetDateTime command which is
defined in PLDM Bios Control and Configuration Specification.
Change-Id: Iced21bbad7be07d357b6885b1b1e03b07a3da165
Signed-off-by: Sampa Misra <sampmisr@in.ibm.com>
diff --git a/libpldmresponder/Makefile.am b/libpldmresponder/Makefile.am
index a9b1507..faa4934 100644
--- a/libpldmresponder/Makefile.am
+++ b/libpldmresponder/Makefile.am
@@ -1,12 +1,18 @@
libpldmresponder_LTLIBRARIES = libpldmresponder.la
libpldmresponderdir = ${libdir}
libpldmresponder_la_SOURCES = \
- base.cpp
+ base.cpp \
+ utils.cpp \
+ bios.cpp
libpldmresponder_la_LIBADD = \
../libpldm/libpldm.la \
$(CODE_COVERAGE_LIBS)
libpldmresponder_la_LDFLAGS = \
+ $(SDBUSPLUS_LIBS)
-version-info 1:0:0 -shared
-libpldmresponder_la_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS)
+libpldmresponder_la_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS) \
+ $(SDBUSPLUS_CFLAGS)
+
libpldmresponder_la_CPPFLAGS = $(CODE_COVERAGE_CPPFLAGS)
+
diff --git a/libpldmresponder/bios.cpp b/libpldmresponder/bios.cpp
new file mode 100644
index 0000000..dfd07b8
--- /dev/null
+++ b/libpldmresponder/bios.cpp
@@ -0,0 +1,99 @@
+#include "bios.hpp"
+
+#include "libpldmresponder/utils.hpp"
+#include "xyz/openbmc_project/Common/error.hpp"
+
+#include <array>
+#include <chrono>
+#include <ctime>
+#include <iostream>
+#include <phosphor-logging/elog-errors.hpp>
+#include <stdexcept>
+#include <string>
+#include <variant>
+#include <vector>
+
+namespace pldm
+{
+
+using namespace phosphor::logging;
+
+using EpochTimeUS = uint64_t;
+
+constexpr auto dbusProperties = "org.freedesktop.DBus.Properties";
+
+namespace responder
+{
+
+namespace utils
+{
+
+void epochToBCDTime(uint64_t timeSec, uint8_t& seconds, uint8_t& minutes,
+ uint8_t& hours, uint8_t& day, uint8_t& month,
+ uint16_t& year)
+{
+ auto t = time_t(timeSec);
+ auto time = localtime(&t);
+
+ seconds = decimalToBcd(time->tm_sec);
+ minutes = decimalToBcd(time->tm_min);
+ hours = decimalToBcd(time->tm_hour);
+ day = decimalToBcd(time->tm_mday);
+ month =
+ decimalToBcd(time->tm_mon + 1); // The number of months in the range
+ // 0 to 11.PLDM expects range 1 to 12
+ year = decimalToBcd(time->tm_year + 1900); // The number of years since 1900
+}
+
+} // namespace utils
+
+void getDateTime(const pldm_msg_payload* request, pldm_msg* response)
+{
+ uint8_t seconds = 0;
+ uint8_t minutes = 0;
+ uint8_t hours = 0;
+ uint8_t day = 0;
+ uint8_t month = 0;
+ uint16_t year = 0;
+
+ constexpr auto timeInterface = "xyz.openbmc_project.Time.EpochTime";
+ constexpr auto bmcTimePath = "/xyz/openbmc_project/time/bmc";
+ std::variant<EpochTimeUS> value;
+
+ auto bus = sdbusplus::bus::new_default();
+ try
+ {
+ auto service = getService(bus, bmcTimePath, timeInterface);
+
+ auto method = bus.new_method_call(service.c_str(), bmcTimePath,
+ dbusProperties, "Get");
+ method.append(timeInterface, "Elapsed");
+
+ auto reply = bus.call(method);
+ reply.read(value);
+ }
+
+ catch (std::exception& e)
+ {
+ log<level::ERR>("Error getting time", entry("PATH=%s", bmcTimePath),
+ entry("TIME INTERACE=%s", timeInterface));
+
+ encode_get_date_time_resp(0, PLDM_ERROR, seconds, minutes, hours, day,
+ month, year, response);
+ return;
+ }
+
+ uint64_t timeUsec = std::get<EpochTimeUS>(value);
+
+ uint64_t timeSec = std::chrono::duration_cast<std::chrono::seconds>(
+ std::chrono::microseconds(timeUsec))
+ .count();
+
+ utils::epochToBCDTime(timeSec, seconds, minutes, hours, day, month, year);
+
+ encode_get_date_time_resp(0, PLDM_SUCCESS, seconds, minutes, hours, day,
+ month, year, response);
+}
+
+} // namespace responder
+} // namespace pldm
diff --git a/libpldmresponder/bios.hpp b/libpldmresponder/bios.hpp
new file mode 100644
index 0000000..80a732b
--- /dev/null
+++ b/libpldmresponder/bios.hpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <stdint.h>
+
+#include "libpldm/bios.h"
+
+namespace pldm
+{
+
+namespace responder
+{
+
+/** @brief Handler for GetDateTime
+ *
+ * @param[in] request - Request message payload
+ * @param[out] response - Response message written here
+ */
+void getDateTime(const pldm_msg_payload* request, pldm_msg* response);
+
+namespace utils
+{
+
+/** @brief Convert epoch time to BCD time
+ *
+ * @param[in] timeSec - Time got from epoch time in seconds
+ * @param[out] seconds - number of seconds in BCD
+ * @param[out] minutes - number of minutes in BCD
+ * @param[out] hours - number of hours in BCD
+ * @param[out] day - day of the month in BCD
+ * @param[out] month - month number in BCD
+ * @param[out] year - year number in BCD
+ */
+void epochToBCDTime(uint64_t timeSec, uint8_t& seconds, uint8_t& minutes,
+ uint8_t& hours, uint8_t& day, uint8_t& month,
+ uint16_t& year);
+} // namespace utils
+
+} // namespace responder
+} // namespace pldm
diff --git a/libpldmresponder/utils.cpp b/libpldmresponder/utils.cpp
new file mode 100644
index 0000000..fe23223
--- /dev/null
+++ b/libpldmresponder/utils.cpp
@@ -0,0 +1,51 @@
+#include "utils.hpp"
+
+#include "xyz/openbmc_project/Common/error.hpp"
+
+#include <array>
+#include <ctime>
+#include <iostream>
+#include <map>
+#include <phosphor-logging/elog-errors.hpp>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+namespace pldm
+{
+using namespace phosphor::logging;
+
+constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
+constexpr auto mapperPath = "/xyz/openbmc_project/object_mapper";
+constexpr auto mapperInterface = "xyz.openbmc_project.ObjectMapper";
+
+namespace responder
+{
+
+std::string getService(sdbusplus::bus::bus& bus, const std::string& path,
+ const std::string& interface)
+{
+ using DbusInterfaceList = std::vector<std::string>;
+ std::map<std::string, std::vector<std::string>> mapperResponse;
+
+ try
+ {
+ auto mapper = bus.new_method_call(mapperBusName, mapperPath,
+ mapperInterface, "GetObject");
+ mapper.append(path, DbusInterfaceList({interface}));
+
+ auto mapperResponseMsg = bus.call(mapper);
+ mapperResponseMsg.read(mapperResponse);
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>("Error in mapper call", entry("ERROR=%s", e.what()),
+ entry("PATH=%s", path.c_str()),
+ entry("INTERFACE=%s", interface.c_str()));
+ throw;
+ }
+ return mapperResponse.begin()->first;
+}
+
+} // namespace responder
+} // namespace pldm
diff --git a/libpldmresponder/utils.hpp b/libpldmresponder/utils.hpp
new file mode 100644
index 0000000..d76b716
--- /dev/null
+++ b/libpldmresponder/utils.hpp
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <stdint.h>
+#include <systemd/sd-bus.h>
+
+#include <sdbusplus/server.hpp>
+#include <string>
+
+namespace pldm
+{
+namespace responder
+{
+
+/**
+ * @brief Get the DBUS Service name for the input dbus path
+ * @param[in] bus - DBUS Bus Object
+ * @param[in] path - DBUS object path
+ * @param[in] interface - DBUS Interface
+ * @return std::string - the dbus service name
+ */
+std::string getService(sdbusplus::bus::bus& bus, const std::string& path,
+ const std::string& interface);
+
+/** @brief Convert any Decimal number to BCD
+ *
+ * @tparam[in] decimal - Decimal number
+ * @return Corresponding BCD number
+ */
+template <typename T>
+T decimalToBcd(T decimal)
+{
+ T bcd = 0;
+ T rem = 0;
+ auto cnt = 0;
+
+ while (decimal)
+ {
+ rem = decimal % 10;
+ bcd = bcd + (rem << cnt);
+ decimal = decimal / 10;
+ cnt += 4;
+ }
+
+ return bcd;
+}
+
+} // namespace responder
+} // namespace pldm