Attn: Add support for raw pel symptom-id

Update raw pel symptom-id based on TI info data.

Signed-off-by: Ben Tyner <ben.tyner@ibm.com>
Change-Id: I501938e0fc9dba189999ab1491d23acd15628068
diff --git a/attn/attn_logging.cpp b/attn/attn_logging.cpp
index 3395c19..a9be924 100644
--- a/attn/attn_logging.cpp
+++ b/attn/attn_logging.cpp
@@ -235,6 +235,21 @@
                        std::min(srcString.size(), pel::asciiStringSize), 0);
 
         tiPel->setAsciiString(srcChars); // pel object src is char array
+
+        // set symptom-id
+        auto symptomId = (i_additional["SrcAscii"].substr(0, 8) + '_');
+
+        symptomId += (i_additional["0x10 SRC Word 12"]);
+        symptomId += (i_additional["0x14 SRC Word 13"] + '_');
+        symptomId += (i_additional["0x18 SRC Word 14"]);
+        symptomId += (i_additional["0x1c SRC Word 15"] + '_');
+        symptomId += (i_additional["0x20 SRC Word 16"]);
+        symptomId += (i_additional["0x24 SRC Word 17"] + '_');
+        symptomId += (i_additional["0x28 SRC Word 18"]);
+        symptomId += (i_additional["0x2c SRC Word 19"]);
+
+        // setSymptomId will take care of required null-terminate and padding
+        tiPel->setSymptomId(symptomId);
     }
     else
     {
@@ -265,6 +280,21 @@
                        std::min(srcString.size(), pel::asciiStringSize), 0);
 
         tiPel->setAsciiString(srcChars); // pel object src is char array
+
+        // set symptom-id
+        auto symptomId = (i_additional["SrcAscii"].substr(0, 8) + '_');
+
+        symptomId += (i_additional["0x10 HB Word 0"]);       // note: word 1
+        symptomId += (i_additional["0x14 HB Word 2"] + '_'); // does not exist
+        symptomId += (i_additional["0x18 HB Word 3"]);
+        symptomId += (i_additional["0x1c HB Word 4"] + '_');
+        symptomId += (i_additional["0x20 HB Word 5"]);
+        symptomId += (i_additional["0x24 HB Word 6"] + '_');
+        symptomId += (i_additional["0x28 HB Word 7"]);
+        symptomId += (i_additional["0x2c HB Word 8"]);
+
+        // setSymptomId will take care of required null-terminate and padding
+        tiPel->setSymptomId(symptomId);
     }
 
     // set severity, event type and action flags
diff --git a/attn/meson.build b/attn/meson.build
index f6fdd56..3b085af 100644
--- a/attn/meson.build
+++ b/attn/meson.build
@@ -40,6 +40,7 @@
 
 # for custom/raw PEL creation
 pel_src = files(
+    'pel/extended_user_header.cpp',
     'pel/pel_minimal.cpp',
     'pel/private_header.cpp',
     'pel/primary_src.cpp',
diff --git a/attn/pel/extended_user_header.cpp b/attn/pel/extended_user_header.cpp
new file mode 100644
index 0000000..117ca62
--- /dev/null
+++ b/attn/pel/extended_user_header.cpp
@@ -0,0 +1,59 @@
+#include "extended_user_header.hpp"
+
+namespace attn
+{
+namespace pel
+{
+
+ExtendedUserHeader::ExtendedUserHeader(Stream& pel)
+{
+    unflatten(pel);
+}
+
+void ExtendedUserHeader::flatten(Stream& pel) const
+{
+    pel << _header;
+    pel.write(_mtms, mtmsSize);
+    pel.write(_serverFWVersion.data(), _serverFWVersion.size());
+    pel.write(_subsystemFWVersion.data(), _subsystemFWVersion.size());
+    pel << _reserved4B << _refTime << _reserved1B1 << _reserved1B2
+        << _reserved1B3 << _symptomIdSize << _symptomId;
+}
+
+void ExtendedUserHeader::unflatten(Stream& pel)
+{
+    pel >> _header;
+    pel.read(_mtms, mtmsSize);
+    pel.read(_serverFWVersion.data(), _serverFWVersion.size());
+    pel.read(_subsystemFWVersion.data(), _subsystemFWVersion.size());
+    pel >> _reserved4B >> _refTime >> _reserved1B1 >> _reserved1B2 >>
+        _reserved1B3 >> _symptomIdSize >> _symptomId;
+
+    //_symptomId.resize(_symptomIdSize);
+    pel >> _symptomId;
+}
+
+void ExtendedUserHeader::setSymptomId(const std::string& symptomId)
+{
+    // set symptomId to new symptomId
+    std::copy(symptomId.begin(), symptomId.end(),
+              std::back_inserter(_symptomId));
+
+    // new symptom Id cannot be larger than existing symptom Id
+    if (_symptomId.size() > size_t((_symptomIdSize - 1)))
+    {
+        _symptomId.resize(_symptomIdSize - 1);
+    }
+
+    // null terminate new symptom Id (it may have been smaller)
+    _symptomId.push_back(0);
+
+    // pad if new symptom ID (it may have been smaller)
+    while ((_symptomId.size() != _symptomIdSize))
+    {
+        _symptomId.push_back(0);
+    }
+}
+
+} // namespace pel
+} // namespace attn
diff --git a/attn/pel/extended_user_header.hpp b/attn/pel/extended_user_header.hpp
new file mode 100644
index 0000000..d6486f1
--- /dev/null
+++ b/attn/pel/extended_user_header.hpp
@@ -0,0 +1,164 @@
+#pragma once
+
+#include "pel_common.hpp"
+#include "pel_section.hpp"
+#include "stream.hpp"
+
+namespace attn
+{
+namespace pel
+{
+
+constexpr uint8_t extendedUserHeaderVersion = 0x01;
+constexpr size_t firmwareVersionSize        = 16;
+
+/**
+ * @class ExtendedUserHeader
+ *
+ * This represents the Extended User Header section in a PEL
+ *
+ * |----------+---------------------------+-------+-------+-------------------|
+ * | length   | byte0                     | byte1 | byte2 | byte3             |
+ * |----------+---------------------------+-------+-------+-------------------|
+ * | 8        | Section Header                                                |
+ * |----------+---------------------------------------------------------------|
+ * | 20       | Machine Type/Model/Serial                                     |
+ * |----------+---------------------------------------------------------------|
+ * | 16       | FW Released Version                                           |
+ * |----------+---------------------------------------------------------------|
+ * | 16       | FW Sub-system driver ver.                                     |
+ * |----------+---------------------------+-------+-------+-------------------|
+ * | 4        | Reserved                  | rsvd  | rsvd  | Symptom ID length |
+ * |----------+---------------------------+-------+-------+-------------------|
+ * | 8        | Event Common Reference Time                                   |
+ * |----------+---------------------------------------------------------------|
+ * | 4        | Reserved                                                      |
+ * |----------+---------------------------------------------------------------|
+ * | variable | Symptom ID                                                    |
+ * |----------+---------------------------------------------------------------|
+ *
+ */
+class ExtendedUserHeader : public Section
+{
+  public:
+    ExtendedUserHeader()                          = delete;
+    ~ExtendedUserHeader()                         = default;
+    ExtendedUserHeader(const ExtendedUserHeader&) = default;
+    ExtendedUserHeader& operator=(const ExtendedUserHeader&) = default;
+    ExtendedUserHeader(ExtendedUserHeader&&)                 = default;
+    ExtendedUserHeader& operator=(ExtendedUserHeader&&) = default;
+
+    /**
+     * @brief Constructor
+     *
+     * Fills in this class's data fields from raw data.
+     *
+     * @param[in] pel - the PEL data stream
+     */
+    explicit ExtendedUserHeader(Stream& pel);
+
+    /**
+     * @brief Flatten the section into the stream
+     *
+     * @param[in] stream - The stream to write to
+     */
+    void flatten(Stream& stream) const override;
+
+    /**
+     * @brief Fills in the object from the stream data
+     *
+     * @param[in] stream - The stream to read from
+     */
+    void unflatten(Stream& stream);
+
+    /**
+     * @brief Returns the size of this section when flattened into a PEL
+     *
+     * @return size_t - the size of the section
+     */
+    size_t flattenedSize()
+    {
+        return Section::flattenedSize() + mtmsSize + _serverFWVersion.size() +
+               _subsystemFWVersion.size() + sizeof(_reserved4B) +
+               sizeof(_refTime) + sizeof(_reserved1B1) + sizeof(_reserved1B2) +
+               sizeof(_reserved1B3) + sizeof(_symptomIdSize) + _symptomIdSize;
+    }
+
+    /**
+     * @brief Set the symptom id field in extended user header
+     *
+     * @param[in] symptomId - The symptom ID to set
+     */
+    void setSymptomId(const std::string& symptomId);
+
+  private:
+    /**
+     * @brief The structure that holds the machine TM and SN fields.
+     */
+    uint8_t _mtms[mtmsSize];
+
+    /**
+     * @brief The server firmware version
+     *
+     * NULL terminated.
+     *
+     * The release version of the full firmware image.
+     */
+    std::array<uint8_t, firmwareVersionSize> _serverFWVersion;
+
+    /**
+     * @brief The subsystem firmware version
+     *
+     * NULL terminated.
+     *
+     * On PELs created on the BMC, this will be the BMC code version.
+     */
+    std::array<uint8_t, firmwareVersionSize> _subsystemFWVersion;
+
+    /**
+     * @brief Reserved
+     */
+    uint32_t _reserved4B = 0;
+
+    /**
+     * @brief Event Common Reference Time
+     *
+     * This is not used by PELs created on the BMC.
+     */
+    uint64_t _refTime;
+
+    /**
+     * @brief Reserved
+     */
+    uint8_t _reserved1B1 = 0;
+
+    /**
+     * @brief Reserved
+     */
+    uint8_t _reserved1B2 = 0;
+
+    /**
+     * @brief Reserved
+     */
+    uint8_t _reserved1B3 = 0;
+
+    /**
+     * @brief The size of the symptom ID field
+     */
+    uint8_t _symptomIdSize;
+
+    /**
+     * @brief The symptom ID field
+     *
+     * Describes a unique event signature for the log.
+     * Required for serviceable events, otherwise optional.
+     * When present, must start with the first 8 characters
+     * of the ASCII string field from the SRC.
+     *
+     * NULL terminated.
+     */
+    std::vector<uint8_t> _symptomId;
+};
+
+} // namespace pel
+} // namespace attn
diff --git a/attn/pel/pel_common.hpp b/attn/pel/pel_common.hpp
index d0f3e15..3dbce5c 100644
--- a/attn/pel/pel_common.hpp
+++ b/attn/pel/pel_common.hpp
@@ -9,9 +9,10 @@
 
 enum class SectionID
 {
-    privateHeader = 0x5048, // 'PH'
-    userHeader    = 0x5548, // 'UH'
-    primarySRC    = 0x5053, // 'PS'
+    privateHeader  = 0x5048, // 'PH'
+    userHeader     = 0x5548, // 'UH'
+    primarySRC     = 0x5053, // 'PS'
+    extendedHeader = 0x4548, // 'EH'
 };
 
 enum class ComponentID
@@ -64,6 +65,7 @@
 
 constexpr size_t numSrcWords = 8;  // number of SRC hex words
 const size_t asciiStringSize = 32; // size of SRC ascii string
+const size_t mtmsSize        = 20; // size of an mtms field
 
 } // namespace pel
 } // namespace attn
diff --git a/attn/pel/pel_minimal.cpp b/attn/pel/pel_minimal.cpp
index 9d7dfc1..11f589f 100644
--- a/attn/pel/pel_minimal.cpp
+++ b/attn/pel/pel_minimal.cpp
@@ -14,6 +14,7 @@
     _ph = std::make_unique<PrivateHeader>(pelData);
     _uh = std::make_unique<UserHeader>(pelData);
     _ps = std::make_unique<PrimarySrc>(pelData);
+    _eh = std::make_unique<ExtendedUserHeader>(pelData);
 }
 
 void PelMinimal::raw(std::vector<uint8_t>& pelBuffer) const
@@ -24,6 +25,7 @@
     _ph->flatten(pelData);
     _uh->flatten(pelData);
     _ps->flatten(pelData);
+    _eh->flatten(pelData);
 }
 
 size_t PelMinimal::size() const
@@ -48,6 +50,12 @@
         size += _ph->header().size;
     }
 
+    // size of extended user section
+    if (_eh)
+    {
+        size += _eh->header().size;
+    }
+
     return ((size > _maxPELSize) ? _maxPELSize : size);
 }
 
@@ -91,5 +99,10 @@
     _ph->setSectionCount(sectionCount);
 }
 
+void PelMinimal::setSymptomId(const std::string& symptomId)
+{
+    _eh->setSymptomId(symptomId);
+}
+
 } // namespace pel
 } // namespace attn
diff --git a/attn/pel/pel_minimal.hpp b/attn/pel/pel_minimal.hpp
index 79c0c11..ad07ab3 100644
--- a/attn/pel/pel_minimal.hpp
+++ b/attn/pel/pel_minimal.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "extended_user_header.hpp"
 #include "pel_common.hpp"
 #include "primary_src.hpp"
 #include "private_header.hpp"
@@ -30,6 +31,8 @@
  * |----------+------------------------------|
  * | 72       | Primary SRC Section          |
  * |----------+------------------------------|
+ * | 20       | Extended User Header         |
+ * |----------+------------------------------|
  */
 class PelMinimal
 {
@@ -111,6 +114,13 @@
      */
     void setSectionCount(uint8_t sectionCount);
 
+    /**
+     * @brief Set the symptom id field in extended user header
+     *
+     * @param[in] symptomId - The symptom ID to set
+     */
+    void setSymptomId(const std::string& symptomId);
+
   private:
     /**
      * @brief Maximum PEL size
@@ -138,6 +148,11 @@
      * @brief PEL Primary SRC
      */
     std::unique_ptr<PrimarySrc> _ps;
+
+    /**
+     * @brief PEL Extended User Header
+     */
+    std::unique_ptr<ExtendedUserHeader> _eh;
 };
 
 } // namespace pel
diff --git a/attn/ti_handler.cpp b/attn/ti_handler.cpp
index 8b8fa7d..fc546c4 100644
--- a/attn/ti_handler.cpp
+++ b/attn/ti_handler.cpp
@@ -274,37 +274,66 @@
 
     std::stringstream ss;
 
-    ss << std::hex << std::showbase;
-    ss << "0x00 TI Area Valid:" << (int)i_tiDataArea->tiAreaValid << ":";
-    ss << "0x01 Command:" << (int)i_tiDataArea->command << ":";
-    ss << "0x02 Num. Data Bytes:" << be16toh(i_tiDataArea->numDataBytes) << ":";
-    ss << "0x04 Reserved:" << (int)i_tiDataArea->reserved1 << ":";
-    ss << "0x06 HWDump Type:" << be16toh(i_tiDataArea->hardwareDumpType) << ":";
-    ss << "0x08 SRC Format:" << (int)i_tiDataArea->srcFormat << ":";
-    ss << "0x09 SRC Flags:" << (int)i_tiDataArea->srcFlags << ":";
-    ss << "0x0a Num. ASCII Words:" << (int)i_tiDataArea->numAsciiWords << ":";
-    ss << "0x0b Num. Hex Words:" << (int)i_tiDataArea->numHexWords << ":";
-    ss << "0x0e Length of SRC:" << be16toh(i_tiDataArea->lenSrc) << ":";
-    ss << "0x10 SRC Word 12:" << be32toh(i_tiDataArea->srcWord12HbWord0) << ":";
-    ss << "0x14 SRC Word 13:" << be32toh(i_tiDataArea->srcWord13HbWord2) << ":";
-    ss << "0x18 SRC Word 14:" << be32toh(i_tiDataArea->srcWord14HbWord3) << ":";
-    ss << "0x1c SRC Word 15:" << be32toh(i_tiDataArea->srcWord15HbWord4) << ":";
-    ss << "0x20 SRC Word 16:" << be32toh(i_tiDataArea->srcWord16HbWord5) << ":";
-    ss << "0x24 SRC Word 17:" << be32toh(i_tiDataArea->srcWord17HbWord6) << ":";
-    ss << "0x28 SRC Word 18:" << be32toh(i_tiDataArea->srcWord18HbWord7) << ":";
-    ss << "0x2c SRC Word 19:" << be32toh(i_tiDataArea->srcWord19HbWord8) << ":";
-    ss << "0x30 ASCII Data:" << be32toh(i_tiDataArea->asciiData0) << ":";
-    ss << "0x34 ASCII Data:" << be32toh(i_tiDataArea->asciiData1) << ":";
-    ss << "0x38 ASCII Data:" << be32toh(i_tiDataArea->asciiData2) << ":";
-    ss << "0x3c ASCII Data:" << be32toh(i_tiDataArea->asciiData3) << ":";
-    ss << "0x40 ASCII Data:" << be32toh(i_tiDataArea->asciiData4) << ":";
-    ss << "0x44 ASCII Data:" << be32toh(i_tiDataArea->asciiData5) << ":";
-    ss << "0x48 ASCII Data:" << be32toh(i_tiDataArea->asciiData6) << ":";
-    ss << "0x4c ASCII Data:" << be32toh(i_tiDataArea->asciiData7) << ":";
-    ss << "0x50 Location:" << (int)i_tiDataArea->location << ":";
-    ss << "0x51 Code Sections:" << (int)i_tiDataArea->codeSection << ":";
-    ss << "0x52 Additional Size:" << (int)i_tiDataArea->additionalSize << ":";
-    ss << "0x53 Additional Data:" << (int)i_tiDataArea->andData;
+    ss << "0x00 TI Area Valid:" << std::setw(2) << std::setfill('0') << std::hex
+       << (int)i_tiDataArea->tiAreaValid << ":";
+    ss << "0x01 Command:" << std::setw(2) << std::setfill('0') << std::hex
+       << (int)i_tiDataArea->command << ":";
+    ss << "0x02 Num. Data Bytes:" << std::setw(4) << std::setfill('0')
+       << std::hex << be16toh(i_tiDataArea->numDataBytes) << ":";
+    ss << "0x04 Reserved:" << std::setw(2) << std::setfill('0') << std::hex
+       << (int)i_tiDataArea->reserved1 << ":";
+    ss << "0x06 HWDump Type:" << std::setw(4) << std::setfill('0') << std::hex
+       << be16toh(i_tiDataArea->hardwareDumpType) << ":";
+    ss << "0x08 SRC Format:" << std::setw(2) << std::setfill('0') << std::hex
+       << (int)i_tiDataArea->srcFormat << ":";
+    ss << "0x09 SRC Flags:" << std::setw(2) << std::setfill('0') << std::hex
+       << (int)i_tiDataArea->srcFlags << ":";
+    ss << "0x0a Num. ASCII Words:" << std::setw(2) << std::setfill('0')
+       << std::hex << (int)i_tiDataArea->numAsciiWords << ":";
+    ss << "0x0b Num. Hex Words:" << std::setw(2) << std::setfill('0')
+       << std::hex << (int)i_tiDataArea->numHexWords << ":";
+    ss << "0x0e Length of SRC:" << std::setw(4) << std::setfill('0') << std::hex
+       << be16toh(i_tiDataArea->lenSrc) << ":";
+    ss << "0x10 SRC Word 12:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->srcWord12HbWord0) << ":";
+    ss << "0x14 SRC Word 13:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->srcWord13HbWord2) << ":";
+    ss << "0x18 SRC Word 14:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->srcWord14HbWord3) << ":";
+    ss << "0x1c SRC Word 15:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->srcWord15HbWord4) << ":";
+    ss << "0x20 SRC Word 16:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->srcWord16HbWord5) << ":";
+    ss << "0x24 SRC Word 17:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->srcWord17HbWord6) << ":";
+    ss << "0x28 SRC Word 18:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->srcWord18HbWord7) << ":";
+    ss << "0x2c SRC Word 19:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->srcWord19HbWord8) << ":";
+    ss << "0x30 ASCII Data:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->asciiData0) << ":";
+    ss << "0x34 ASCII Data:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->asciiData1) << ":";
+    ss << "0x38 ASCII Data:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->asciiData2) << ":";
+    ss << "0x3c ASCII Data:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->asciiData3) << ":";
+    ss << "0x40 ASCII Data:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->asciiData4) << ":";
+    ss << "0x44 ASCII Data:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->asciiData5) << ":";
+    ss << "0x48 ASCII Data:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->asciiData6) << ":";
+    ss << "0x4c ASCII Data:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->asciiData7) << ":";
+    ss << "0x50 Location:" << std::setw(2) << std::setfill('0') << std::hex
+       << (int)i_tiDataArea->location << ":";
+    ss << "0x51 Code Sections:" << std::setw(2) << std::setfill('0') << std::hex
+       << (int)i_tiDataArea->codeSection << ":";
+    ss << "0x52 Additional Size:" << std::setw(2) << std::setfill('0')
+       << std::hex << (int)i_tiDataArea->additionalSize << ":";
+    ss << "0x53 Additional Data:" << std::setw(2) << std::setfill('0')
+       << std::hex << (int)i_tiDataArea->andData;
 
     std::string key, value;
     char delim = ':';
@@ -327,22 +356,36 @@
 
     std::stringstream ss;
 
-    ss << std::hex << std::showbase;
-    ss << "0x00 TI Area Valid:" << (int)i_tiDataArea->tiAreaValid << ":";
-    ss << "0x04 Reserved:" << (int)i_tiDataArea->reserved1 << ":";
-    ss << "0x05 HB_Term. Type:" << (int)i_tiDataArea->hbTerminateType << ":";
-    ss << "0x0c HB Dump Flag:" << (int)i_tiDataArea->hbDumpFlag << ":";
-    ss << "0x0d Source:" << (int)i_tiDataArea->source << ":";
-    ss << "0x10 HB Word 0:" << be32toh(i_tiDataArea->srcWord12HbWord0) << ":";
-    ss << "0x14 HB Word 2:" << be32toh(i_tiDataArea->srcWord13HbWord2) << ":";
-    ss << "0x18 HB Word 3:" << be32toh(i_tiDataArea->srcWord14HbWord3) << ":";
-    ss << "0x1c HB Word 4:" << be32toh(i_tiDataArea->srcWord15HbWord4) << ":";
-    ss << "0x20 HB Word 5:" << be32toh(i_tiDataArea->srcWord16HbWord5) << ":";
-    ss << "0x24 HB Word 6:" << be32toh(i_tiDataArea->srcWord17HbWord6) << ":";
-    ss << "0x28 HB Word 7:" << be32toh(i_tiDataArea->srcWord18HbWord7) << ":";
-    ss << "0x2c HB Word 8:" << be32toh(i_tiDataArea->srcWord19HbWord8) << ":";
-    ss << "0x30 error_data:" << be32toh(i_tiDataArea->asciiData0) << ":";
-    ss << "0x34 EID:" << be32toh(i_tiDataArea->asciiData1);
+    ss << "0x00 TI Area Valid:" << std::setw(2) << std::setfill('0') << std::hex
+       << (int)i_tiDataArea->tiAreaValid << ":";
+    ss << "0x04 Reserved:" << std::setw(2) << std::setfill('0') << std::hex
+       << (int)i_tiDataArea->reserved1 << ":";
+    ss << "0x05 HB_Term. Type:" << std::setw(2) << std::setfill('0') << std::hex
+       << (int)i_tiDataArea->hbTerminateType << ":";
+    ss << "0x0c HB Dump Flag:" << std::setw(2) << std::setfill('0') << std::hex
+       << (int)i_tiDataArea->hbDumpFlag << ":";
+    ss << "0x0d Source:" << std::setw(2) << std::setfill('0') << std::hex
+       << (int)i_tiDataArea->source << ":";
+    ss << "0x10 HB Word 0:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->srcWord12HbWord0) << ":";
+    ss << "0x14 HB Word 2:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->srcWord13HbWord2) << ":";
+    ss << "0x18 HB Word 3:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->srcWord14HbWord3) << ":";
+    ss << "0x1c HB Word 4:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->srcWord15HbWord4) << ":";
+    ss << "0x20 HB Word 5:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->srcWord16HbWord5) << ":";
+    ss << "0x24 HB Word 6:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->srcWord17HbWord6) << ":";
+    ss << "0x28 HB Word 7:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->srcWord18HbWord7) << ":";
+    ss << "0x2c HB Word 8:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->srcWord19HbWord8) << ":";
+    ss << "0x30 error_data:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->asciiData0) << ":";
+    ss << "0x34 EID:" << std::setw(8) << std::setfill('0') << std::hex
+       << be32toh(i_tiDataArea->asciiData1);
 
     std::string key, value;
     char delim = ':';