| #pragma once |
| |
| #include <deque> |
| #include <tuple> |
| #include <vector> |
| |
| namespace witherspoon |
| { |
| namespace power |
| { |
| namespace history |
| { |
| |
| static constexpr auto recIDPos = 0; |
| static constexpr auto recTimePos = 1; |
| static constexpr auto recAvgPos = 2; |
| static constexpr auto recMaxPos = 3; |
| 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 |
| * a power supply. |
| * |
| * The history is the average and maximum power values across 30s |
| * intervals. Every 30s, a new record will be available from the |
| * PS. This class takes that raw PS data and converts it into |
| * something useable by D-Bus. It ensures the readings are always |
| * sorted newest to oldest, and prunes out the oldest entries when |
| * necessary. If there is a problem with the ordering IDs coming |
| * from the PS, it will clear out the old records and start over. |
| */ |
| class RecordManager |
| { |
| public: |
| |
| static constexpr auto RAW_RECORD_SIZE = 5; |
| static constexpr auto RAW_RECORD_ID_OFFSET = 0; |
| static constexpr auto FIRST_SEQUENCE_ID = 0; |
| static constexpr auto LAST_SEQUENCE_ID = 0xFF; |
| |
| using DBusRecord = std::tuple<uint64_t, int64_t>; |
| using DBusRecordList = std::vector<DBusRecord>; |
| |
| RecordManager() = delete; |
| ~RecordManager() = default; |
| RecordManager(const RecordManager&) = default; |
| RecordManager& operator=(const RecordManager&) = default; |
| RecordManager(RecordManager&&) = default; |
| RecordManager& operator=(RecordManager&&) = default; |
| |
| /** |
| * @brief Constructor |
| * |
| * @param[in] maxRec - the maximum number of history |
| * records to keep at a time |
| */ |
| RecordManager(size_t maxRec) : |
| RecordManager(maxRec, LAST_SEQUENCE_ID) |
| { |
| } |
| |
| /** |
| * @brief Constructor |
| * |
| * @param[in] maxRec - the maximum number of history |
| * records to keep at a time |
| * @param[in] lastSequenceID - the last sequence ID the power supply |
| * will use before starting over |
| */ |
| RecordManager(size_t maxRec, size_t lastSequenceID) : |
| maxRecords(maxRec), |
| lastSequenceID(lastSequenceID) |
| { |
| } |
| |
| /** |
| * @brief Adds a new entry to the history |
| * |
| * Also checks to see if the old history should be |
| * cleared, such as when there is an invalid record |
| * sequence ID or if there was no data from the PS. |
| * |
| * @param[in] rawRecord - the record data straight |
| * from the power supply |
| * |
| * @return bool - If there has been a change to the |
| * history records that needs to be |
| * reflected in D-Bus. |
| */ |
| bool add(const std::vector<uint8_t>& rawRecord); |
| |
| /** |
| * @brief Returns the history of average input power |
| * in a representation used by D-Bus. |
| * |
| * @return DBusRecordList - A list of averages with |
| * a timestamp for each entry. |
| */ |
| DBusRecordList getAverageRecords(); |
| |
| /** |
| * @brief Returns the history of maximum input power |
| * in a representation used by D-Bus. |
| * |
| * @return DBusRecordList - A list of maximums with |
| * a timestamp for each entry. |
| */ |
| DBusRecordList getMaximumRecords(); |
| |
| /** |
| * @brief Converts a Linear Format power number to an integer |
| * |
| * The PMBus spec describes a 2 byte Linear Format |
| * number that is composed of an exponent and mantissa |
| * in two's complement notation. |
| * |
| * Value = Mantissa * 2**Exponent |
| * |
| * @return int64_t the converted value |
| */ |
| static int64_t linearToInteger(uint16_t data); |
| |
| /** |
| * @brief Returns the number of records |
| * |
| * @return size_t - the number of records |
| * |
| */ |
| inline size_t getNumRecords() const |
| { |
| return records.size(); |
| } |
| |
| /** |
| * @brief Deletes all records |
| */ |
| inline void clear() |
| { |
| records.clear(); |
| } |
| |
| 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. |
| */ |
| const size_t maxRecords; |
| |
| /** |
| * @brief The last ID the power supply returns before rolling over |
| * back to the first ID of 0. |
| */ |
| const size_t lastSequenceID; |
| |
| /** |
| * @brief The list of timestamp/average/maximum records. |
| * Newer records are added to the front, and older ones |
| * removed from the back. |
| */ |
| std::deque<Record> records; |
| }; |
| |
| } |
| } |
| } |