blob: 53e5b9b97870a949cec53a0e152352ac22f5d02b [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{
28 public:
29
30 InvalidRecordException() :
31 std::runtime_error("Invalid history record")
32 {
33 }
34};
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{
52 public:
53
Matt Spinler28fa1b62018-01-18 13:15:02 -060054 static constexpr auto RAW_RECORD_SIZE = 5;
55 static constexpr auto RAW_RECORD_ID_OFFSET = 0;
Matt Spinler8168d282018-01-18 13:24:06 -060056 static constexpr auto FIRST_SEQUENCE_ID = 0;
Matt Spinlerd7abf362018-01-18 12:40:02 -060057 static constexpr auto LAST_SEQUENCE_ID = 0xFF;
58
59 using DBusRecord = std::tuple<uint64_t, int64_t>;
60 using DBusRecordList = std::vector<DBusRecord>;
61
62 RecordManager() = delete;
63 ~RecordManager() = default;
64 RecordManager(const RecordManager&) = default;
65 RecordManager& operator=(const RecordManager&) = default;
66 RecordManager(RecordManager&&) = default;
67 RecordManager& operator=(RecordManager&&) = default;
68
69 /**
70 * @brief Constructor
71 *
72 * @param[in] maxRec - the maximum number of history
73 * records to keep at a time
74 */
75 RecordManager(size_t maxRec) :
76 RecordManager(maxRec, LAST_SEQUENCE_ID)
77 {
78 }
79
80 /**
81 * @brief Constructor
82 *
83 * @param[in] maxRec - the maximum number of history
84 * records to keep at a time
85 * @param[in] lastSequenceID - the last sequence ID the power supply
86 * will use before starting over
87 */
88 RecordManager(size_t maxRec, size_t lastSequenceID) :
89 maxRecords(maxRec),
90 lastSequenceID(lastSequenceID)
91 {
92 }
93
94 /**
Matt Spinler8168d282018-01-18 13:24:06 -060095 * @brief Adds a new entry to the history
96 *
97 * Also checks to see if the old history should be
98 * cleared, such as when there is an invalid record
99 * sequence ID or if there was no data from the PS.
100 *
101 * @param[in] rawRecord - the record data straight
102 * from the power supply
103 *
104 * @return bool - If there has been a change to the
105 * history records that needs to be
106 * reflected in D-Bus.
107 */
108 bool add(const std::vector<uint8_t>& rawRecord);
109
110 /**
Matt Spinlerc3414382018-01-18 13:49:16 -0600111 * @brief Returns the history of average input power
112 * in a representation used by D-Bus.
113 *
114 * @return DBusRecordList - A list of averages with
115 * a timestamp for each entry.
116 */
117 DBusRecordList getAverageRecords();
118
119 /**
120 * @brief Returns the history of maximum input power
121 * in a representation used by D-Bus.
122 *
123 * @return DBusRecordList - A list of maximums with
124 * a timestamp for each entry.
125 */
126 DBusRecordList getMaximumRecords();
127
128 /**
Matt Spinlere710d182018-01-18 13:06:17 -0600129 * @brief Converts a Linear Format power number to an integer
130 *
131 * The PMBus spec describes a 2 byte Linear Format
132 * number that is composed of an exponent and mantissa
133 * in two's complement notation.
134 *
135 * Value = Mantissa * 2**Exponent
136 *
137 * @return int64_t the converted value
138 */
139 static int64_t linearToInteger(uint16_t data);
140
141 /**
Matt Spinlerd7abf362018-01-18 12:40:02 -0600142 * @brief Returns the number of records
143 *
144 * @return size_t - the number of records
145 *
146 */
147 inline size_t getNumRecords() const
148 {
149 return records.size();
150 }
151
152 /**
153 * @brief Deletes all records
154 */
155 inline void clear()
156 {
157 records.clear();
158 }
159
160 private:
161
162 /**
Matt Spinler28fa1b62018-01-18 13:15:02 -0600163 * @brief returns the sequence ID from a raw history record
164 *
165 * Throws InvalidRecordException if the data is the wrong length.
166 *
167 * @param[in] data - the raw record data as the PS returns it
168 *
169 * @return size_t - the ID from byte 0
170 */
171 size_t getRawRecordID(const std::vector<uint8_t>& data) const;
172
173 /**
174 * @brief Creates an instance of a Record from the raw PS data
175 *
176 * @param[in] data - the raw record data as the PS returns it
177 *
178 * @return Record - A filled in Record instance
179 */
180 Record createRecord(const std::vector<uint8_t>& data);
181
182 /**
Matt Spinlerd7abf362018-01-18 12:40:02 -0600183 * @brief The maximum number of entries to keep in the history.
184 *
185 * When a new record is added, the oldest one will be removed.
186 */
187 const size_t maxRecords;
188
189 /**
190 * @brief The last ID the power supply returns before rolling over
191 * back to the first ID of 0.
192 */
193 const size_t lastSequenceID;
194
195 /**
196 * @brief The list of timestamp/average/maximum records.
197 * Newer records are added to the front, and older ones
198 * removed from the back.
199 */
200 std::deque<Record> records;
201};
202
203}
204}
205}