blob: eae741ddd03417eed47e0d4e4b373587e48341c5 [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>
5#include <tuple>
6#include <vector>
7
Lei YUab093322019-10-09 16:43:22 +08008namespace phosphor
Matt Spinlerd7abf362018-01-18 12:40:02 -06009{
10namespace power
11{
12namespace history
13{
14
15static constexpr auto recIDPos = 0;
16static constexpr auto recTimePos = 1;
17static constexpr auto recAvgPos = 2;
18static constexpr auto recMaxPos = 3;
19using Record = std::tuple<size_t, int64_t, int64_t, int64_t>;
20
21/**
Matt Spinler28fa1b62018-01-18 13:15:02 -060022 * @class InvalidRecordException
23 *
24 * The exception that is thrown when a raw history record
25 * cannot be parsed.
26 */
27class InvalidRecordException : public std::runtime_error
28{
Matt Spinlerf0f02b92018-10-25 16:12:43 -050029 public:
30 InvalidRecordException() : std::runtime_error("Invalid history record")
31 {
32 }
Matt Spinler28fa1b62018-01-18 13:15:02 -060033};
34
35/**
Matt Spinlerd7abf362018-01-18 12:40:02 -060036 * @class RecordManager
37 *
38 * This class manages the records for the input power history of
39 * a power supply.
40 *
41 * The history is the average and maximum power values across 30s
42 * intervals. Every 30s, a new record will be available from the
43 * PS. This class takes that raw PS data and converts it into
Gunnar Millscab48342018-06-13 15:57:13 -050044 * something usable by D-Bus. It ensures the readings are always
Matt Spinlerd7abf362018-01-18 12:40:02 -060045 * sorted newest to oldest, and prunes out the oldest entries when
46 * necessary. If there is a problem with the ordering IDs coming
47 * from the PS, it will clear out the old records and start over.
48 */
49class RecordManager
50{
Matt Spinlerf0f02b92018-10-25 16:12:43 -050051 public:
52 static constexpr auto RAW_RECORD_SIZE = 5;
53 static constexpr auto RAW_RECORD_ID_OFFSET = 0;
54 static constexpr auto FIRST_SEQUENCE_ID = 0;
55 static constexpr auto LAST_SEQUENCE_ID = 0xFF;
Matt Spinlerd7abf362018-01-18 12:40:02 -060056
Matt Spinlerf0f02b92018-10-25 16:12:43 -050057 using DBusRecord = std::tuple<uint64_t, int64_t>;
58 using DBusRecordList = std::vector<DBusRecord>;
Matt Spinlerd7abf362018-01-18 12:40:02 -060059
Matt Spinlerf0f02b92018-10-25 16:12:43 -050060 RecordManager() = delete;
61 ~RecordManager() = default;
62 RecordManager(const RecordManager&) = default;
63 RecordManager& operator=(const RecordManager&) = default;
64 RecordManager(RecordManager&&) = default;
65 RecordManager& operator=(RecordManager&&) = default;
Matt Spinlerd7abf362018-01-18 12:40:02 -060066
Matt Spinlerf0f02b92018-10-25 16:12:43 -050067 /**
68 * @brief Constructor
69 *
70 * @param[in] maxRec - the maximum number of history
71 * records to keep at a time
72 */
73 RecordManager(size_t maxRec) : RecordManager(maxRec, LAST_SEQUENCE_ID)
74 {
75 }
Matt Spinlerd7abf362018-01-18 12:40:02 -060076
Matt Spinlerf0f02b92018-10-25 16:12:43 -050077 /**
78 * @brief Constructor
79 *
80 * @param[in] maxRec - the maximum number of history
81 * records to keep at a time
82 * @param[in] lastSequenceID - the last sequence ID the power supply
83 * will use before starting over
84 */
85 RecordManager(size_t maxRec, size_t lastSequenceID) :
86 maxRecords(maxRec), lastSequenceID(lastSequenceID)
87 {
88 }
Matt Spinlerd7abf362018-01-18 12:40:02 -060089
Matt Spinlerf0f02b92018-10-25 16:12:43 -050090 /**
91 * @brief Adds a new entry to the history
92 *
93 * Also checks to see if the old history should be
94 * cleared, such as when there is an invalid record
95 * sequence ID or if there was no data from the PS.
96 *
97 * @param[in] rawRecord - the record data straight
98 * from the power supply
99 *
100 * @return bool - If there has been a change to the
101 * history records that needs to be
102 * reflected in D-Bus.
103 */
104 bool add(const std::vector<uint8_t>& rawRecord);
Matt Spinlerd7abf362018-01-18 12:40:02 -0600105
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500106 /**
107 * @brief Returns the history of average input power
108 * in a representation used by D-Bus.
109 *
110 * @return DBusRecordList - A list of averages with
111 * a timestamp for each entry.
112 */
113 DBusRecordList getAverageRecords();
Matt Spinler8168d282018-01-18 13:24:06 -0600114
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500115 /**
116 * @brief Returns the history of maximum input power
117 * in a representation used by D-Bus.
118 *
119 * @return DBusRecordList - A list of maximums with
120 * a timestamp for each entry.
121 */
122 DBusRecordList getMaximumRecords();
Matt Spinlerc3414382018-01-18 13:49:16 -0600123
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500124 /**
125 * @brief Converts a Linear Format power number to an integer
126 *
127 * The PMBus spec describes a 2 byte Linear Format
128 * number that is composed of an exponent and mantissa
129 * in two's complement notation.
130 *
131 * Value = Mantissa * 2**Exponent
132 *
133 * @return int64_t the converted value
134 */
135 static int64_t linearToInteger(uint16_t data);
Matt Spinlerc3414382018-01-18 13:49:16 -0600136
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500137 /**
138 * @brief Returns the number of records
139 *
140 * @return size_t - the number of records
141 *
142 */
143 inline size_t getNumRecords() const
144 {
145 return records.size();
146 }
Matt Spinlere710d182018-01-18 13:06:17 -0600147
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500148 /**
149 * @brief Deletes all records
150 */
151 inline void clear()
152 {
153 records.clear();
154 }
Matt Spinlerd7abf362018-01-18 12:40:02 -0600155
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500156 private:
157 /**
158 * @brief returns the sequence ID from a raw history record
159 *
160 * Throws InvalidRecordException if the data is the wrong length.
161 *
162 * @param[in] data - the raw record data as the PS returns it
163 *
164 * @return size_t - the ID from byte 0
165 */
166 size_t getRawRecordID(const std::vector<uint8_t>& data) const;
Matt Spinlerd7abf362018-01-18 12:40:02 -0600167
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500168 /**
169 * @brief Creates an instance of a Record from the raw PS data
170 *
171 * @param[in] data - the raw record data as the PS returns it
172 *
173 * @return Record - A filled in Record instance
174 */
175 Record createRecord(const std::vector<uint8_t>& data);
Matt Spinlerd7abf362018-01-18 12:40:02 -0600176
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500177 /**
178 * @brief The maximum number of entries to keep in the history.
179 *
180 * When a new record is added, the oldest one will be removed.
181 */
182 const size_t maxRecords;
Matt Spinler28fa1b62018-01-18 13:15:02 -0600183
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500184 /**
185 * @brief The last ID the power supply returns before rolling over
186 * back to the first ID of 0.
187 */
188 const size_t lastSequenceID;
Matt Spinler28fa1b62018-01-18 13:15:02 -0600189
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500190 /**
191 * @brief The list of timestamp/average/maximum records.
192 * Newer records are added to the front, and older ones
193 * removed from the back.
194 */
195 std::deque<Record> records;
Matt Spinlerd7abf362018-01-18 12:40:02 -0600196};
197
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500198} // namespace history
199} // namespace power
Lei YUab093322019-10-09 16:43:22 +0800200} // namespace phosphor