buffer: Implement "updateBmcFlags"

This function will be used to update the "bmcFlags" member of the buffer
header.

Also reinforced the updateReadPtr unit tests to check that the header
buffer was actually updated by checking the result after.

Tested: Unit tested

Signed-off-by: Brandon Kim <brandonkim@google.com>
Change-Id: Iff7a1eea6824b84347e1a6aaed872ed6caa55788
diff --git a/include/buffer.hpp b/include/buffer.hpp
index d676165..54d197e 100644
--- a/include/buffer.hpp
+++ b/include/buffer.hpp
@@ -21,6 +21,13 @@
 // EntryPair.second = Error entry in vector of bytes
 using EntryPair = std::pair<struct QueueEntryHeader, std::vector<uint8_t>>;
 
+enum class BmcFlags : uint32_t
+{
+    ueSwitch = 1,
+    overflow = 1 << 1,
+    ready = 1 << 2,
+};
+
 struct CircularBufferHeader
 {
     little_uint32_t bmcInterfaceVersion;        // Offset 0x0
@@ -110,6 +117,12 @@
     virtual void updateReadPtr(const uint32_t newReadPtr) = 0;
 
     /**
+     * Write to the bufferHeader and update the BMC flags
+     * @param[in] newBmcFlags - new flag to update to
+     */
+    virtual void updateBmcFlags(const uint32_t newBmcFlags) = 0;
+
+    /**
      * Wrapper for the dataInterface->read, performs wraparound read
      *
      * @param[in] relativeOffset - offset relative the "Error Log
@@ -162,6 +175,7 @@
     void readBufferHeader() override;
     struct CircularBufferHeader getCachedBufferHeader() const override;
     void updateReadPtr(const uint32_t newReadPtr) override;
+    void updateBmcFlags(const uint32_t newBmcFlag) override;
     std::vector<uint8_t> wraparoundRead(const uint32_t relativeOffset,
                                         const uint32_t length) override;
     struct QueueEntryHeader readEntryHeader(size_t relativeOffset) override;
diff --git a/src/buffer.cpp b/src/buffer.cpp
index 278f8cf..5d39f69 100644
--- a/src/buffer.cpp
+++ b/src/buffer.cpp
@@ -119,6 +119,29 @@
     cachedBufferHeader.bmcReadPtr = truncatedReadPtr;
 }
 
+void BufferImpl::updateBmcFlags(const uint32_t newBmcFlag)
+{
+    constexpr uint8_t bmcFlagsPtrOffset =
+        offsetof(struct CircularBufferHeader, bmcFlags);
+
+    little_uint32_t littleNewBmcFlag =
+        boost::endian::native_to_little(newBmcFlag);
+    uint8_t* littleNewBmcFlagPtr =
+        reinterpret_cast<uint8_t*>(&littleNewBmcFlag);
+
+    size_t writtenSize = dataInterface->write(
+        bmcFlagsPtrOffset, std::span<const uint8_t>{
+                               littleNewBmcFlagPtr,
+                               littleNewBmcFlagPtr + sizeof(little_uint32_t)});
+    if (writtenSize != sizeof(little_uint32_t))
+    {
+        throw std::runtime_error(fmt::format(
+            "[updateBmcFlags] Wrote '{}' bytes, instead of expected '{}'",
+            writtenSize, sizeof(little_uint32_t)));
+    }
+    cachedBufferHeader.bmcFlags = littleNewBmcFlag;
+}
+
 size_t BufferImpl::getQueueOffset()
 {
     return sizeof(struct CircularBufferHeader) +
diff --git a/test/buffer_test.cpp b/test/buffer_test.cpp
index 577e322..0b3d8e2 100644
--- a/test/buffer_test.cpp
+++ b/test/buffer_test.cpp
@@ -203,6 +203,45 @@
                                              ElementsAreArray(expectedReadPtr)))
         .WillOnce(Return(expectedWriteSize));
     EXPECT_NO_THROW(bufferImpl->updateReadPtr(testNewReadPtr));
+
+    auto cachedHeader = bufferImpl->getCachedBufferHeader();
+    EXPECT_EQ(boost::endian::little_to_native(cachedHeader.bmcReadPtr), 0x1234);
+}
+
+TEST_F(BufferTest, BufferUpdateBmcFlagsFail)
+{
+    // Return write size that is not 4 which is sizeof(little_uint32_t)
+    constexpr size_t wrongWriteSize = 1;
+    EXPECT_CALL(*dataInterfaceMockPtr, write(_, _))
+        .WillOnce(Return(wrongWriteSize));
+    EXPECT_THROW(
+        try {
+            bufferImpl->updateBmcFlags(static_cast<uint32_t>(BmcFlags::ready));
+        } catch (const std::runtime_error& e) {
+            EXPECT_STREQ(
+                e.what(),
+                "[updateBmcFlags] Wrote '1' bytes, instead of expected '4'");
+            throw;
+        },
+        std::runtime_error);
+}
+
+TEST_F(BufferTest, BufferUpdateBmcFlagsPass)
+{
+    constexpr size_t expectedWriteSize = 4;
+    constexpr uint8_t expectedBmcReadPtrOffset = 0x1c;
+    const std::vector<uint8_t> expectedNewBmcFlagsVector{0x04, 0x0, 0x0, 0x00};
+
+    EXPECT_CALL(*dataInterfaceMockPtr,
+                write(expectedBmcReadPtrOffset,
+                      ElementsAreArray(expectedNewBmcFlagsVector)))
+        .WillOnce(Return(expectedWriteSize));
+    EXPECT_NO_THROW(
+        bufferImpl->updateBmcFlags(static_cast<uint32_t>(BmcFlags::ready)));
+
+    auto cachedHeader = bufferImpl->getCachedBufferHeader();
+    EXPECT_EQ(boost::endian::little_to_native(cachedHeader.bmcFlags),
+              static_cast<uint32_t>(BmcFlags::ready));
 }
 
 class BufferWraparoundReadTest : public BufferTest