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/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