Add functions to parse an input history record

The code will take a 5 byte raw record that comes from
the power supply and create an instance of a Record
out of it.  A Record includes the average and maximum
power values, the sequence ID, and a timestamp.

Change-Id: I9dec5fd3de2ae2c6275a1407bcec4717557ffe86
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/power-supply/record_manager.cpp b/power-supply/record_manager.cpp
index 7492dd3..1fcd463 100644
--- a/power-supply/record_manager.cpp
+++ b/power-supply/record_manager.cpp
@@ -13,7 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <chrono>
 #include <math.h>
+#include <phosphor-logging/log.hpp>
 #include "record_manager.hpp"
 
 namespace witherspoon
@@ -23,6 +25,44 @@
 namespace history
 {
 
+using namespace phosphor::logging;
+
+size_t RecordManager::getRawRecordID(
+        const std::vector<uint8_t>& data) const
+{
+    if (data.size() != RAW_RECORD_SIZE)
+    {
+        log<level::ERR>("Invalid INPUT_HISTORY size",
+                entry("SIZE=%d", data.size()));
+        throw InvalidRecordException{};
+    }
+
+    return data[RAW_RECORD_ID_OFFSET];
+}
+
+Record RecordManager::createRecord(const std::vector<uint8_t>& data)
+{
+    //The raw record format is:
+    //  0xAABBCCDDEE
+    //
+    //  where:
+    //    0xAA = sequence ID
+    //    0xBBCC = average power in linear format (0xCC = MSB)
+    //    0xDDEE = maximum power in linear format (0xEE = MSB)
+    auto id = getRawRecordID(data);
+
+    auto time = std::chrono::duration_cast<std::chrono::milliseconds>(
+            std::chrono::system_clock::now().time_since_epoch()).count();
+
+    auto val = static_cast<uint16_t>(data[2]) << 8 | data[1];
+    auto averagePower = linearToInteger(val);
+
+    val = static_cast<uint16_t>(data[4]) << 8 | data[3];
+    auto maxPower = linearToInteger(val);
+
+    return Record{id, time, averagePower, maxPower};
+}
+
 int64_t RecordManager::linearToInteger(uint16_t data)
 {
     //The exponent is the first 5 bits, followed by 11 bits of mantissa.
diff --git a/power-supply/record_manager.hpp b/power-supply/record_manager.hpp
index 09b55f9..73459df 100644
--- a/power-supply/record_manager.hpp
+++ b/power-supply/record_manager.hpp
@@ -18,6 +18,22 @@
 using Record = std::tuple<size_t, int64_t, int64_t, int64_t>;
 
 /**
+ * @class InvalidRecordException
+ *
+ * The exception that is thrown when a raw history record
+ * cannot be parsed.
+ */
+class InvalidRecordException : public std::runtime_error
+{
+    public:
+
+        InvalidRecordException() :
+            std::runtime_error("Invalid history record")
+        {
+        }
+};
+
+/**
  * @class RecordManager
  *
  * This class manages the records for the input power history of
@@ -35,6 +51,8 @@
 {
     public:
 
+        static constexpr auto RAW_RECORD_SIZE = 5;
+        static constexpr auto RAW_RECORD_ID_OFFSET = 0;
         static constexpr auto LAST_SEQUENCE_ID = 0xFF;
 
         using DBusRecord = std::tuple<uint64_t, int64_t>;
@@ -107,6 +125,26 @@
     private:
 
         /**
+         * @brief returns the sequence ID from a raw history record
+         *
+         * Throws InvalidRecordException if the data is the wrong length.
+         *
+         * @param[in] data - the raw record data as the PS returns it
+         *
+         * @return size_t - the ID from byte 0
+         */
+        size_t getRawRecordID(const std::vector<uint8_t>& data) const;
+
+        /**
+         * @brief Creates an instance of a Record from the raw PS data
+         *
+         * @param[in] data - the raw record data as the PS returns it
+         *
+         * @return Record - A filled in Record instance
+         */
+        Record createRecord(const std::vector<uint8_t>& data);
+
+        /**
          * @brief The maximum number of entries to keep in the history.
          *
          * When a new record is added, the oldest one will be removed.