diff options
author | Matt Spinler <spinler@us.ibm.com> | 2019-07-09 15:39:51 -0500 |
---|---|---|
committer | Matt Spinler <spinler@us.ibm.com> | 2019-07-26 12:58:40 -0500 |
commit | df797f2b865c79f4bdb2a0889bc32cc681eecaa8 (patch) | |
tree | c3597f9f4990aced51e6ce972ec6b923d6f5f472 | |
parent | 113ad28c9a94612fe199fe5e85cf007e1abf254c (diff) | |
download | phosphor-logging-df797f2b865c79f4bdb2a0889bc32cc681eecaa8.tar.gz phosphor-logging-df797f2b865c79f4bdb2a0889bc32cc681eecaa8.zip |
PEL: Add BCD time helpers for PELs
A PEL stores time in BCD, with a byte each for:
* year MSB
* year LSB
* month
* day
* hour
* minutes
* seconds
* hundredths
This commit adds a structure to represent this, and functions to:
* Create a BCD structure from a std::chrono::time_point
* Convert any number to BCD
* Write the BCD structure into a Stream
* Extract a BCD structure from a Stream
Refresher: The BCD value of 32 is 0x32.
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I09ea4098f3a3981931f595d11fb63aff31d9fb0d
-rw-r--r-- | extensions/openpower-pels/bcd_time.cpp | 61 | ||||
-rw-r--r-- | extensions/openpower-pels/bcd_time.hpp | 88 | ||||
-rw-r--r-- | extensions/openpower-pels/openpower-pels.mk | 1 | ||||
-rw-r--r-- | test/openpower-pels/Makefile.include | 12 | ||||
-rw-r--r-- | test/openpower-pels/bcd_time_test.cpp | 80 |
5 files changed, 241 insertions, 1 deletions
diff --git a/extensions/openpower-pels/bcd_time.cpp b/extensions/openpower-pels/bcd_time.cpp new file mode 100644 index 0000000..bb80f1a --- /dev/null +++ b/extensions/openpower-pels/bcd_time.cpp @@ -0,0 +1,61 @@ +#include "bcd_time.hpp" + +namespace openpower +{ +namespace pels +{ + +bool BCDTime::operator==(const BCDTime& right) const +{ + return (yearMSB == right.yearMSB) && (yearLSB == right.yearLSB) && + (month == right.month) && (day == right.day) && + (hour == right.hour) && (minutes == right.minutes) && + (seconds == right.seconds) && (hundredths == right.hundredths); +} + +bool BCDTime::operator!=(const BCDTime& right) const +{ + return !(*this == right); +} + +BCDTime getBCDTime(std::chrono::time_point<std::chrono::system_clock>& time) +{ + BCDTime bcd; + + using namespace std::chrono; + time_t t = system_clock::to_time_t(time); + tm* localTime = localtime(&t); + assert(localTime != nullptr); + + int year = 1900 + localTime->tm_year; + bcd.yearMSB = toBCD(year / 100); + bcd.yearLSB = toBCD(year % 100); + bcd.month = toBCD(localTime->tm_mon + 1); + bcd.day = toBCD(localTime->tm_mday); + bcd.hour = toBCD(localTime->tm_hour); + bcd.minutes = toBCD(localTime->tm_min); + bcd.seconds = toBCD(localTime->tm_sec); + + auto ms = duration_cast<milliseconds>(time.time_since_epoch()).count(); + int hundredths = (ms % 1000) / 10; + bcd.hundredths = toBCD(hundredths); + + return bcd; +} + +Stream& operator>>(Stream& s, BCDTime& time) +{ + s >> time.yearMSB >> time.yearLSB >> time.month >> time.day >> time.hour; + s >> time.minutes >> time.seconds >> time.hundredths; + return s; +} + +Stream& operator<<(Stream& s, BCDTime& time) +{ + s << time.yearMSB << time.yearLSB << time.month << time.day << time.hour; + s << time.minutes << time.seconds << time.hundredths; + return s; +} + +} // namespace pels +} // namespace openpower diff --git a/extensions/openpower-pels/bcd_time.hpp b/extensions/openpower-pels/bcd_time.hpp new file mode 100644 index 0000000..e218756 --- /dev/null +++ b/extensions/openpower-pels/bcd_time.hpp @@ -0,0 +1,88 @@ +#pragma once +#include "stream.hpp" + +#include <chrono> + +namespace openpower +{ +namespace pels +{ + +/** + * @brief A structure that contains a PEL timestamp in BCD. + */ +struct BCDTime +{ + uint8_t yearMSB; + uint8_t yearLSB; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minutes; + uint8_t seconds; + uint8_t hundredths; + + bool operator==(const BCDTime& right) const; + bool operator!=(const BCDTime& right) const; + +} __attribute__((packed)); + +/** + * @brief Converts a time_point into a BCD time + * + * @param[in] time - the time_point to convert + * @return BCDTime - the BCD time + */ +BCDTime getBCDTime(std::chrono::time_point<std::chrono::system_clock>& time); + +/** + * @brief Converts a number to a BCD. + * + * For example 32 -> 0x32. + * + * Source: PLDM repository + * + * @param[in] value - the value to convert. + * + * @return T - the BCD value + */ +template <typename T> +T toBCD(T decimal) +{ + T bcd = 0; + T remainder = 0; + auto count = 0; + + while (decimal) + { + remainder = decimal % 10; + bcd = bcd + (remainder << count); + decimal = decimal / 10; + count += 4; + } + + return bcd; +} + +/** + * @brief Stream extraction operator for BCDTime + * + * @param[in] s - the Stream + * @param[out] time - the BCD time + * + * @return Stream& + */ +Stream& operator>>(Stream& s, BCDTime& time); + +/** + * @brief Stream insertion operator for BCDTime + * + * @param[in/out] s - the Stream + * @param[in] time - the BCD time + * + * @return Stream& + */ +Stream& operator<<(Stream& s, BCDTime& time); + +} // namespace pels +} // namespace openpower diff --git a/extensions/openpower-pels/openpower-pels.mk b/extensions/openpower-pels/openpower-pels.mk index 1030171..94c7bb8 100644 --- a/extensions/openpower-pels/openpower-pels.mk +++ b/extensions/openpower-pels/openpower-pels.mk @@ -1,4 +1,5 @@ phosphor_log_manager_SOURCES += \ + extensions/openpower-pels/bcd_time.cpp \ extensions/openpower-pels/entry_points.cpp \ extensions/openpower-pels/manager.cpp diff --git a/test/openpower-pels/Makefile.include b/test/openpower-pels/Makefile.include index 295069a..a68b229 100644 --- a/test/openpower-pels/Makefile.include +++ b/test/openpower-pels/Makefile.include @@ -2,6 +2,7 @@ TESTS += $(check_PROGRAMS) check_PROGRAMS += \ additional_data_test \ + bcd_time_test \ stream_test additional_data_test_SOURCES = %reldir%/additional_data_test.cpp @@ -14,4 +15,13 @@ stream_test_SOURCES = %reldir%/stream_test.cpp stream_test_CPPFLAGS = $(test_cppflags) stream_test_CXXFLAGS = $(test_cxxflags) stream_test_LDADD = $(test_ldadd) -stream_test_LDFLAGS = $(test_ldflags)
\ No newline at end of file +stream_test_LDFLAGS = $(test_ldflags) + +bcd_time_test_SOURCES = \ + %reldir%/bcd_time_test.cpp +bcd_time_test_CPPFLAGS = $(test_cppflags) +bcd_time_test_CXXFLAGS = $(test_cxxflags) +bcd_time_test_LDADD = \ + $(test_ldadd) \ + $(top_builddir)/extensions/openpower-pels/bcd_time.o +bcd_time_test_LDFLAGS = $(test_ldflags)
\ No newline at end of file diff --git a/test/openpower-pels/bcd_time_test.cpp b/test/openpower-pels/bcd_time_test.cpp new file mode 100644 index 0000000..f1b7663 --- /dev/null +++ b/test/openpower-pels/bcd_time_test.cpp @@ -0,0 +1,80 @@ +#include "extensions/openpower-pels/bcd_time.hpp" + +#include <gtest/gtest.h> + +using namespace openpower::pels; + +TEST(BCDTimeTest, ToBCDTest) +{ + EXPECT_EQ(toBCD(0), 0x00); + EXPECT_EQ(toBCD(1), 0x01); + EXPECT_EQ(toBCD(10), 0x10); + EXPECT_EQ(toBCD(99), 0x99); + EXPECT_EQ(toBCD(37), 0x37); + EXPECT_EQ(toBCD(60), 0x60); + EXPECT_EQ(toBCD(12345678), 0x12345678); + EXPECT_EQ(toBCD(0xF), 0x15); +} + +TEST(BCDTimeTest, FlattenUnflattenTest) +{ + std::vector<uint8_t> data{1, 2, 3, 4, 5, 6, 7, 8}; + Stream stream{data}; + BCDTime bcd; + + // Unflatten + stream >> bcd; + + EXPECT_EQ(bcd.yearMSB, 1); + EXPECT_EQ(bcd.yearLSB, 2); + EXPECT_EQ(bcd.month, 3); + EXPECT_EQ(bcd.day, 4); + EXPECT_EQ(bcd.hour, 5); + EXPECT_EQ(bcd.minutes, 6); + EXPECT_EQ(bcd.seconds, 7); + EXPECT_EQ(bcd.hundredths, 8); + + // Flatten + uint8_t val = 0x20; + bcd.yearMSB = val++; + bcd.yearLSB = val++; + bcd.month = val++; + bcd.day = val++; + bcd.hour = val++; + bcd.minutes = val++; + bcd.seconds = val++; + bcd.hundredths = val++; + + stream.offset(0); + stream << bcd; + + for (size_t i = 0; i < 8; i++) + { + EXPECT_EQ(data[i], 0x20 + i); + } +} + +TEST(BCDTimeTest, ConvertTest) +{ + // Convert a time_point into BCDTime + tm time_tm; + time_tm.tm_year = 125; + time_tm.tm_mon = 11; + time_tm.tm_mday = 31; + time_tm.tm_hour = 15; + time_tm.tm_min = 23; + time_tm.tm_sec = 42; + time_tm.tm_isdst = 0; + + auto timepoint = std::chrono::system_clock::from_time_t(mktime(&time_tm)); + auto timeInBCD = getBCDTime(timepoint); + + EXPECT_EQ(timeInBCD.yearMSB, 0x20); + EXPECT_EQ(timeInBCD.yearLSB, 0x25); + EXPECT_EQ(timeInBCD.month, 0x12); + EXPECT_EQ(timeInBCD.day, 0x31); + EXPECT_EQ(timeInBCD.hour, 0x15); + EXPECT_EQ(timeInBCD.minutes, 0x23); + EXPECT_EQ(timeInBCD.seconds, 0x42); + EXPECT_EQ(timeInBCD.hundredths, 0x00); +} |