blob: 36a786f736235cfb9663773b2caebac251225ae0 [file] [log] [blame]
Matt Spinlerd7abf362018-01-18 12:40:02 -06001#pragma once
2
Patrick Williams2c4fbc42020-06-26 15:33:11 -05003#include <cstdint>
Matt Spinlerd7abf362018-01-18 12:40:02 -06004#include <deque>
Patrick Williams2c4fbc42020-06-26 15:33:11 -05005#include <stdexcept>
Matt Spinlerd7abf362018-01-18 12:40:02 -06006#include <tuple>
7#include <vector>
8
9namespace witherspoon
10{
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:
Patrick Williamsb7ed5772023-05-10 07:50:45 -050031 InvalidRecordException() : std::runtime_error("Invalid history record") {}
Matt Spinler28fa1b62018-01-18 13:15:02 -060032};
33
34/**
Matt Spinlerd7abf362018-01-18 12:40:02 -060035 * @class RecordManager
36 *
37 * This class manages the records for the input power history of
38 * a power supply.
39 *
40 * The history is the average and maximum power values across 30s
41 * intervals. Every 30s, a new record will be available from the
42 * PS. This class takes that raw PS data and converts it into
Gunnar Millscab48342018-06-13 15:57:13 -050043 * something usable by D-Bus. It ensures the readings are always
Matt Spinlerd7abf362018-01-18 12:40:02 -060044 * sorted newest to oldest, and prunes out the oldest entries when
45 * necessary. If there is a problem with the ordering IDs coming
46 * from the PS, it will clear out the old records and start over.
47 */
48class RecordManager
49{
Matt Spinlerf0f02b92018-10-25 16:12:43 -050050 public:
51 static constexpr auto RAW_RECORD_SIZE = 5;
52 static constexpr auto RAW_RECORD_ID_OFFSET = 0;
53 static constexpr auto FIRST_SEQUENCE_ID = 0;
54 static constexpr auto LAST_SEQUENCE_ID = 0xFF;
Matt Spinlerd7abf362018-01-18 12:40:02 -060055
Matt Spinlerf0f02b92018-10-25 16:12:43 -050056 using DBusRecord = std::tuple<uint64_t, int64_t>;
57 using DBusRecordList = std::vector<DBusRecord>;
Matt Spinlerd7abf362018-01-18 12:40:02 -060058
Matt Spinlerf0f02b92018-10-25 16:12:43 -050059 RecordManager() = delete;
60 ~RecordManager() = default;
61 RecordManager(const RecordManager&) = default;
62 RecordManager& operator=(const RecordManager&) = default;
63 RecordManager(RecordManager&&) = default;
64 RecordManager& operator=(RecordManager&&) = default;
Matt Spinlerd7abf362018-01-18 12:40:02 -060065
Matt Spinlerf0f02b92018-10-25 16:12:43 -050066 /**
67 * @brief Constructor
68 *
69 * @param[in] maxRec - the maximum number of history
70 * records to keep at a time
71 */
Patrick Williamsb7ed5772023-05-10 07:50:45 -050072 RecordManager(size_t maxRec) : RecordManager(maxRec, LAST_SEQUENCE_ID) {}
Matt Spinlerd7abf362018-01-18 12:40:02 -060073
Matt Spinlerf0f02b92018-10-25 16:12:43 -050074 /**
75 * @brief Constructor
76 *
77 * @param[in] maxRec - the maximum number of history
78 * records to keep at a time
79 * @param[in] lastSequenceID - the last sequence ID the power supply
80 * will use before starting over
81 */
82 RecordManager(size_t maxRec, size_t lastSequenceID) :
83 maxRecords(maxRec), lastSequenceID(lastSequenceID)
Patrick Williams2c4fbc42020-06-26 15:33:11 -050084 {}
Matt Spinlerd7abf362018-01-18 12:40:02 -060085
Matt Spinlerf0f02b92018-10-25 16:12:43 -050086 /**
87 * @brief Adds a new entry to the history
88 *
89 * Also checks to see if the old history should be
90 * cleared, such as when there is an invalid record
91 * sequence ID or if there was no data from the PS.
92 *
93 * @param[in] rawRecord - the record data straight
94 * from the power supply
95 *
96 * @return bool - If there has been a change to the
97 * history records that needs to be
98 * reflected in D-Bus.
99 */
100 bool add(const std::vector<uint8_t>& rawRecord);
Matt Spinlerd7abf362018-01-18 12:40:02 -0600101
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500102 /**
103 * @brief Returns the history of average input power
104 * in a representation used by D-Bus.
105 *
106 * @return DBusRecordList - A list of averages with
107 * a timestamp for each entry.
108 */
109 DBusRecordList getAverageRecords();
Matt Spinler8168d282018-01-18 13:24:06 -0600110
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500111 /**
112 * @brief Returns the history of maximum input power
113 * in a representation used by D-Bus.
114 *
115 * @return DBusRecordList - A list of maximums with
116 * a timestamp for each entry.
117 */
118 DBusRecordList getMaximumRecords();
Matt Spinlerc3414382018-01-18 13:49:16 -0600119
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500120 /**
121 * @brief Converts a Linear Format power number to an integer
122 *
123 * The PMBus spec describes a 2 byte Linear Format
124 * number that is composed of an exponent and mantissa
125 * in two's complement notation.
126 *
127 * Value = Mantissa * 2**Exponent
128 *
129 * @return int64_t the converted value
130 */
131 static int64_t linearToInteger(uint16_t data);
Matt Spinlerc3414382018-01-18 13:49:16 -0600132
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500133 /**
134 * @brief Returns the number of records
135 *
136 * @return size_t - the number of records
137 *
138 */
139 inline size_t getNumRecords() const
140 {
141 return records.size();
142 }
Matt Spinlere710d182018-01-18 13:06:17 -0600143
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500144 /**
145 * @brief Deletes all records
146 */
147 inline void clear()
148 {
149 records.clear();
150 }
Matt Spinlerd7abf362018-01-18 12:40:02 -0600151
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500152 private:
153 /**
154 * @brief returns the sequence ID from a raw history record
155 *
156 * Throws InvalidRecordException if the data is the wrong length.
157 *
158 * @param[in] data - the raw record data as the PS returns it
159 *
160 * @return size_t - the ID from byte 0
161 */
162 size_t getRawRecordID(const std::vector<uint8_t>& data) const;
Matt Spinlerd7abf362018-01-18 12:40:02 -0600163
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500164 /**
165 * @brief Creates an instance of a Record from the raw PS data
166 *
167 * @param[in] data - the raw record data as the PS returns it
168 *
169 * @return Record - A filled in Record instance
170 */
171 Record createRecord(const std::vector<uint8_t>& data);
Matt Spinlerd7abf362018-01-18 12:40:02 -0600172
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500173 /**
174 * @brief The maximum number of entries to keep in the history.
175 *
176 * When a new record is added, the oldest one will be removed.
177 */
178 const size_t maxRecords;
Matt Spinler28fa1b62018-01-18 13:15:02 -0600179
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500180 /**
181 * @brief The last ID the power supply returns before rolling over
182 * back to the first ID of 0.
183 */
184 const size_t lastSequenceID;
Matt Spinler28fa1b62018-01-18 13:15:02 -0600185
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500186 /**
187 * @brief The list of timestamp/average/maximum records.
188 * Newer records are added to the front, and older ones
189 * removed from the back.
190 */
191 std::deque<Record> records;
Matt Spinlerd7abf362018-01-18 12:40:02 -0600192};
193
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500194} // namespace history
195} // namespace power
196} // namespace witherspoon