Use BCD format timestamps

Tested: Unit tests, ran on GLP machine and checked decoded base64
encoded cper log https://paste.googleplex.com/5503804505325568#l=18
Google-Bug-Id: b/377739641
Change-Id: Idfeba55cf6f21ca8066fcbc555d6e30323f63289
Signed-off-by: Aryk Ledet <arykledet@google.com>
diff --git a/include/cper.hpp b/include/cper.hpp
index 8f0bbd9..500cf6e 100644
--- a/include/cper.hpp
+++ b/include/cper.hpp
@@ -170,15 +170,14 @@
                  const guid_t notificationTypeIn, uint64_t recordIdIn,
                  const uint32_t flagsIn,
                  const uint64_t setPersistenceInformationIn) :
-        signature(kRecordSignature),
-        revision(kRecordRevision), signatureEnd(kRecordSignatureEnd),
-        sectionCount(sectionCountIn), errorSeverity(errorSeverityIn),
-        validationBits(validationBitsIn), recordLength(recordLengthIn),
-        timestamp(timestampIn), platformId(platformIdIn),
-        partitionId(partitionIdIn), creatorId(creatorIdIn),
-        notificationType(notificationTypeIn), recordId(recordIdIn),
-        flags(flagsIn), persistenceInformation(setPersistenceInformationIn),
-        reserved({0})
+        signature(kRecordSignature), revision(kRecordRevision),
+        signatureEnd(kRecordSignatureEnd), sectionCount(sectionCountIn),
+        errorSeverity(errorSeverityIn), validationBits(validationBitsIn),
+        recordLength(recordLengthIn), timestamp(timestampIn),
+        platformId(platformIdIn), partitionId(partitionIdIn),
+        creatorId(creatorIdIn), notificationType(notificationTypeIn),
+        recordId(recordIdIn), flags(flagsIn),
+        persistenceInformation(setPersistenceInformationIn), reserved({0})
     {}
 };
 
@@ -238,10 +237,9 @@
                       const guid_t sectionTypeIn, const guid_t fruIdIn,
                       const uint32_t sectionSeverityIn,
                       const std::array<uint8_t, 20> fruTextIn) :
-        sectionOffset(sectionOffsetIn),
-        sectionLength(sectionLengthIn), revision(revisionIn),
-        validationBits(validationBitsIn), reserved(0), flags(flagsIn),
-        sectionType(sectionTypeIn), fruId(fruIdIn),
+        sectionOffset(sectionOffsetIn), sectionLength(sectionLengthIn),
+        revision(revisionIn), validationBits(validationBitsIn), reserved(0),
+        flags(flagsIn), sectionType(sectionTypeIn), fruId(fruIdIn),
         sectionSeverity(sectionSeverityIn), fruText(fruTextIn)
     {}
 };
diff --git a/include/cper_encoder.hpp b/include/cper_encoder.hpp
index 70d21cb..4258cf1 100644
--- a/include/cper_encoder.hpp
+++ b/include/cper_encoder.hpp
@@ -14,6 +14,21 @@
 concept ByteLike = std::is_trivially_copyable_v<T> && sizeof(T) == 1;
 
 /**
+ * @brief Helper function to convert time values into BCD format.
+ *
+ * @example You may have minutes represented as base10 20 which is 0x14. BCD
+ * expects the values to be represented as 0x20.
+ *
+ * @param[in] val - The value to convert to BCD.
+ *
+ * @returns a byte with the BCD val.
+ */
+uint8_t convertToBcd(uint8_t val)
+{
+    return (0x10 * (val / 10)) + (val % 10);
+}
+
+/**
  * @brief Helper function to create a UTC UEFI CPER timestamp from a
  * std::chrono time point.
  * https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#record-header
@@ -47,9 +62,16 @@
     const uint8_t year = calendarYear % kCentury;
     const uint8_t century = calendarYear / kCentury;
 
-    const Timestamp timestamp(utcTime.tm_sec, utcTime.tm_min, utcTime.tm_hour,
-                              isPreciseBit, utcTime.tm_mday, utcTime.tm_mon,
-                              year, century);
+    const Timestamp timestamp{
+        .seconds = convertToBcd(utcTime.tm_sec),
+        .minutes = convertToBcd(utcTime.tm_min),
+        .hours = convertToBcd(utcTime.tm_hour),
+        .isPrecise = isPreciseBit,
+        .day = convertToBcd(utcTime.tm_mday),
+        // tm_mon is months since January, add one to get current month.
+        .month = convertToBcd(utcTime.tm_mon + 1),
+        .year = convertToBcd(year),
+        .century = convertToBcd(century)};
 
     uint64_t ret;
     memcpy(&ret, &timestamp, sizeof(ret));
diff --git a/include/guid.hpp b/include/guid.hpp
index f734161..6bd692d 100644
--- a/include/guid.hpp
+++ b/include/guid.hpp
@@ -22,8 +22,8 @@
     constexpr Guid(const uint32_t timeLowIn, const uint16_t timeMidIn,
                    const uint16_t timeHiAndVersionIn,
                    const std::array<uint8_t, 8> bytesIn) :
-        timeLow(timeLowIn),
-        timeMid(timeMidIn), timeHiAndVersion(timeHiAndVersionIn), bytes(bytesIn)
+        timeLow(timeLowIn), timeMid(timeMidIn),
+        timeHiAndVersion(timeHiAndVersionIn), bytes(bytesIn)
     {}
 
     constexpr bool operator==(const Guid& rhs) const
diff --git a/meson.build b/meson.build
index 0e06631..1003aba 100644
--- a/meson.build
+++ b/meson.build
@@ -27,6 +27,6 @@
     description: 'Utilities for easily creating CPER logs'
 )
 
-if get_option('tests').enabled()
+if get_option('tests').allowed()
     subdir('test')
 endif
diff --git a/meson.options b/meson.options
index b6cb722..92f99ae 100644
--- a/meson.options
+++ b/meson.options
@@ -1 +1 @@
-option('tests', type: 'feature', value: 'auto', description: 'Build tests')
+option('tests', type: 'feature', value: 'disabled', description: 'Build tests')
diff --git a/test/cper_encoder_test.cpp b/test/cper_encoder_test.cpp
index 0f3a74e..78e6000 100644
--- a/test/cper_encoder_test.cpp
+++ b/test/cper_encoder_test.cpp
@@ -16,6 +16,17 @@
 concept StringOrVector =
     std::is_same_v<T, std::string> || std::is_same_v<T, std::vector<uint8_t>>;
 
+uint8_t bcdToDecimal(const uint8_t bcd)
+{
+    uint8_t tens = bcd >> 4;
+    uint8_t ones = bcd & 0x0F;
+    if (ones > 9 || tens > 9)
+    {
+        return 0;
+    }
+    return (tens * 10) + ones;
+}
+
 class CperEncoderTest : public testing::Test
 {
   public:
@@ -111,6 +122,14 @@
         Timestamp structTimestamp;
         memcpy(&structTimestamp, &cperTimestamp, sizeof(structTimestamp));
 
+        structTimestamp.seconds = bcdToDecimal(structTimestamp.seconds);
+        structTimestamp.minutes = bcdToDecimal(structTimestamp.minutes);
+        structTimestamp.hours = bcdToDecimal(structTimestamp.hours);
+        structTimestamp.day = bcdToDecimal(structTimestamp.day);
+        structTimestamp.month = bcdToDecimal(structTimestamp.month) - 1;
+        structTimestamp.year = bcdToDecimal(structTimestamp.year);
+        structTimestamp.century = bcdToDecimal(structTimestamp.century);
+
         time_t tt = std::chrono::system_clock::to_time_t(ref);
         tm utcTime = *gmtime(&tt);