blob: 98382c7499db2ab1c742ef1cffff4305194de989 [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:
31 InvalidRecordException() : std::runtime_error("Invalid history record")
Patrick Williams2c4fbc42020-06-26 15:33:11 -050032 {}
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)
Patrick Williams2c4fbc42020-06-26 15:33:11 -050074 {}
Matt Spinlerd7abf362018-01-18 12:40:02 -060075
Matt Spinlerf0f02b92018-10-25 16:12:43 -050076 /**
77 * @brief Constructor
78 *
79 * @param[in] maxRec - the maximum number of history
80 * records to keep at a time
81 * @param[in] lastSequenceID - the last sequence ID the power supply
82 * will use before starting over
83 */
84 RecordManager(size_t maxRec, size_t lastSequenceID) :
85 maxRecords(maxRec), lastSequenceID(lastSequenceID)
Patrick Williams2c4fbc42020-06-26 15:33:11 -050086 {}
Matt Spinlerd7abf362018-01-18 12:40:02 -060087
Matt Spinlerf0f02b92018-10-25 16:12:43 -050088 /**
89 * @brief Adds a new entry to the history
90 *
91 * Also checks to see if the old history should be
92 * cleared, such as when there is an invalid record
93 * sequence ID or if there was no data from the PS.
94 *
95 * @param[in] rawRecord - the record data straight
96 * from the power supply
97 *
98 * @return bool - If there has been a change to the
99 * history records that needs to be
100 * reflected in D-Bus.
101 */
102 bool add(const std::vector<uint8_t>& rawRecord);
Matt Spinlerd7abf362018-01-18 12:40:02 -0600103
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500104 /**
105 * @brief Returns the history of average input power
106 * in a representation used by D-Bus.
107 *
108 * @return DBusRecordList - A list of averages with
109 * a timestamp for each entry.
110 */
111 DBusRecordList getAverageRecords();
Matt Spinler8168d282018-01-18 13:24:06 -0600112
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500113 /**
114 * @brief Returns the history of maximum input power
115 * in a representation used by D-Bus.
116 *
117 * @return DBusRecordList - A list of maximums with
118 * a timestamp for each entry.
119 */
120 DBusRecordList getMaximumRecords();
Matt Spinlerc3414382018-01-18 13:49:16 -0600121
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500122 /**
123 * @brief Converts a Linear Format power number to an integer
124 *
125 * The PMBus spec describes a 2 byte Linear Format
126 * number that is composed of an exponent and mantissa
127 * in two's complement notation.
128 *
129 * Value = Mantissa * 2**Exponent
130 *
131 * @return int64_t the converted value
132 */
133 static int64_t linearToInteger(uint16_t data);
Matt Spinlerc3414382018-01-18 13:49:16 -0600134
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500135 /**
136 * @brief Returns the number of records
137 *
138 * @return size_t - the number of records
139 *
140 */
141 inline size_t getNumRecords() const
142 {
143 return records.size();
144 }
Matt Spinlere710d182018-01-18 13:06:17 -0600145
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500146 /**
147 * @brief Deletes all records
148 */
149 inline void clear()
150 {
151 records.clear();
152 }
Matt Spinlerd7abf362018-01-18 12:40:02 -0600153
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500154 private:
155 /**
156 * @brief returns the sequence ID from a raw history record
157 *
158 * Throws InvalidRecordException if the data is the wrong length.
159 *
160 * @param[in] data - the raw record data as the PS returns it
161 *
162 * @return size_t - the ID from byte 0
163 */
164 size_t getRawRecordID(const std::vector<uint8_t>& data) const;
Matt Spinlerd7abf362018-01-18 12:40:02 -0600165
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500166 /**
167 * @brief Creates an instance of a Record from the raw PS data
168 *
169 * @param[in] data - the raw record data as the PS returns it
170 *
171 * @return Record - A filled in Record instance
172 */
173 Record createRecord(const std::vector<uint8_t>& data);
Matt Spinlerd7abf362018-01-18 12:40:02 -0600174
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500175 /**
176 * @brief The maximum number of entries to keep in the history.
177 *
178 * When a new record is added, the oldest one will be removed.
179 */
180 const size_t maxRecords;
Matt Spinler28fa1b62018-01-18 13:15:02 -0600181
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500182 /**
183 * @brief The last ID the power supply returns before rolling over
184 * back to the first ID of 0.
185 */
186 const size_t lastSequenceID;
Matt Spinler28fa1b62018-01-18 13:15:02 -0600187
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500188 /**
189 * @brief The list of timestamp/average/maximum records.
190 * Newer records are added to the front, and older ones
191 * removed from the back.
192 */
193 std::deque<Record> records;
Matt Spinlerd7abf362018-01-18 12:40:02 -0600194};
195
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500196} // namespace history
197} // namespace power
198} // namespace witherspoon