blob: 7ebcc3f15e3c3364be14c69bb2e9a71dd0f74532 [file] [log] [blame]
Matt Spinlerd7abf362018-01-18 12:40:02 -06001#pragma once
2
3#include <deque>
4#include <tuple>
5#include <vector>
6
7namespace witherspoon
8{
9namespace power
10{
11namespace history
12{
13
14static constexpr auto recIDPos = 0;
15static constexpr auto recTimePos = 1;
16static constexpr auto recAvgPos = 2;
17static constexpr auto recMaxPos = 3;
18using Record = std::tuple<size_t, int64_t, int64_t, int64_t>;
19
20/**
Matt Spinler28fa1b62018-01-18 13:15:02 -060021 * @class InvalidRecordException
22 *
23 * The exception that is thrown when a raw history record
24 * cannot be parsed.
25 */
26class InvalidRecordException : public std::runtime_error
27{
Matt Spinlerf0f02b92018-10-25 16:12:43 -050028 public:
29 InvalidRecordException() : std::runtime_error("Invalid history record")
30 {
31 }
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 */
72 RecordManager(size_t maxRec) : RecordManager(maxRec, LAST_SEQUENCE_ID)
73 {
74 }
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)
86 {
87 }
Matt Spinlerd7abf362018-01-18 12:40:02 -060088
Matt Spinlerf0f02b92018-10-25 16:12:43 -050089 /**
90 * @brief Adds a new entry to the history
91 *
92 * Also checks to see if the old history should be
93 * cleared, such as when there is an invalid record
94 * sequence ID or if there was no data from the PS.
95 *
96 * @param[in] rawRecord - the record data straight
97 * from the power supply
98 *
99 * @return bool - If there has been a change to the
100 * history records that needs to be
101 * reflected in D-Bus.
102 */
103 bool add(const std::vector<uint8_t>& rawRecord);
Matt Spinlerd7abf362018-01-18 12:40:02 -0600104
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500105 /**
106 * @brief Returns the history of average input power
107 * in a representation used by D-Bus.
108 *
109 * @return DBusRecordList - A list of averages with
110 * a timestamp for each entry.
111 */
112 DBusRecordList getAverageRecords();
Matt Spinler8168d282018-01-18 13:24:06 -0600113
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500114 /**
115 * @brief Returns the history of maximum input power
116 * in a representation used by D-Bus.
117 *
118 * @return DBusRecordList - A list of maximums with
119 * a timestamp for each entry.
120 */
121 DBusRecordList getMaximumRecords();
Matt Spinlerc3414382018-01-18 13:49:16 -0600122
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500123 /**
124 * @brief Converts a Linear Format power number to an integer
125 *
126 * The PMBus spec describes a 2 byte Linear Format
127 * number that is composed of an exponent and mantissa
128 * in two's complement notation.
129 *
130 * Value = Mantissa * 2**Exponent
131 *
132 * @return int64_t the converted value
133 */
134 static int64_t linearToInteger(uint16_t data);
Matt Spinlerc3414382018-01-18 13:49:16 -0600135
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500136 /**
137 * @brief Returns the number of records
138 *
139 * @return size_t - the number of records
140 *
141 */
142 inline size_t getNumRecords() const
143 {
144 return records.size();
145 }
Matt Spinlere710d182018-01-18 13:06:17 -0600146
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500147 /**
148 * @brief Deletes all records
149 */
150 inline void clear()
151 {
152 records.clear();
153 }
Matt Spinlerd7abf362018-01-18 12:40:02 -0600154
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500155 private:
156 /**
157 * @brief returns the sequence ID from a raw history record
158 *
159 * Throws InvalidRecordException if the data is the wrong length.
160 *
161 * @param[in] data - the raw record data as the PS returns it
162 *
163 * @return size_t - the ID from byte 0
164 */
165 size_t getRawRecordID(const std::vector<uint8_t>& data) const;
Matt Spinlerd7abf362018-01-18 12:40:02 -0600166
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500167 /**
168 * @brief Creates an instance of a Record from the raw PS data
169 *
170 * @param[in] data - the raw record data as the PS returns it
171 *
172 * @return Record - A filled in Record instance
173 */
174 Record createRecord(const std::vector<uint8_t>& data);
Matt Spinlerd7abf362018-01-18 12:40:02 -0600175
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500176 /**
177 * @brief The maximum number of entries to keep in the history.
178 *
179 * When a new record is added, the oldest one will be removed.
180 */
181 const size_t maxRecords;
Matt Spinler28fa1b62018-01-18 13:15:02 -0600182
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500183 /**
184 * @brief The last ID the power supply returns before rolling over
185 * back to the first ID of 0.
186 */
187 const size_t lastSequenceID;
Matt Spinler28fa1b62018-01-18 13:15:02 -0600188
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500189 /**
190 * @brief The list of timestamp/average/maximum records.
191 * Newer records are added to the front, and older ones
192 * removed from the back.
193 */
194 std::deque<Record> records;
Matt Spinlerd7abf362018-01-18 12:40:02 -0600195};
196
Matt Spinlerf0f02b92018-10-25 16:12:43 -0500197} // namespace history
198} // namespace power
199} // namespace witherspoon