blob: fed860d0766ef2eceb4e65db1dc49d5377cf7293 [file] [log] [blame]
Matt Spinlerd7abf362018-01-18 12:40:02 -06001#pragma once
2
Andrew Geisslerc60b9752020-05-16 14:49:19 -05003#include <cstdint>
Matt Spinlerd7abf362018-01-18 12:40:02 -06004#include <deque>
Andrew Geissler01779a62020-05-16 14:54:41 -05005#include <stdexcept>
Matt Spinlerd7abf362018-01-18 12:40:02 -06006#include <tuple>
7#include <vector>
8
Lei YUab093322019-10-09 16:43:22 +08009namespace phosphor
Matt Spinlerd7abf362018-01-18 12:40:02 -060010{
11namespace power
12{
13namespace history
14{
15
16static constexpr auto recIDPos = 0;
17static constexpr auto recTimePos = 1;
18static constexpr auto recAvgPos = 2;
19static constexpr auto recMaxPos = 3;
20using Record = std::tuple<size_t, int64_t, int64_t, int64_t>;
21
22/**
Matt Spinler28fa1b62018-01-18 13:15:02 -060023 * @class InvalidRecordException
24 *
25 * The exception that is thrown when a raw history record
26 * cannot be parsed.
27 */
28class InvalidRecordException : public std::runtime_error
29{
Matt Spinlerf0f02b92018-10-25 16:12:43 -050030 public:
31 InvalidRecordException() : std::runtime_error("Invalid history record")
32 {
33 }
Matt Spinler28fa1b62018-01-18 13:15:02 -060034};
35
36/**
Matt Spinlerd7abf362018-01-18 12:40:02 -060037 * @class RecordManager
38 *
39 * This class manages the records for the input power history of
40 * a power supply.
41 *
42 * The history is the average and maximum power values across 30s
43 * intervals. Every 30s, a new record will be available from the
44 * PS. This class takes that raw PS data and converts it into
Gunnar Millscab48342018-06-13 15:57:13 -050045 * something usable by D-Bus. It ensures the readings are always
Matt Spinlerd7abf362018-01-18 12:40:02 -060046 * sorted newest to oldest, and prunes out the oldest entries when
47 * necessary. If there is a problem with the ordering IDs coming
48 * from the PS, it will clear out the old records and start over.
49 */
50class RecordManager
51{
Matt Spinlerf0f02b92018-10-25 16:12:43 -050052 public:
53 static constexpr auto RAW_RECORD_SIZE = 5;
54 static constexpr auto RAW_RECORD_ID_OFFSET = 0;
55 static constexpr auto FIRST_SEQUENCE_ID = 0;
56 static constexpr auto LAST_SEQUENCE_ID = 0xFF;
Matt Spinlerd7abf362018-01-18 12:40:02 -060057
Matt Spinlerf0f02b92018-10-25 16:12:43 -050058 using DBusRecord = std::tuple<uint64_t, int64_t>;
59 using DBusRecordList = std::vector<DBusRecord>;
Matt Spinlerd7abf362018-01-18 12:40:02 -060060
Matt Spinlerf0f02b92018-10-25 16:12:43 -050061 RecordManager() = delete;
62 ~RecordManager() = default;
63 RecordManager(const RecordManager&) = default;
64 RecordManager& operator=(const RecordManager&) = default;
65 RecordManager(RecordManager&&) = default;
66 RecordManager& operator=(RecordManager&&) = default;
Matt Spinlerd7abf362018-01-18 12:40:02 -060067
Matt Spinlerf0f02b92018-10-25 16:12:43 -050068 /**
69 * @brief Constructor
70 *
71 * @param[in] maxRec - the maximum number of history
72 * records to keep at a time
73 */
74 RecordManager(size_t maxRec) : RecordManager(maxRec, LAST_SEQUENCE_ID)
75 {
76 }
Matt Spinlerd7abf362018-01-18 12:40:02 -060077
Matt Spinlerf0f02b92018-10-25 16:12:43 -050078 /**
79 * @brief Constructor
80 *
81 * @param[in] maxRec - the maximum number of history
82 * records to keep at a time
83 * @param[in] lastSequenceID - the last sequence ID the power supply
84 * will use before starting over
85 */
86 RecordManager(size_t maxRec, size_t lastSequenceID) :
87 maxRecords(maxRec), lastSequenceID(lastSequenceID)
88 {
89 }
Matt Spinlerd7abf362018-01-18 12:40:02 -060090
Matt Spinlerf0f02b92018-10-25 16:12:43 -050091 /**
92 * @brief Adds a new entry to the history
93 *
94 * Also checks to see if the old history should be
95 * cleared, such as when there is an invalid record
96 * sequence ID or if there was no data from the PS.
97 *
98 * @param[in] rawRecord - the record data straight
99 * from the power supply
100 *
101 * @return bool - If there has been a change to the
102 * history records that needs to be
103 * reflected in D-Bus.
104 */
105 bool add(const std::vector<uint8_t>& rawRecord);
Matt Spinlerd7abf362018-01-18 12:40:02 -0600106
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500107 /**
108 * @brief Returns the history of average input power
109 * in a representation used by D-Bus.
110 *
111 * @return DBusRecordList - A list of averages with
112 * a timestamp for each entry.
113 */
114 DBusRecordList getAverageRecords();
Matt Spinler8168d282018-01-18 13:24:06 -0600115
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500116 /**
117 * @brief Returns the history of maximum input power
118 * in a representation used by D-Bus.
119 *
120 * @return DBusRecordList - A list of maximums with
121 * a timestamp for each entry.
122 */
123 DBusRecordList getMaximumRecords();
Matt Spinlerc3414382018-01-18 13:49:16 -0600124
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500125 /**
126 * @brief Converts a Linear Format power number to an integer
127 *
128 * The PMBus spec describes a 2 byte Linear Format
129 * number that is composed of an exponent and mantissa
130 * in two's complement notation.
131 *
132 * Value = Mantissa * 2**Exponent
133 *
134 * @return int64_t the converted value
135 */
136 static int64_t linearToInteger(uint16_t data);
Matt Spinlerc3414382018-01-18 13:49:16 -0600137
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500138 /**
139 * @brief Returns the number of records
140 *
141 * @return size_t - the number of records
142 *
143 */
144 inline size_t getNumRecords() const
145 {
146 return records.size();
147 }
Matt Spinlere710d182018-01-18 13:06:17 -0600148
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500149 /**
150 * @brief Deletes all records
151 */
152 inline void clear()
153 {
154 records.clear();
155 }
Matt Spinlerd7abf362018-01-18 12:40:02 -0600156
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500157 private:
158 /**
159 * @brief returns the sequence ID from a raw history record
160 *
161 * Throws InvalidRecordException if the data is the wrong length.
162 *
163 * @param[in] data - the raw record data as the PS returns it
164 *
165 * @return size_t - the ID from byte 0
166 */
167 size_t getRawRecordID(const std::vector<uint8_t>& data) const;
Matt Spinlerd7abf362018-01-18 12:40:02 -0600168
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500169 /**
170 * @brief Creates an instance of a Record from the raw PS data
171 *
172 * @param[in] data - the raw record data as the PS returns it
173 *
174 * @return Record - A filled in Record instance
175 */
176 Record createRecord(const std::vector<uint8_t>& data);
Matt Spinlerd7abf362018-01-18 12:40:02 -0600177
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500178 /**
179 * @brief The maximum number of entries to keep in the history.
180 *
181 * When a new record is added, the oldest one will be removed.
182 */
183 const size_t maxRecords;
Matt Spinler28fa1b62018-01-18 13:15:02 -0600184
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500185 /**
186 * @brief The last ID the power supply returns before rolling over
187 * back to the first ID of 0.
188 */
189 const size_t lastSequenceID;
Matt Spinler28fa1b62018-01-18 13:15:02 -0600190
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500191 /**
192 * @brief The list of timestamp/average/maximum records.
193 * Newer records are added to the front, and older ones
194 * removed from the back.
195 */
196 std::deque<Record> records;
Matt Spinlerd7abf362018-01-18 12:40:02 -0600197};
198
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500199} // namespace history
200} // namespace power
Lei YUab093322019-10-09 16:43:22 +0800201} // namespace phosphor